def insecureVerify(params, public_key, message, tag): r, s = tag[0], tag[1] hash_obj = sha256.SHA256() hash_obj.Update(message) msg_hash = hash_obj.Sum() % params["q"] s_inv = GroupOp.find_inverse(s, params["q"]) arg1 = GroupOp.mod_exp(params["g"], (s_inv * msg_hash) % params["q"], params["p"]) arg2 = GroupOp.mod_exp(public_key, (r * s_inv) % params["q"], params["p"]) lhs = ((arg1 * arg2) % params["p"]) % params["q"] return (lhs == r)
def insecureSign(params, private_key, message): k = random.randrange(1, params["q"]) r = GroupOp.mod_exp(params["g"], k, params["p"]) % params["q"] init_hash = sha1.SHA1() init_hash.Update(message) hashed_msg_val = int.from_bytes(init_hash.Sum(), byteorder="big") % params["q"] k_inv = GroupOp.find_inverse(k, params["q"]) s = (k_inv * (hashed_msg_val + private_key * r)) % params["q"] return (r, s)
def attacker(pub_key, old_ct): #pick a number rel. prime with the modulus random_s = random.randrange(1, pub_key[0]) while GroupOp.find_gcd(random_s, pub_key[0]) != 1: random_s = random.randrange(1, pub_key[0]) inv_s = GroupOp.find_inverse(random_s, pub_key[0]) old_ct_as_number = int.from_bytes(old_ct, byteorder="big") new_ct = (GroupOp.mod_exp(random_s, pub_key[1], pub_key[0]) * old_ct_as_number) % pub_key[0] oracle_res = recovery_oracle( new_ct.to_bytes((new_ct.bit_length() + 7) // 8, byteorder="big")) val = (inv_s * int.from_bytes(oracle_res, byteorder="big")) % pub_key[0] print("Original message was {}".format( val.to_bytes((val.bit_length() + 7) // 8, byteorder="big")))
def crt_reconstruct(modulus_one, modulus_two, modulus_three, rem_one, rem_two, rem_three): large_mod = modulus_one * modulus_two * modulus_three crt_factor = (modulus_one * modulus_two) + \ (modulus_two*modulus_three) + \ (modulus_one*modulus_three) crt_factor = crt_factor % large_mod crt_factor_inv = GroupOp.find_inverse(crt_factor, large_mod) mod_one_factor = (crt_factor_inv * modulus_two * modulus_three * rem_one) mod_two_factor = (crt_factor_inv * modulus_three * modulus_one * rem_two) mod_three_factor = (crt_factor_inv * modulus_two * modulus_one * rem_three) reconstructed_ct_value = (mod_two_factor + mod_one_factor + mod_three_factor) % large_mod return reconstructed_ct_value
def AttackerWithKnownSubKeyK(params, public_key, k, msg, msg_sig, msg_hash=None): recover_x = (msg_sig[1] * k) % params["q"] if not msg_hash: hash_obj = sha1.SHA1() hash_obj.Update(msg) msg_as_int = int.from_bytes(hash_obj.Sum(), byteorder="big") else: msg_as_int = msg_hash recover_x = (recover_x - (msg_as_int % params["q"])) % params["q"] recover_x = recover_x * (GroupOp.find_inverse(msg_sig[0], params["q"])) return recover_x % params["q"]
def DSASign(params, private_key, message, print_k=False, k=0): r = 0 s = 0 while r == 0 and s == 0: if k == 0: k = random.randrange(1, params["q"]) if print_k: print("K value is {:x}".format(k)) r = GroupOp.mod_exp(params["g"], k, params["p"]) % params["q"] if r != 0: init_hash = sha1.SHA1() init_hash.Update(message) hashed_msg_val = int.from_bytes(init_hash.Sum(), byteorder="big") % params["q"] k_inv = GroupOp.find_inverse(k, params["q"]) s = (k_inv * (hashed_msg_val + private_key * r)) % params["q"] return (r, s)
def main(): dictionary = from_file("44.txt") dict1, dict2 = isolate_repeated_k(dictionary) if not dict1: print("Could not run attack :(") else: inv_s_elt = (dict1["s"] - dict2["s"]) % challenge_params["q"] inv_s_elt = GroupOp.find_inverse(inv_s_elt, challenge_params["q"]) exp_k = (dict1["m"] - dict2["m"]) % challenge_params["q"] exp_k = (exp_k * inv_s_elt) % challenge_params["q"] recovered_x = CP43.AttackerWithKnownSubKeyK(challenge_params, challenge_public_key, exp_k, dict1["msg"], (dict1["r"], dict1["s"]), dict1["m"]) key_hash_obj = sha1.SHA1() key_hash_obj.Update(hex(recovered_x)[2:]) key = int.from_bytes(key_hash_obj.Sum(), byteorder="big") print("Recovered key is {:x} with fp {:x}".format(recovered_x, key)) return
def main(): global challenge_params # assuming we want to keep the same public key because if we didn't # and it was based on the bogus generator then we have big problems tag = insecureSign(challenge_params, recovered_priv_key, b"A message") # r will be 0 here, s will be k^inv * H(msg) # but it really doesn't matter, because the other side needs to # find the inverse of s so as long as s is invertible, you'll # validate. This signature would "work" for every message and moreover # ANYTHING will work as long as r=0 and s is invert. message = b"If music be the food of love, play on; Give me excess of it, that, surfeiting,The appetite may sicken, and so die. --Twelfth Night" res = insecureVerify(challenge_params, challenge_public_key, message, (0, 0xdeadbeef)) print("Generator g = 0\n") print("Message: {}, Sig: (0x{:x},0x{:x}), Result: {}".format( message, 0, 0xdeadbeef, res)) # change the generator is p+1 and not challenge_params["g"] = challenge_params["p"] + 1 # I'm going to assume the key was genereated honestly, because if it wasn't # we would get g**x = (p+1)**x mod p which is just 1 choose_random = random.randrange(1, challenge_params["q"]) r = GroupOp.mod_exp(challenge_public_key, choose_random, challenge_params["p"]) % challenge_params["q"] s = (r * GroupOp.find_inverse( choose_random, challenge_params["q"])) % challenge_params["q"] result = insecureVerify(challenge_params, challenge_public_key, b"Hello, world", (r, s)) res2 = insecureVerify(challenge_params, challenge_public_key, b"Goodbye, world", (r, s)) print("Generator g = p + 1") print("Message: {}, Random val: 0x{:x}, Sig: (0x{:x},0x{:x}), Result: {}". format(b"Hello, world", choose_random, r, s, result)) print("Message: {}, Random val: 0x{:x}, Sig: (0x{:x}, 0x{:x}), Result: {}". format(b"Goodbye, world", choose_random, r, s, res2)) return
def generate_RSA_key(bit_size_modulus, primes=None): if primes: p = primes[0] q = primes[1] else: desired_prime_size = (bit_size_modulus + 1) // 2 p = GroupOp.generate_prime(desired_prime_size) q = GroupOp.generate_prime(desired_prime_size) while p == q or GroupOp.find_totient(p * q, [(p, 1), (q, 1)]) % 3 == 0: q = GroupOp.generate_prime(desired_prime_size) print("Prime p {:x} and q {:x}".format(p, q)) n = p * q assert (n.bit_length() >= bit_size_modulus) group_of_mult_inv = GroupOp.find_totient(n, [(p, 1), (q, 1)]) assert (group_of_mult_inv == ((p - 1) * (q - 1))) e = 3 d = GroupOp.find_inverse(e, group_of_mult_inv) pub_key = (n, e) priv_key = (n, d) return pub_key, priv_key