def srp_authn(self, email, input_hmac): account = self.accounts[email] salt = account["salt"] salt_bytes = to_bytes(salt) A, b, u = account["A"], account["b"], account["u"] for password in WORDS: # Find x as in Steven's `hello` step/Carla's `kexch` step. x_bytes = sha256(salt_bytes + password.encode()).digest() x = from_bytes(x_bytes) # Find v as in Steven's `hello` step. v = modexp(self.g, x, self.n) # Find S and K as in Steven's `kexch` step. S = modexp(A * modexp(v, u, self.n), b, self.n) K = sha256(to_bytes(S)).digest() if hmac_sha256(K, salt_bytes) == input_hmac: return f"{email}, your password is '{password}'. Muahahaha!" # Password wasn't found in the dictionary. return f"These are not the droids you're looking for."
def srp_kexch(self): a = random.getrandbits(1536) A = modexp(self.g, a, self.n) # Carol now receives u from Steve. self.salt, B, u = self.parley("kexch", self.email, A) x_bytes = sha256(to_bytes(self.salt) + self.password.encode()).digest() x = from_bytes(x_bytes) # k is not used anymore. S = modexp(B, a + u * x, self.n) self.K = sha256(to_bytes(S)).digest()
def srp_kexch(self): a = random.getrandbits(1536) A = modexp(self.g, a, self.n) self.salt, B = self.parley("kexch", self.email, A) u_bytes = sha256(to_bytes(A, B)).digest() u = from_bytes(u_bytes) x_bytes = sha256(to_bytes(self.salt) + self.password.encode()).digest() x = from_bytes(x_bytes) S = modexp(B - self.k * modexp(self.g, x, self.n), a + u * x, self.n) self.K = sha256(to_bytes(S)).digest()
def srp_kexch(self, email, A): account = self.accounts[email] b = random.getrandbits(1536) B = modexp(self.g, b, self.n) # u is now simply a random uint128. u = random.getrandbits(128) S = modexp(A * modexp(account["v"], u, self.n), b, self.n) account["K"] = sha256(to_bytes(S)).digest() # Steven now sends u to Carl. return account["salt"], B, u
def rsa_echo(self, ctext): # Eve is actually MITMing, not just eavesdropping. # To simulate an eavesdrop, have Eve discard the plaintext. self.parley("echo", ctext) # Steve will reject repeat submissions. assert self.parley("echo", ctext) is None # Eve cracks the ciphertext on her own. C = from_bytes(ctext) E, N = self.remote_pubkey S = random.randint(2, N - 1) C_ = (C * modexp(S, E, N)) % N ptext_ = self.parley("echo", to_bytes(C_)) P_ = from_bytes(ptext_) P = (P_ * invmod(S, N)) % N ptext = to_bytes(P) print("Eve cracked Carol's plaintext:") print() print(" " * 4 + ptext.decode()) print() # Carol won't notice a thing :P return ptext
def decryptor(ctext, pubkey, oracle, show=True): e, n = pubkey two = modexp(2, e, n) # Decryption algorithm as described in the challenge. # Mostly works, but usually fails for the last character. # # lower, upper, ptext = 0, n, b"" # while lower < upper: # mid = (upper + lower) // 2 # if oracle(ctext): # upper -= mid # else: # lower += mid # return to_bytes(upper) lower, upper, bit_length = 0, 1, n.bit_length() for i in range(1, bit_length + 1): diff, lower, upper = upper - lower, lower << 1, upper << 1 ctext = (ctext * two) % n if oracle(ctext): upper -= diff else: lower += diff print("\r" + to_str((upper * n) >> i) + "\033[K", end="", flush=True) else: print() return to_bytes((upper * n) >> bit_length)
def srp_kexch(self, email, A): account = self.accounts[email] b = random.getrandbits(1536) B = self.k * account["v"] + modexp(self.g, b, self.n) u_bytes = sha256(to_bytes(A, B)).digest() u = from_bytes(u_bytes) # We can't simply calculate the `A * v ** u` part of # `S = (A * v ** u) ** b % n`; the result is huge. But it seems # that all arithmetic is performed modulo n of late. *hint hint* S = modexp(A * modexp(account["v"], u, self.n), b, self.n) account["K"] = sha256(to_bytes(S)).digest() return account["salt"], B
def srp_hello(self, email, password): salt = random.getrandbits(32) x_bytes = sha256(to_bytes(salt) + password.encode()).digest() x = from_bytes(x_bytes) v = modexp(self.g, x, self.n) self.accounts[email] = {"password": password, "salt": salt, "v": v} return self.n, self.g, self.k
def decrypt_pass(constants, state, oracle): e, n, c_0, s_0, B, B_2, B_3, B_31 = constants i, s_i1, M_i1 = state # Find s_i. if i == 1 or (i > 1 and len(M_i1) > 1): s_i = (n + B_31) // B_3 if i == 1 else s_i1 + 1 while not oracle((c_0 * modexp(s_i, e, n)) % n): s_i += 1 else: a, b = list(M_i1)[0] r_i = ((2 * (b * s_i1 - B_2)) + (n - 1)) // n while True: lower = (B_2 + (r_i * n) + (b - 1)) // b upper = (B_3 + (r_i * n) + (a - 1)) // a for s_i in range(lower, upper): if oracle((c_0 * modexp(s_i, e, n)) % n): break else: r_i += 1 continue break # Find M_i. M_i = set() for a, b in M_i1: lower = ((a * s_i) - B_31 + (n - 1)) // n upper = ((b * s_i) - B_2) // n for r in range(lower, upper + 1): a_i = (B_2 + (r * n) + (s_i - 1)) // s_i b_i = (B_31 + (r * n)) // s_i M_i.add((max(a, a_i), min(b, b_i))) if len(M_i) == 1: a, b = list(M_i)[0] if a == b: return (a * invmod(s_0, n)) % n state = (i + 1, s_i, M_i) return constants, state
def decrypt_prepare(ctext, pubkey, oracle): # Extract/precompute some numbers that show up often in the math. e, n = pubkey B = 1 << 8 * (byte_length(n) - 2) B_2, B_3, B_31 = 2 * B, 3 * B, 3 * B - 1 M_0 = {(B_2, B_31)} for s_0 in range(1, n + 1): c_0 = (ctext * modexp(s_0, e, n)) % n if oracle(c_0): constants = (e, n, c_0, s_0, B, B_2, B_3, B_31) state = (1, s_0, M_0) return constants, state
def bruteforce_dsa_privkey(bs, sig, max_k=2**16, p=P, q=Q, g=G): r, s = sig z = from_bytes(SHA1(bs).digest()) for k in range(1, max_k): k_inv = invmod(k, q) if k_inv is None: continue x = (((((s * k) % q) - z) % q) * invmod(r, q)) % q sk, rk = (k_inv * (z + x * r)) % q, modexp(g, k, p) % q if s == sk and r == rk: return x
def decryptor(ctext, pubkey, oracle, show=True): e, n = pubkey two = modexp(2, e, n) lower, upper, bit_length = 0, 1, n.bit_length() for i in range(1, bit_length + 1): diff, lower, upper = upper - lower, lower << 1, upper << 1 ctext = (ctext * two) % n if oracle(ctext): upper -= diff else: lower += diff print("\r" + to_str((upper * n) >> i) + "\033[K", end="", flush=True) else: print() return to_bytes((upper * n) >> bit_length)
def __init__(self, pubkey, privkey, ctext): orig_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) self.pool = Pool(CPUS) signal.signal(signal.SIGINT, orig_handler) self.e, self.n = pubkey self.privkey = privkey # Save the modulus length for the progress indicator. self.bits = self.n.bit_length() # Find s_0 and save initial state. self.c_0 = ctext self.s_0 = self.s = self.mp_find_s(self.gen_incr(1)) self.c_0 = (self.c_0 * modexp(self.s, self.e, self.n)) % self.n self.i = 0 self.B = 1 << (byte_length(self.n) - 2) * 8 self.M = {(self.B * 2, self.B * 3 - 1)} self.result = None
def srp_kexch(self, email, A): account = self.accounts[email] # Mallory doesn't know the password or anything about it. account.pop("password") account.pop("v") # "Use arbitrary values for b, B, u, and salt". The way Steven # generates these is already arbitrary; just do as Steven does. # (We could fix b, u, and salt to values that simplify the math, # but the attack doesn't seem to hinge upon doing this.) b = random.getrandbits(1536) B = modexp(self.g, b, self.n) u = random.getrandbits(128) # Mallory needs to save A, b, and u for her `authn` step. account.update({"A": A, "b": b, "u": u}) # A salt was already generated in Steven's `hello` step. return account["salt"], B, u
def mp_test_s(mp_data): c_0, s, e, n, privkey = mp_data if oracle((c_0 * modexp(s, e, n)) % n, privkey): return s