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

我的HMAC-SHA-512实现与Python官方库结果不符,求排查

自定义HMAC-SHA512实现与官方库结果不一致的问题

我在密码学作业中实现了RFC2104定义的HMAC函数,但输出结果和Python官方hmac库、在线工具的结果均不匹配。官方库文档明确说明其实现符合RFC2104规范,我也按照H(K XOR opad, H(K XOR ipad, text))的算法步骤编写代码,但结果仍不一致,求排查实现中的错误。

我的实现代码

from hashlib import sha512
b = 512  # 此处错误:SHA-512的块大小是1024位,不是输出长度512位

def HMAC(key, message, h, b):
    # 按照RFC2104定义的7步实现HMAC
    # 初始化opad和ipad
    B = b//8  # 注释错误:B是哈希函数块大小对应的字节数,不是输出字节数
    ipad = 0x36
    opad = 0x5c

    # 步骤1:将key调整为B字节长度
    if len(key) > b:  # 错误:len(key)是字节数,b是位数,应该比较len(key) > B
        k = bytearray((h(k).digest()))  # 变量名错误:这里用了未定义的k,应该是h(key).digest()
    else:
        k = key + bytearray(B - len(key))  # 补零到B字节
    print(k, len(k))

    # 计算kXORopad和kXORipad
    kXopad = bytearray(B)
    kXipad = bytearray(B)
    for i in range(B):
        kXipad[i] ^= ipad  # 错误:没有和处理后的key k做异或,应该是k[i] ^ ipad
        kXopad[i] ^= opad  # 错误:同上,应该是k[i] ^ opad
    
    sub_result = h()
    sub_result.update(kXipad)
    sub_result.update(message)
    print(kXipad, len(kXipad))
    print(sub_result.digest())

    sub_result = bytearray(sub_result.digest())

    result = h()
    result.update(kXopad)
    print(kXopad, len(kXopad))
    print(result.digest())
    result.update(sub_result)

    return result.hexdigest()

# 测试用例
message = "a"
key = "a"
my_Hmac = HMAC(key.encode(), message.encode(), sha512, b)
print(my_Hmac)

import hmac
official_hmac = hmac.new(key.encode(), message.encode(), digestmod=sha512)
print(official_hmac.name)
print(official_hmac.hexdigest())
print(my_Hmac == official_hmac.hexdigest())

输出结果对比

  • 自定义实现的hex digest输出:
    4f330db94c708a6c6b54b009e48c54a1fa1e2fad77728c2d6c28fcdb7f702fa572ea928da2154537b7cef8f4f0389cfa9c7b67ebad21b445e58c228ead9e8c15

  • Python官方hmac库的hex digest输出:
    b37ee7821bf96e293def120539070a3010f69c37a247bb4bc1344d3491b89844525519df30d89a49d2537905b30cfa7f3a6ee54324eb1c280af5a747f3baaac5

  • 在线工具计算的SHA-512 HMAC结果:
    fc8c80e6b943cd07eccecf01bc6038bae68ebb6fa2e1e62b44753d7c177af7a46b089df349a19f7622a22312c76906ca9c984e1446d3ab86a98fdfa1425341c5

错误排查与修正

你的实现存在三个核心错误:

  1. 混淆了哈希函数的块大小与输出长度
    SHA-512的块大小是1024位(对应128字节),而你把b设为了SHA-512的输出长度512位。RFC2104中定义的b是哈希函数的块大小(位),所以正确的b值应为1024,B = 1024//8 = 128字节。

  2. 未将处理后的key与ipad/opad做异或
    你当前的代码只是创建了全0的bytearray,然后直接与ipad/opad异或,得到的是全0x36或全0x5c的数组,完全没有用到处理后的key k。正确的逻辑应该是:

    kXipad[i] = k[i] ^ ipad
    kXopad[i] = k[i] ^ opad
    
  3. key长度判断逻辑错误
    原代码中if len(key) > b的条件不成立:len(key)是字节数,b是位数,两者单位不一致。正确的判断应该是比较字节数:if len(key) > B(因为B是块大小的字节数)。同时,当key过长时,哈希的对象应该是原始key,而不是未定义的k,即h(key).digest()而非h(k).digest()。

修正后的代码示例

from hashlib import sha512
b = 1024  # SHA-512的块大小(位)

def HMAC(key, message, h, b):
    B = b // 8  # 块大小对应的字节数(128字节)
    ipad = 0x36
    opad = 0x5c

    # 步骤1:调整key到B字节长度
    if len(key) > B:
        # key过长则哈希后取摘要,再补零到B字节
        k = bytearray(h(key).digest())
        k += bytearray(B - len(k))
    else:
        # key过短则补零到B字节
        k = bytearray(key) + bytearray(B - len(key))

    # 计算k XOR ipad 和 k XOR opad
    kXipad = bytearray([byte ^ ipad for byte in k])
    kXopad = bytearray([byte ^ opad for byte in k])
    
    # 计算H(k XOR ipad, message)
    sub_result = h()
    sub_result.update(kXipad)
    sub_result.update(message)
    sub_digest = sub_result.digest()

    # 计算H(k XOR opad, sub_digest)
    result = h()
    result.update(kXopad)
    result.update(sub_digest)

    return result.hexdigest()

# 测试
message = "a"
key = "a"
my_Hmac = HMAC(key.encode(), message.encode(), sha512, b)
print(my_Hmac)

import hmac
official_hmac = hmac.new(key.encode(), message.encode(), digestmod=sha512)
print(official_hmac.hexdigest())
print(my_Hmac == official_hmac.hexdigest())  # 现在会输出True

内容的提问来源于stack exchange,提问作者El-Icarus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 11:35:22