HMAC algorithm implementation I wanted to understand the HMAC algorithm. So, I implemented it as a Jupyter Notebook with all intermediate steps being output to console. My objective now is to improve it so it may serve as a reference to anyone trying to implement or understand it.

The Jupyter Notebook on github is easier to read and I would like feedback on the notebook rather than the code below.

Jupiter notebook on GitHub

import hashlib
import hmac

### Define key, message, Block size, hashing algorithm    
hash_algo = "sha1"
B = 64
message = b'hello!'
key = b'key'

### hash () for an easy to read code
def hash(M):
    H = hashlib.new(hash_algo)
    H.update(M)
    b_hash = H.digest()
    return b_hash

### XOR Translation table
trans_5C = bytes((x ^ 0x5C) for x in range(256))
trans_36 = bytes((x ^ 0x36) for x in range(256))

### Zero pad key to block length B
K_zpad=key.ljust(B,b'\0')
# Xor with ipad and opad sequence
K_ipad=K_zpad.translate(trans_36)
K_opad=K_zpad.translate(trans_5C)

print("Key XOR ipad(0x363636...):\n"+K_ipad.hex())
print("\n\nKey XOR opad(0x505050...):\n"+K_opad.hex())

### concatinate message
part1=K_ipad+message
print("key XOR ipad || message:\n"+part1.hex())

### hash (key xor ipad || message )
hash1=hash(part1)
print("hash( key XOR ipad || message):\n"+hash1.hex())

### hash (key xor opad || hash ( (key xor ipad)||message ) )
part2 = K_opad + hash1
print("hash (key xor opad || hash ( (key XOR ipad)||message ) ):\n"+part2.hex())
hash_final = hash(part2)
print("\n\nFinal Hash:\n"+hash_final.hex())

# Compare with Python's HMAC Implementation
pyH=hmac.new(key,message,digestmod=hash_algo)
pyH.hexdigest()
My objective now is to improve it so it may serve as a reference to anyone trying to implement or understand it.


In light of that goal I would have thought it made more sense to use the documented test vectors of RFC 2202 rather than make up your own one.




### hash (key xor opad || hash ( (key xor ipad)||message ) )
part2 = K_opad + hash1
print("hash (key xor opad || hash ( (key XOR ipad)||message ) ):\n"+part2.hex())
hash_final = hash(part2)
print("\n\nFinal Hash:\n"+hash_final.hex())



The comment and the first print describe hash_final, not part2. IMO this is a bug, albeit a minor one.