CBC MAC
CBC-MAC¶
- Encrypt with CBC and the last block is the MAC.
- Uses an all zero IV
- Ensure that the MAC key is different than the encryption key
Implementation¶
from cryptopals_lib import *
from aes_lib import AES
def CBC_MAC(enc_obj, message, iv=None):
#First Block is the IV
cipher_block = iv
if iv == None:
cipher_block = b"\x00" * enc_obj.block_size
blocks = to_blocks(message, enc_obj.block_size)
for block in blocks:
xor_block = fixedlen_xor(block, cipher_block)
cipher_block = enc_obj.aes_block_encryption(xor_block)
#Do regular CBC Encryption but the MAC is the last block
return cipher_block
if __name__ == '__main__':
key = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
test = AES(key)
out = CBC_MAC(test, add_PKCS7_pad(b"Message Data", test.block_size))
print(out.hex())
IV Control Attack¶
The first block is controllable if the IV is user controllable
### IV Test
real_message = b"Administrator"
forged_message = b"administrator"
key = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
test = AES(key)
real_mac = CBC_MAC(test, add_PKCS7_pad(real_message, test.block_size))
#Manipulate the IV so the input is the same
manipulated_iv = fixedlen_xor(b"A", b"a") + b"\x00" * (test.block_size -1)
forged_mac = CBC_MAC(test, add_PKCS7_pad(forged_message, test.block_size), iv=manipulated_iv)
print(f"real_message: {real_message}, real_mac: {real_mac.hex()}")
#real_message: b'Administrator', real_mac: 958b151e5d001a449859077a20c9632d
print(f"manipulated_iv: {manipulated_iv.hex()}")
#manipulated_iv: 20000000000000000000000000000000
print(f"forged_message: {forged_message}, forged_mac: {forged_mac.hex()}")
#forged_message: b'administrator', forged_mac: 958b151e5d001a449859077a20c9632d
Message Spoofing Attack¶
### Block Forging
real_message = add_PKCS7_pad(b"User=Administrator", test.block_size)
forged_message1 = b"User=Administrat"
forged_message2 = b"or\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e"
key = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
test = AES(key)
real_mac = CBC_MAC(test, real_message)
#Lets get each block
forged_mac_block1 = CBC_MAC(test, forged_message1)
forged_mac_block2 = CBC_MAC(test, forged_message2)
#XOR the CBC output of forged_message1 with the Second block (forged_message2)
forged_input = fixedlen_xor(forged_mac_block1, forged_message2)
forged_mac = CBC_MAC(test, forged_input)
print(f"real_message: {real_message}, real_mac: {real_mac.hex()}")
#real_message: b'User=Administrator\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e', real_mac: 5bd3e29e4485c3c93ad2c54d19c70392
print(f"forged_message1: {forged_message1}, forged_mac: {forged_mac_block1.hex()}")
#forged_message1: b'User=Administrat', forged_mac: 80fdcee9dd73a3cdb4642acbb3a6d27b
print(f"forged_message2: {forged_message2}, forged_mac: {forged_mac_block2.hex()}")
#forged_message2: b'or\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e', forged_mac: c56302835470a32beeaf0a48adf979de
print(f"forged_input: {forged_input}, forged_mac: {forged_mac.hex()}")
#forged_input: b'\xef\x8f\xc0\xe7\xd3}\xad\xc3\xbaj$\xc5\xbd\xa8\xdcu', forged_mac: 5bd3e29e4485c3c93ad2c54d19c70392