5.5 TEST PYTHON’S HMAC

EXERCISE 5.5 TEST PYTHON’S HMAC

Although you should not roll your own crypto, it doesn’t mean you shouldn’t verify implementations! Create your own implementation of HMAC following the instructions from RFC 2104 and test some inputs and keys with both your implementation and Python’s cryptography library’s implementation. Ensure that they produce the same outputs!


Python’s HMAC

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, hmac 

def pythons_sha256_hmac(text: bytes, k: bytes) -> bytes: 
    h = hmac.HMAC(k, hashes.SHA256(), backend=default_backend())
    h.update(text) 
    return h.finalize()
official_result = pythons_sha256_hmac(text=b'hello world', k=b'accccc').hex(sep=' ')
print(official_result)
ae 7d 07 10 49 9d 66 48 ce 14 71 95 f7 96 06 a7 02 74 a2 93 34 67 0b 4a f5 18 f7 99 10 d6 f4 b0

Custom HMAC

from hashlib import sha256

BLOCK_SIZE_OF_SHA256 = 64  # bytes

def h(x: bytes) -> bytes: return sha256(x).digest()

def make_key_B_bytes_long(key: bytes):
    if len(key) == BLOCK_SIZE_OF_SHA256:
        return key
    elif len(key) < BLOCK_SIZE_OF_SHA256:
        return key + bytes(BLOCK_SIZE_OF_SHA256 - len(key))
    else:
        return make_key_B_bytes_long(h(key))


# the following function is taken from Exercise 3.9.
def xor_two_byte_strings(x: bytes, y: bytes) -> bytes:
    assert (len(x) == len(y))

    result = []
    for _1, _2 in zip(x, y):
        result.append(_1 ^ _2)
    return bytes(result)


def custom_hmac(key: bytes, text: bytes) -> bytes:
    key = make_key_B_bytes_long(key=key)
    ipad = bytes.fromhex('36') * BLOCK_SIZE_OF_SHA256
    opad = bytes.fromhex('5c') * BLOCK_SIZE_OF_SHA256
    kipad = xor_two_byte_strings(key, ipad)
    kopad = xor_two_byte_strings(key, opad)

    return h(kopad + h(kipad + text))
custom_result = custom_hmac(text=b'hello world', key=b'accccc').hex(sep=' ')
print(custom_result)
ae 7d 07 10 49 9d 66 48 ce 14 71 95 f7 96 06 a7 02 74 a2 93 34 67 0b 4a f5 18 f7 99 10 d6 f4 b0
print(custom_result == official_result)
True