def parameter_injection_attack(alice, bob): """Simulates a MITM key-fixing attack on Diffie-Hellman with parameter injection.""" # Step 1: Alice computes A and sends it to the MITM (thinking of Bob) A = alice.get_public_key() # Step 2: the MITM changes A with p and sends it to Bob A = alice.p # Step 3: Bob computes B and sends it to the MITM (thinking of Alice) B = bob.get_public_key() # Step 4: the MITM changes B with p and sends it to Alice B = bob.p # Step 5: Alice finally sends her encrypted message to Bob (without knowledge of MITM) _msg = b'Hello, how are you?' _a_key = unhexlify(sha1(str(alice.get_shared_secret_key(B)).encode()))[:16] _a_iv = Random.new().read(AES.block_size) a_question = aes_cbc_encrypt(_msg, _a_key, _a_iv) + _a_iv # Step 6: the MITM relays that to Bob # Step 7: Bob decrypts the message sent by Alice (without knowing of the attack), encrypts it and sends it again _b_key = unhexlify(sha1(str(bob.get_shared_secret_key(A)).encode()))[:16] _a_iv = a_question[-AES.block_size:] _a_message = aes_cbc_decrypt(a_question[:-AES.block_size], _b_key, _a_iv) _b_iv = Random.new().read(AES.block_size) b_answer = aes_cbc_encrypt(_a_message, _b_key, _b_iv) + _b_iv # Step 8: the MITM relays that to Alice # Step 9: the MITM decrypts the message (either from a_question or from b_answer, it's the same). # # Finding the key after replacing A and B with p is, in fact, very easy. # Instead of (B^a % p) or (A^b % p), the shared secret key of the exercise became (p^a % p) # and (p^b % p), both equal to zero! mitm_hacked_key = unhexlify(sha1(b'0').encode())[:16] # Hack Alice's question mitm_a_iv = a_question[-AES.block_size:] mitm_hacked_message_a = aes_cbc_decrypt(a_question[:-AES.block_size], mitm_hacked_key, mitm_a_iv) # Hack Bob's answer (which here is the same) mitm_b_iv = b_answer[-AES.block_size:] mitm_hacked_message_b = aes_cbc_decrypt(b_answer[:-AES.block_size], mitm_hacked_key, mitm_b_iv) # Check if the attack worked assert _msg == mitm_hacked_message_a == mitm_hacked_message_b
def encrypt(plaintext): # Add a random padding before and after the plaintext padded_plaintext = AesEncryptionOracle._pad_with_bytes(plaintext) # Generate a random key key = Random.new().read(block_size) # Encrypt randomly with ECB or CBC if randint(0, 1) == 0: return "ECB", aes_ecb_encrypt(padded_plaintext, key) else: return "CBC", aes_cbc_encrypt(padded_plaintext, key, Random.new().read(block_size))
def get_encrypted_message(self): """Selects at random one of the 10 input strings and encrypts it under a random key and IV with AES-128-CBC.""" chosen_input = self._possible_inputs[randint( 0, len(self._possible_inputs) - 1)].encode() return aes_cbc_encrypt(chosen_input, self._key, self.iv)
def encrypt(self, data): """Adds the prefix and the suffix specified in the challenge and encrypts the data with AES-128-CBC""" data = data.replace(';', '').replace( '=', '') # Remove special characters to avoid injection plaintext = (self._prefix + data + self._suffix).encode() return aes_cbc_encrypt(plaintext, self._key, self._iv)
def malicious_g_attack(): """Simulates the break of Diffie-Hellman with negotiated groups by using malicious 'g' parameters.""" p = DiffieHellman.DEFAULT_P for g in [1, p, p - 1]: # Step 1: the MITM changes the default g sent by Alice to Bob with a forced value alice = DiffieHellman() bob = DiffieHellman(g=g) # Step 2: Bob receives this forced g and sends an ACK to Alice # Step 3: Alice computes A and sends it to the MITM (thinking of Bob) A = alice.get_public_key() # Step 4: Bob computes B and sends it to the MITM (thinking of Alice) B = bob.get_public_key() # Step 5: Alice sends her encrypted message to Bob (without knowledge of MITM) _msg = b'Hello, how are you?' _a_key = unhexlify(sha1(str( alice.get_shared_secret_key(B)).encode()))[:16] _a_iv = Random.new().read(AES.block_size) a_question = aes_cbc_encrypt(_msg, _a_key, _a_iv) + _a_iv # Step 6: Bob receives the message sent by Alice (without knowing of the attack) # However, this time Bob will not be able to decrypt it, because (if I understood the # challenge task correctly) Alice and Bob now use different values of g. # Step 7: the MITM decrypts the Alice's question mitm_a_iv = a_question[-AES.block_size:] # When g is 1, the secret key is also 1 if g == 1: mitm_hacked_key = unhexlify(sha1(b'1').encode())[:16] mitm_hacked_message = aes_cbc_decrypt(a_question[:-AES.block_size], mitm_hacked_key, mitm_a_iv) # When g is equal to p, it works the same as in the S5C34 attack (the secret key is 0) elif g == p: mitm_hacked_key = unhexlify(sha1(b'0').encode())[:16] mitm_hacked_message = aes_cbc_decrypt(a_question[:-AES.block_size], mitm_hacked_key, mitm_a_iv) # When g is equal to p - 1, the secret key is (-1)^(ab), which is either (+1 % p) or (-1 % p). # We can try both and later check the padding to see which one is correct. else: for candidate in [str(1).encode(), str(p - 1).encode()]: mitm_hacked_key = unhexlify(sha1(candidate).encode())[:16] mitm_hacked_message = aes_cbc_decrypt( a_question[:-AES.block_size], mitm_hacked_key, mitm_a_iv, unpad=False) if is_pkcs7_padded(mitm_hacked_message): mitm_hacked_message = pkcs7_unpad(mitm_hacked_message) break # Check if the attack worked assert _msg == mitm_hacked_message