def hmac_sha1(key, msg): assert type(msg) == bytes assert type(key) == bytes if len(key) > 64: key = sha1(key, len(key) * 8) if len(key) < 64: key += b'\x00' * (64 - len(key)) o_key_pad = bytes.fromhex(xor_hex_strings(key.hex(), (b'\x5c' * 64).hex())) i_key_pad = bytes.fromhex(xor_hex_strings(key.hex(), (b'\x36' * 64).hex())) i_pad_hash = bytes.fromhex( sha1(i_key_pad + msg, len(i_key_pad + msg) * 8)[2:]) return sha1(o_key_pad + i_pad_hash, len(o_key_pad + i_pad_hash) * 8)[2:]
def chall_two_phase_1(p, g): # Alice and Bob generate private keys a, b = random.randint(0, p), random.randint(0, p) # Alice and Bob sends public messages A, B = modexp(g,a,p), modexp(g,b,p) print(f"These are public info! \np: \t\t\t{hex(p)} \ng: {g}\nAlice public key: \t{hex(A)}\nBob public key: \t{hex(B)}") # Now, generate shared secret S by computing # S == A^b == B^a S = modexp(A,b,p) bytes_S = hex(S)[2:].encode() assert S == modexp(B,a,p), "Shared secret miscomputed" # 1a) Preparing to send Bob the message iv_a = get_random_int(128) sha_S = sha1(bytes_S,len(bytes_S)*8) print(f"shared secret is: {S}") shared_S = sha_S[2:][:32] alice_msg = "This is the password. Pass it on!".encode().hex() alice_encrypt = cbc_encrypt(alice_msg, shared_S, iv_a) + iv_a print(f"Here is my (alice's) encrypted text: \t\t{alice_encrypt}") print("\n~~~~~SENDING MESSAGE~~~~~~ PLS NO INTERCEPT ~~~~~") print("~~~~~BUT EVEN IF YOU DO THIS IS UNHAXABLE~~~~~~~~\n") # 1b) Bob receives the message # Confirming that Bob received the message from Alice correctly iv_b = alice_encrypt[-32:] alice_ciphertext = alice_encrypt[:-32] bob_decrypt = cbc_decrypt(alice_ciphertext, shared_S, iv_b) padding = int(bob_decrypt[-1], 16)*2 bob_decrypt = bob_decrypt[:-padding] assert bob_decrypt == alice_msg iv_b = get_random_int(128) bob_encrypt = cbc_encrypt(bob_decrypt, shared_S, iv_b) + iv_b print(f"Thanks! Here is my (bob's) encrypted text: \t{bob_encrypt}") # 2) Bob sending message back to Alice iv_b = bob_encrypt[-32:] bob_ciphertext = bob_encrypt[:-32] alice_decrypt = cbc_decrypt(bob_ciphertext, shared_S, iv_b) padding = int(alice_decrypt[-1], 16)*2 alice_decrypt = alice_decrypt[:-padding] assert alice_decrypt == alice_msg return alice_encrypt, bob_encrypt
def mallory_decrypt(alice_encrypt, bob_encrypt, g, p, S): bytes_S = hex(S)[2:].encode() sha_S = sha1(bytes_S,len(bytes_S)*8) shared_S = sha_S[2:][:32] iv_b = alice_encrypt[-32:] alice_ciphertext = alice_encrypt[:-32] bob_decrypt = cbc_decrypt(alice_ciphertext, shared_S, iv_b) padding = int(bob_decrypt[-1], 16)*2 bob_decrypt = bob_decrypt[:-padding] return binascii.unhexlify(bob_decrypt)
def length_extension(known_msg, inject_data, original_hash): for guess_key_len in range(128): # use the same padding in sha1, but just chop the key/suffix # since key will just get "added back" in the oracle crafted_msg = pad_msg( b"A" * guess_key_len + known_msg.encode(), (guess_key_len + len(known_msg)) * 8)[guess_key_len:] + inject_data (a, b, c, d, e) = struct.unpack('>5I', bytes.fromhex(original_hash)) forged_mac = sha1(inject_data, (guess_key_len + len(crafted_msg)) * 8, a, b, c, d, e)[2:] if validate_mac(crafted_msg, forged_mac): return forged_mac, crafted_msg raise ValueError("length extension failed")
def sha1_mac(key, msg): return sha1(key + msg, len(key+msg)*8)[2:].zfill(40)
def main(): p = 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff g = 2 # Alice and Bob generate private keys a, b = random.randint(0, p), random.randint(0, p) # Alice and Bob sends public messages A, B = modexp(g,a,p), modexp(g,b,p) print(f"These are public info! \np: \t\t\t{hex(p)} \ng: {g}\nAlice public key: \t{hex(A)}\nBob public key: \t{hex(B)}") # Now, generate shared secret S by computing # S == A^b == B^a S = modexp(A,b,p) bytes_S = hex(S)[2:].encode() assert S == modexp(B,a,p), "Shared secret miscomputed" # 1a) Preparing to send Bob the message iv_a = get_random_int(128) sha_S = sha1(bytes_S,len(bytes_S)*8) print(f"shared secret is: {S}") shared_S = sha_S[2:][:32] alice_msg = "This is the password. Pass it on!".encode().hex() alice_encrypt = cbc_encrypt(alice_msg, shared_S, iv_a) + iv_a print(f"Here is my (alice's) encrypted text: \t\t{alice_encrypt}") print("\n~~~~~SENDING MESSAGE~~~~~~ PLS NO INTERCEPT ~~~~~") print("~~~~~BUT EVEN IF YOU DO THIS IS UNHAXABLE~~~~~~~~\n") # 1b) Bob receives the message # Confirming that Bob received the message from Alice correctly iv_b = alice_encrypt[-32:] alice_ciphertext = alice_encrypt[:-32] bob_decrypt = cbc_decrypt(alice_ciphertext, shared_S, iv_b) padding = int(bob_decrypt[-1], 16)*2 bob_decrypt = bob_decrypt[:-padding] assert bob_decrypt == alice_msg iv_b = get_random_int(128) bob_encrypt = cbc_encrypt(bob_decrypt, shared_S, iv_b) + iv_b print(f"Thanks! Here is my (bob's) encrypted text: \t{bob_encrypt}") # 2) Bob sending message back to Alice iv_b = bob_encrypt[-32:] bob_ciphertext = bob_encrypt[:-32] alice_decrypt = cbc_decrypt(bob_ciphertext, shared_S, iv_b) padding = int(alice_decrypt[-1], 16)*2 alice_decrypt = alice_decrypt[:-padding] assert alice_decrypt == alice_msg """ PHASE 2 """ print("~~~~~~~~~~~~~~~~~~~~~~~~~~") print(" PHASE 2 ") print("~~~~~~~~~~~~~~~~~~~~~~~~~~") # if A == B == p, keys are just 0 since p^k mod p == 0 A, B = modexp(g,a,p), modexp(g,b,p) M_A, M_B = p, p S = modexp(M_A,b,p) bytes_S = hex(S)[2:].encode() print(f"shared secret is: {S}") assert S == modexp(M_B,a,p) sha_S = sha1(bytes_S,len(bytes_S)*8) print(f"shared secret is: {S}") shared_S = sha_S[2:][:32] """
def mac(msg): return sha1.sha1(key + msg)