Cmac
Cipher-based Message Authentication Code
- AES-CBC the message and take the last block and use it as the tag
Implementation
from aes_lib import AES
from cryptopals_lib import int_to_bytes, bytes_to_int, fixedlen_xor, asint, to_blocks
class CMAC():
"""docstring for CMAC"""
def __init__(self, key):
self.key = key
self.block_size = 16
self.crypt = AES(self.key)
self.subkeys = self._gen_subkeys()
def _gen_subkeys(self):
#Encrypt a Zero block
enc_zeros = self.crypt.aes_block_encryption(b"\x00" * self.block_size)
#Left Shift encrypted zero budder output by 1
key_1 = int_to_bytes(asint(bytes_to_int(enc_zeros) << 1, self.block_size*8))
#If first bit is set xor byte
if enc_zeros[0] & 0x80 != 0:
key_1[-1] ^= 0x87
#Left Shift key_1 output by 1
key_2 = int_to_bytes(asint(bytes_to_int(key_1) << 1, self.block_size*8))
#print(key_2)
#If first bit is set xor byte
if key_1[0] & 0x80 != 0:
tmp = fixedlen_xor(key_2[-1], 0x87)
key_2 = key_2[:-1] + int_to_bytes(tmp)
return key_1, key_2
def _pad_message(self, message):
#Pad the message
padding_num = len(message) % self.block_size
if len(message) == 0 or padding_num != 0:
message += b"\x80" + b"\x00" * (self.block_size - 1 - padding_num)
xor_key = self.subkeys[1]
else:
xor_key = self.subkeys[0]
#Convert into blocks of 128 bits
message_blocks = to_blocks(message, 16)
#print([x.hex() for x in message_blocks])
#Xor last block with the approprate key
message_blocks[-1] = fixedlen_xor(message_blocks[-1], xor_key)
return message_blocks
def hash(self, message):
#Pad Message
message_blocks = self._pad_message(message)
hash_output = b"\x00" * self.block_size
for block in message_blocks:
print(f"Round: {block.hex()}")
tmp = fixedlen_xor(block, hash_output)
hash_output = self.crypt.aes_block_encryption(tmp)
return hash_output
def hashdigest(self, message):
return self.hash(message).hex()
if __name__ == '__main__':
#Test Vectors
k = b"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c"
m1 = b""
m2 = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
m3 = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" \
b"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" \
b"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
m4 = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" \
b"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" \
b"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" \
b"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10"
c = CMAC(k)
k1,k2 = c._gen_subkeys()
print(f"k1 : {k1.hex()}")
#k1 : fbeed618357133667c85e08f7236a8de
print(f"k2 : {k2.hex()}")
#k2 : f7ddac306ae266ccf90bc11ee46d513b
print(f"t1 : {c.hash(m1).hex()}")
#t1 : bb1d6929e95937287fa37d129b756746
print(f"t2 : {c.hash(m2).hex()}")
#t2 : 070a16b46b4d4144f79bdd9dd04a287c
print(f"t3 : {c.hash(m3).hex()}")
#t3 : dfa66747de9ae63030ca32611497c827
print(f"t4 : {c.hash(m4).hex()}")
#t4 : 51f0bebf7e3b9d92fc49741779363cfe