使用hashlib.sha1实现HMAC-SHA1时遇类型错误:无法拼接哈希对象与字节
解决HMAC-SHA1实现中的类型错误问题
问题根源
报错TypeError: can't concat _hashlib.HASH to bytes的核心原因:
- 自定义的
sha1函数返回的是_hashlib.HASH哈希实例对象,而非哈希计算后的字节串,导致无法和bytes类型数据直接拼接 - 代码中多余的Base64编码完全没必要,会导致哈希结果和标准HMAC-SHA1不一致
- 密钥处理分支中,当密钥长度超过块大小B时,同样试图将HASH对象与bytes拼接,触发类型错误
修正步骤
- 修复自定义sha1函数:让它返回哈希计算后的字节串(调用
digest()方法),同时移除多余的Base64编码 - 修正hmac_sha1拼接逻辑:确保所有参与拼接的都是bytes类型
- 补充bxor函数:实现字节级的异或操作(代码中用到但未定义)
修正后的完整代码
import hashlib def bxor(a, b): # 实现两个字节串的逐字节异或 return bytes(x ^ y for x, y in zip(a, b)) def sha1(data): sha1_object = hashlib.sha1() sha1_object.update(data) # 返回哈希后的字节串,而非HASH对象 return sha1_object.digest() def hmac_sha1(data, key): IPAD = b'\x36' * 64 OPAD = b'\x5C' * 64 B = hashlib.sha1().block_size L = hashlib.sha1().digest_size if len(key) == B: K_exp = key elif len(key) > B: # 先哈希密钥得到字节串,再补零 K_exp = sha1(key) + b'\x00' * (B - L) else: K_exp = key + b'\x00' * (B - len(key)) # 所有操作均为字节串拼接,无HASH对象参与 inner_hash = sha1(bxor(K_exp, IPAD) + data) return sha1(bxor(K_exp, OPAD) + inner_hash) # 测试验证 if __name__ == "__main__": key = b'Test Key' data = b'Test Message' # 标准库结果 standard_digester = hashlib.hmac.new(key, data, hashlib.sha1) standard_signature = standard_digester.digest() # 自定义实现结果 custom_signature = hmac_sha1(data, key) assert custom_signature == standard_signature, "结果不一致!" print(f"签名验证通过,签名值:{custom_signature.hex()}")
关键说明
sha1函数现在返回digest()的字节串结果,满足后续拼接操作的类型要求- 移除了Base64编码,HMAC-SHA1直接对原始字节数据计算,无需额外编码
- 密钥处理分支中,
sha1(key)返回字节串,可与补零的bytes正常拼接 - 补充的
bxor函数确保字节异或操作能正确执行
内容的提问来源于stack exchange,提问作者quintus
相关产品推荐
相关产品推荐

