You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用hmac库实现RFC2104 SHA-1 HMAC遇测试向量不符问题

你的HMAC-SHA1代码问题梳理

咱们来一步步拆解你代码里的问题,这些都是导致和RFC测试向量对不上的核心原因:

1. 错误的Block Size定义

你把SHA-1的blocksize设成了40,但这是SHA-1输出的十六进制字符长度(SHA-1原始输出是20字节,转十六进制是40个字符)。HMAC要求的blocksize是哈希函数的内部块大小,SHA-1的内部块大小是512位,也就是64字节。这个参数错了,整个HMAC的逻辑就完全跑偏了。

2. 字符串、字节、十六进制的混乱处理

HMAC是纯字节流的算法,你现在混合了字符串转十六进制、数字转字符串拼接等操作,完全破坏了字节级的运算逻辑:

  • 你的toHex函数把输入字符串转成十六进制字符串,但这完全没必要——比如测试向量里的"Jefe"应该直接用原始字节b"Jefe",而不是它的十六进制表示"4a656665"。
  • 异或操作后你把结果转成字符串拼接(比如str(ord(key[i]) ^ val1)),这会把字节值(比如99)变成字符串"99",而不是对应的字节b'\x63',彻底打乱了后续哈希的输入结构。

3. Key填充逻辑错误

  • 你写的pad函数在key左边补'0'字符串,但HMAC要求的是在key的末尾补0字节,直到长度达到blocksize。
  • 当key长度超过blocksize时,你直接赋值key = hasher(key),但如果key是字符串的话,哈希函数会报错;正确的做法是先把key转成字节,哈希后取原始字节结果(用digest()),而不是十六进制字符串(hexdigest())。

4. 哈希函数硬编码+参数未使用

你在hmac函数里硬写了hasher = hashlib.sha1,完全忽略了传入的hashfunc参数,这样不管用户选SHA-256还是SHA-1,都只会用SHA-1,这也不符合你的功能设计。


修正后的完整代码

下面是修复所有问题后的代码,完全遵循RFC 2104的逻辑:

import hashlib

def hmac(key, message, hashfunc):
    # 根据选择的哈希函数获取对应的实现和参数
    if hashfunc == '1':  # SHA-1
        hasher = hashlib.sha1
        blocksize = 64  # SHA-1内部块大小:512位=64字节
    elif hashfunc == '0':  # SHA-256
        hasher = hashlib.sha256
        blocksize = 64  # SHA-256内部块大小同样是512位=64字节
    else:
        raise ValueError("Invalid hash selection - use 0 for SHA-256, 1 for SHA-1")

    # 统一把输入转成字节(如果是字符串的话)
    if isinstance(key, str):
        key = key.encode('utf-8')
    if isinstance(message, str):
        message = message.encode('utf-8')

    # 处理Key:长度超过blocksize则哈希缩短;不足则补0字节到blocksize
    if len(key) > blocksize:
        key = hasher(key).digest()
    elif len(key) < blocksize:
        key += b'\x00' * (blocksize - len(key))

    # 生成o_key_pad和i_key_pad:字节级异或操作
    o_key_pad = bytes(byte ^ 0x5c for byte in key)
    i_key_pad = bytes(byte ^ 0x36 for byte in key)

    # 计算内部哈希:i_key_pad拼接message,取原始字节结果
    inner_hash = hasher(i_key_pad + message).digest()
    # 计算最终哈希:o_key_pad拼接内部哈希,转十六进制输出
    final_hash = hasher(o_key_pad + inner_hash).hexdigest()
    print(final_hash)
    return final_hash

def main():
    while True:
        key = input("key = ")
        message = input("message = ")
        hash_choice = input("hash (0: SHA-256, 1: SHA-1) = ")
        try:
            hmac(key, message, hash_choice)
        except ValueError as e:
            print(e)

if __name__ == "__main__":
    main()

验证RFC测试向量

用RFC 2104里的测试用例验证:

Test Case 1
key = "Jefe"
message = "what do ya want for nothing?"
预期HMAC-SHA1结果:effcdf6ae5eb2fa2d27416d5f184df9c259a7c79

运行代码输入上述值,选1(SHA-1),会输出正确的结果。

另外关于你提到的维基伪代码里的output size参数:那个参数确实是冗余的,因为HMAC的输出长度就是哈希函数的输出长度,所以伪代码里没用到它,不用纠结这个。

内容的提问来源于stack exchange,提问作者Kodiak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:18:26