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 RSAVerifyPKCS15(pub_key, msg, sig): verify_against = (GroupOp.mod_exp(sig, pub_key[1], pub_key[0])).to_bytes( pub_key[0].bit_length() // 8, byteorder="big") begin_correct = verify_against.startswith(b"\x00\x01") # strip all of the ff's ff_strip = verify_against[2:] while ff_strip[0] == 0xff: ff_strip = ff_strip[1:] correct0 = ff_strip.startswith(b"\x00") hash_id_length = SHA1_ASNBitLen // 8 hash_identifier = int.from_bytes(ff_strip[1:hash_id_length + 1], byteorder="big") if hash_identifier == SHA1_ASN: hash_obj = sha1.SHA1() elif hash_identifier == SHA256_ASN: hash_obj = sha256.SHA256() else: raise ValueError("Was unable to identify hash alg") hash_obj.Update(msg) hashed_msg = hash_obj.Sum() hash_from_sig = ff_strip[hash_id_length + 1:hash_id_length + 1 + SHA1Len] check_val = (hash_from_sig == hashed_msg) return check_val and correct0 and begin_correct
def generate_public_key(generator, prime): secret_val = random.getrandbits(prime.bit_length()) if secret_val > prime: secret_val = secret_val ^ prime assert secret_val < prime public_val = GroupOp.mod_exp(generator, secret_val, prime) assert public_val < prime return (secret_val, public_val)
def generate_shared_key(secret_val, public_val_from_other, prime): print("Secret value is {}, shared value is {}".format( secret_val, public_val_from_other)) shared_key = GroupOp.mod_exp(public_val_from_other, secret_val, prime) print(shared_key) assert shared_key < prime hash_feed = SHA1.SHA1() hash_feed.Update( shared_key.to_bytes(shared_key.bit_length() + 7 // 8, byteorder='big')) return hash_feed.Sum()
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 encrypt(pub_key, message): if type(message) is str or type(message) is bytes: if type(message) is str: message = message.encode() msg_as_number = int.from_bytes(message, byteorder="big") elif type(message) is int: msg_as_number = message mod, e = pub_key[0], pub_key[1] if msg_as_number > mod: raise ValueError("Message must be in range of the modulus") ct = GroupOp.mod_exp(msg_as_number, e, mod) ct = ct.to_bytes((ct.bit_length() + 7) // 8, byteorder="big") return ct
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 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(): 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 RSASignPKCS15(priv_key, msg): msg_encoded = EncodeMessage(msg, priv_key[0]) sig = GroupOp.mod_exp(msg_encoded, priv_key[1], priv_key[0]) return sig
def generate_generator(prime_p, prime_q): g = 1 while g == 1: h = random.randrange(1, prime_p) g = GroupOp.mod_exp(h, (prime_p - 1) // prime_q, prime_p) return g
def DSAKeyGen(params, print_x=False): private_key = random.randrange(1, params["q"]) public_key = GroupOp.mod_exp(params["g"], private_key, params["p"]) if print_x: print("Secret key was {:x}".format(private_key)) return public_key, private_key
def main(): """ parameters = DSAParamGen(42, 256) pub_key, priv_key = DSAKeyGen(parameters) test_msg = b"Lost Lenore" tag = DSASign(parameters, priv_key, test_msg) verify = DSAVerify(parameters, pub_key, test_msg, tag) if verify: print("Passed simple test") else: print("Failed simple test") print("Attempting to use stolen attacker knowledge to recover the private key...") for i in range(3): temp_pub_key, temp_priv_key = DSAKeyGen(parameters, print_x=True) msg = input("Type in message to sign: ").encode("utf-8") tag = DSASign(parameters, temp_priv_key, msg, print_k=True) k_val = input("Give k value in hex: 0x") k = int("0x" + k_val, 16) recovered_private_key = AttackerWithKnownSubKeyK(parameters, temp_pub_key, k, msg, tag) print("Recovered secret key was {:x}".format(recovered_private_key)) """ print("Attempting to crack private key from challenge...") msg_str = "For those that envy a MC it can be hazardous to your health\nSo be friendly, a matter of life and death, just like a etch-a-sketch\n" print("Checking to make sure the message string is correct...") hash_obj = sha1.SHA1() hash_obj.Update(msg_str.encode('utf-8')) result_hash = int.from_bytes(hash_obj.Sum(), byteorder="big") if not hex(result_hash) == "0xd2d0714f014a9784047eaeccf956520045c45265": raise ValueError("Object hash is incorrect") challenge_tag = (548099063082341131477253921760299949438196259240, 857042759984254168557880549501802188789837994940) challenge_params = { "p": 0x800000000000000089e1855218a0e7dac38136ffafa72eda7859f2171e25e65eac698c1702578b07dc2a1076da241c76c62d374d8389ea5aeffd3226a0530cc565f3bf6b50929139ebeac04f48c3c84afb796d61e5a4f9a8fda812ab59494232c7d2b4deb50aa18ee9e132bfa85ac4374d7f9091abc3d015efc871a584471bb1, "q": 0xf4f47f05794b256174bba6e9b396a7707e563c5b, "g": 0x5958c9d3898b224b12672c0b98e06c60df923cb8bc999d119458fef538b8fa4046c8db53039db620c094c9fa077ef389b5322a559946a71903f990f1f7e0e025e2d7f7cf494aff1a0470f5b64c36b625a097f1651fe775323556fe00b3608c887892878480e99041be601a62166ca6894bdd41a7054ec89f756ba9fc95302291 } challenge_public_key = 0x84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a08084056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec568280ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17 sha_key_fp = 0x0954edd5e0afe5542a4adf012611a91912a3ec16 for i in range(0, 2**16): selector = GroupOp.mod_exp( challenge_params["g"], i, challenge_params["p"]) % challenge_params["q"] if selector == challenge_tag[0]: print("Calculated a correct r value!") # test k potential_priv_key = AttackerWithKnownSubKeyK( challenge_params, challenge_public_key, i, msg_str, challenge_tag, result_hash) key_obj = sha1.SHA1() string_feed = hex(potential_priv_key)[2:] key_obj.Update(string_feed) key = int.from_bytes(key_obj.Sum(), byteorder="big") print("Key fp is {:x}".format(key)) compute_tag = DSASign(challenge_params, potential_priv_key, msg_str.encode("utf-8"), False, i) if compute_tag[1] == challenge_tag[1]: print("Success! Key is {}".format(potential_priv_key)) return else: print("Failure, correct r but incorrect s") return
def decrypt(priv_key, ciphertext): cipherint = int.from_bytes(ciphertext, byteorder="big") mod, d = priv_key[0], priv_key[1] pt = GroupOp.mod_exp(cipherint, d, mod) pt = pt.to_bytes((pt.bit_length() + 7) // 8, byteorder="big") return pt