HMAC SHA256内层哈希正常但外层哈希结果错误求助
HMAC-SHA256外层Hash结果不符的排查建议
问题背景
实现NIST标准的HMAC-SHA256时,内层Hash(Hash((Key^ipad)||text))结果符合预期,但外层Hash(Hash((Key^opad)||H_1))结果错误。已知K0、K0ipad、K0opad、内层Hash结果均正确,外层得到的ASCII结果为218135127ad7a8e5967ce7b47499214d1df46a9589eb0bec7637c86021fd928d,预期是8BB9A1DB9806F20DF7F77B82138C7914D174D59E13DC4D0169C9057B133E1D62。
相关代码片段:
// Up to this point ipad, opad, K0, both XORs all match the expected values const std::array<uint32_t, 8>& h_output_1 = Hash<BUFFER_SIZE>(&xor_1[0], 64, &message[0], message_length); // This is correct LOG("H_1: " << sha256::GetASCIIRepresentation(h_output_1)); const std::array<uint32_t, 8>& h_output_2 = Hash<BUFFER_SIZE>(&xor_2[0], 64, &h_output_1[0], 32); // This is NOT correct LOG("H_2: " << sha256::GetASCIIRepresentation(h_output_2));
排查方向
1. 检查内层输出的字节序匹配问题
SHA-256的最终状态(8个uint32_t)是大端字节序定义的,但内存中uint32_t的存储默认是主机字节序(多数系统为小端)。
- 若直接将
h_output_1的内存布局(小端字节)传给外层Hash,相当于每个uint32_t的字节顺序被反转,外层输入会完全错误。 - 验证方式:将
h_output_1的每个uint32_t转换为大端字节序后拼接成32字节缓冲区,对比该缓冲区的十六进制与NIST示例中H_1的十六进制是否一致。
2. 确认Hash函数的拼接逻辑
Hash(buffer1, len1, buffer2, len2)的拼接逻辑需严格符合预期:
- 检查函数是否将
len2当成uint32_t的个数而非字节数(比如误将32字节解读为8个uint32_t,导致读取64字节越界数据)。 - 手动构造
(K0^opad)||H_1的正确字节流,用独立SHA-256工具计算结果,再dump代码中外层Hash的实际输入字节流,对比两者是否完全一致。
3. 验证uint32_t数组到字节流的转换
传递&h_output_1[0]给Hash时,需确保转换为32字节的正确字节流:
- 若
GetASCIIRepresentation是将每个uint32_t按大端转十六进制(如0x12345678转"12345678"),但传给Hash的是内存中小端字节,会出现H_1显示正确但外层输入错误的情况。 - 测试方案:将
h_output_1的每个uint32_t按大端转换为4字节,拼接成32字节数组后替换&h_output_1[0]传给外层Hash,查看结果是否符合预期。
4. 核对外层Hash的输入完整性
完整dump外层Hash的输入(opad + H_1字节流),与NIST示例中的对应输入逐字节对比:
- NIST HMAC示例的外层输入是
(K0^opad)拼接内层Hash的字节结果,而非uint32_t状态的内存布局,确保输入完全匹配。
内容的提问来源于stack exchange,提问作者intrigued_66
相关产品推荐
相关产品推荐

