Freddy L.
Freddy L.

Reputation: 193

HMAC SHA256 in Python: HMAC Library vs Hashlib Produces Different Results

So I've been looking at Wikipedia's pseudocode for HMAC and it seemed relatively straightforward; if your key size is already the block size, the pseudo code boils down to 3 lines:

    o_key_pad ← key xor [0x5c * blockSize]   // Outer padded key
    i_key_pad ← key xor [0x36 * blockSize]   // Inner padded key

    return hash(o_key_pad ∥ hash(i_key_pad ∥ message))

This translates very easily into Python:

ik = bytes([0x36 ^ b for b in k])
ok = bytes([0x5c ^ b for b in k])

print(hashlib.sha256(ok + bytearray.fromhex(hashlib.sha256(ik+msg).hexdigest())).hexdigest())

But this doesn't produce the same result as using Python's HMAC library:

p = bytes("password", encoding='utf8')
k = bytearray.fromhex("eae1f9b8c78d0e0dbaeb3bc49fea3f0be9e9dc580c0b0ba09bcf5104713fda80")

x = hmac.new(k, digestmod='sha256')
x.update(p)
print(x.hexdigest())

ik = bytes([0x36 ^ b for b in k])
ok = bytes([0x5c ^ b for b in k])
print(hashlib.sha256(ok + bytearray.fromhex(hashlib.sha256(ik+p).hexdigest())).hexdigest())

ends up producing

1b96a6d3473698c3592a99d752934b875f82cdd623230abc534f92e7b70cc251 57dcbe4ada890bcc8d3cc2e6072874e0d1a0d6d3f73ceb1ced8dad4f07b56e33

Why?

Upvotes: 3

Views: 998

Answers (1)

Topaco
Topaco

Reputation: 49460

In the custom implementation the padding of the key to the block size is missing, see here:

Keys shorter than blockSize are padded to blockSize by padding with zeros on the right

The block size of SHA256 is 64 bytes, see here.

The following ptyhon code produces the expected result:

import hmac 
import hashlib

p = bytes("password", encoding='utf8')
k = bytearray.fromhex("eae1f9b8c78d0e0dbaeb3bc49fea3f0be9e9dc580c0b0ba09bcf5104713fda80")

x = hmac.new(k, digestmod='sha256')
x.update(p)
print(x.hexdigest())

k = bytearray.fromhex("eae1f9b8c78d0e0dbaeb3bc49fea3f0be9e9dc580c0b0ba09bcf5104713fda80".ljust(128,'0')) # pad with zeros
ik = bytes([0x36 ^ b for b in k])
ok = bytes([0x5c ^ b for b in k])
print(hashlib.sha256(ok + bytearray.fromhex(hashlib.sha256(ik+p).hexdigest())).hexdigest())

with the output:

1b96a6d3473698c3592a99d752934b875f82cdd623230abc534f92e7b70cc251
1b96a6d3473698c3592a99d752934b875f82cdd623230abc534f92e7b70cc251

which can also be verified here.

Upvotes: 2

Related Questions