问题描述
因此,我一直在查看Wikipedia的HMAC伪代码,它似乎相对简单。如果您的密钥大小已经是块大小,则伪代码可归结为3行:
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))
这很容易翻译成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())
但这不会产生与使用Python的HMAC库相同的结果:
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())
最终生产
1b96a6d3473698c3592a99d752934b875f82cdd623230abc534f92e7b70cc251 57dcbe4ada890bcc8d3cc2e6072874e0d1a0d6d3f73ceb1ced8dad4f07b56e33
为什么?
解决方法
在自定义实现中,缺少对块大小的键的填充,请参见here:
短于blockSize的键通过在右边用零填充来填充为blockSize
SHA256的块大小为64个字节,请参见here。
以下ptyhon代码会产生预期的结果:
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())
输出:
1b96a6d3473698c3592a99d752934b875f82cdd623230abc534f92e7b70cc251
1b96a6d3473698c3592a99d752934b875f82cdd623230abc534f92e7b70cc251
也可以通过here进行验证。