def test_crack_shared_cipher(): ciphertext = 'Call me Ishmael.' keypair0 = RSAKeypair.create(e=3) keypair1 = RSAKeypair.create(e=3) keypair2 = RSAKeypair.create(e=3) c0 = rsa_encrypt(ciphertext, keypair0) c1 = rsa_encrypt(ciphertext, keypair1) c2 = rsa_encrypt(ciphertext, keypair2) n0 = keypair0.exponent n1 = keypair1.exponent n2 = keypair2.exponent m_s_0 = n1 * n2 m_s_1 = n0 * n2 m_s_2 = n0 * n1 assert all(gcd(n, n_) == 1 for n, n_ in combinations([n0, n1, n2], 2)) result, _ = crt_inductive([ (c0 * m_s_0 * mod_inverse(m_s_0, n0), keypair0.exponent), (c1 * m_s_1 * mod_inverse(m_s_1, n1), n1), (c2 * m_s_2 * mod_inverse(m_s_2, n2), n2), ]) cube_root, is_exact = iroot(mpz(result), 3) assert is_exact, 'Cube root should have been exact' assert unhexlify('{:02x}'.format(cube_root)).decode() == ciphertext
def brute_force_digest(digest, h, r, p): assert pow(h, r, p) == 1, 'Element h should have had order r' # h has order r so the digest must have value h^x where 0 <= x < r - 1 # Must include x = r (so K would be 1) for x in range(1, r + 1): d = sha1('crazy flamboyant for the rap enjoyment'.encode()) d.update(str(pow(h, x, p)).encode()) candidate_digest = d.digest() if digest == candidate_digest: return x raise ValueError(f'Could not find h^x such that h^x = K mod p') def find_residues(j, p, secret): for r in small_factors(j): h = find_element_of_order(r, p) # Simulates getting a message from Bob using the secret (h) digest = encrypt_digest(h, secret, p) b = brute_force_digest(digest, h, r, p) yield (b, r) if __name__ == '__main__': crt_moduli = list(find_residues(j, p, bob_secret)) x, _ = crt_inductive(crt_moduli) assert bob_secret == x print(f'All done! Successfully cracked bob_secret using ' f'{len(crt_moduli)} samples')
order_curve2 = 233970423115425145544350131142039591210 bad_curve3 = WeierstrassCurve(p, -95051, 727) order_curve3 = 233970423115425145545378039958152057148 bad_curves = [bad_curve1, bad_curve2, bad_curve3] curve_orders = [order_curve1, order_curve2, order_curve3] crt_residues = [] for bad_curve, bad_curve_order in zip(bad_curves, curve_orders): print(f'Computing residues for {bad_curve}') crt_residues += list( subgroup_confinement_residues(bob_keypair, bad_curve, bad_curve_order)) # Must remove duplicates because the given bad curves might end up # with the same residues. In the event of a bug where we have # different residue values mod the same prime the algorithm will # still explode. crt_residues = list(set(crt_residues)) q = reduce(mul, map(itemgetter(1), crt_residues), 1) if q > given_order: break for m, r in crt_residues: assert bob_keypair.secret % r == m # Ready to attack x, _ = crt_inductive(crt_residues) assert x == bob_keypair.secret, 'Brute forced secret with bogus points' print(f'All done! Used {len(crt_residues)} residues to determine ' f'{x} == {bob_keypair.secret}')
return b + xT - xW raise ValueError('Kangaroo sequences did not intersect') # g^705485 = y1 # print(kangaroo_attack(pseudorandom_map, N, g, 0, 2**20, y1)) assert pow(g, 705485, p) == y1 # g^359579674340 = y2 # print(kangaroo_attack(pseudorandom_map, N, g, 0, 2**40, y2)) assert pow(g, 359579674340, p) == y2 if __name__ == '__main__': bob_secret = randint(0, q) residues = list(find_residues(j, p, bob_secret)) n, r = crt_inductive(residues) print(f'secret_key = {n} mod {r}') assert bob_secret % r == n, 'Bob secret did not satisfy expected relationship' # We know {secret key} = n mod r # So {secret key} = n + m * r - must find m # Through a series of algebraic transformations, we have: # y' = g^{m * r} # y' = (g^{r})^m g_ = pow(g, r, p) # This is the Diffie-Hellman public key (and so public) y = pow(g, bob_secret, p) g_inverse = pow(g, p - 2, p) assert (g * g_inverse) % p == 1, 'g_inverse was not inverse of g' y_ = (y * pow(g_inverse, n, p)) % p
print(f'{alice_keypair.secret} (alice secret)') # if calculate_residues: residues = subgroup_confinement_residues(curve, alice_keypair, twist_order) residues_list = list(residues) # else: # residues_list = [ # (4, 11), (46, 107), (15, 197), (721, 1621), # (36413, 105143), (140928, 405373), (3842, 2323367)] print(f'Residues: {residues_list}') option1, option2 = filter_moduli(curve, alice_keypair, twist_order, residues_list) # So these values are actually duplicative since r1 == r2 and m2 = r1 - m1 m1, r = crt_inductive(option1) m2, r_ = crt_inductive(option2) assert r == r_ assert alice_keypair.secret % r in [m1, r - m1] assert alice_keypair.secret % r in [m1, m2] # So we can forget about m2 for now and just work with m1. # So n is either r - m1 or m1 # x = n + m * r --> n is known, m is unknown # We know alice_public is g^alice_secret # y = alice_public print(f'We know {alice_keypair.secret} = ±{m1} + m * {r}. Solve for m') x1 = curve_kangaroo_attack(point, m1, r) x2 = curve_kangaroo_attack(point, r - m1, r)