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

基于C从零实现SHA256的字节序问题求助

SHA256 小端机器字节序处理完全指南

核心原则

SHA256的所有规范定义都是基于大端字节序的,小端机器上实现时,仅需要在「字节流转32位字」和「最终哈希值输出」这两个环节做字节序转换,中间的32位字运算完全不需要考虑字节序。


各部分字节序处理细则

1. 消息块转32位字(消息调度w[0]-w[15])

填充后的消息是连续的字节流,每4个字节组成一个32位大端字。比如你提到的61 62 63 80这四个字节,必须按大端顺序拼接成uint32_t,也就是0x61626380。

你的错误在于直接把小端机器的内存布局当成了字的值:小端机器中,如果把这四个字节直接赋值给uint32_t变量,得到的是0x80636261(小端是低字节存低地址),这完全不符合SHA256的要求。必须手动转换,用这个函数处理:

uint32_t big_endian_bytes_to_u32(const uint8_t *bytes) {
    return ((uint32_t)bytes[0] << 24) |
           ((uint32_t)bytes[1] << 16) |
           ((uint32_t)bytes[2] << 8) |
           bytes[3];
}

对消息块的每4字节调用一次这个函数,就能得到正确的w[0]-w[15]。

2. 初始哈希值H0-H7

NIST给出的初始值是大端格式的十六进制数(比如H0=0x6a09e667),直接用这个十六进制字面量赋值给uint32_t变量即可。不需要做任何字节转换——因为C语言中十六进制字面量是按数值存储的,和机器字节序无关,变量存储的是正确的数值,后续运算直接用这个值就行。

3. 消息长度字段(最后64位)

必须转换为大端格式的64位整数后写入消息块的最后8个字节。比如输入"abc"是24比特,对应的64位数值是0x0000000000000018,小端机器上要把这个值转成大端字节序再写入:

void write_big_endian_u64(uint8_t *dst, uint64_t value) {
    dst[0] = (value >> 56) & 0xff;
    dst[1] = (value >> 48) & 0xff;
    dst[2] = (value >> 40) & 0xff;
    dst[3] = (value >> 32) & 0xff;
    dst[4] = (value >> 24) & 0xff;
    dst[5] = (value >> 16) & 0xff;
    dst[6] = (value >> 8) & 0xff;
    dst[7] = value & 0xff;
}

4. 消息调度w[16]-w[63]及压缩循环

这部分所有运算都是针对uint32_t的数值进行的,和字节序完全无关。只要w[0]-w[15]是正确的大端转换后的值,按NIST规范计算即可。你的右旋转函数是正确的,因为旋转操作是对32位数值的位操作,不需要考虑字节存储顺序。

5. 最终哈希结果输出

最终的H0-H7是uint32_t变量,每个变量需要转成大端字节序输出。比如输出H0时,要按(H0 >> 24) & 0xff、(H0 >> 16) & 0xff、(H0 >> 8) & 0xff、H0 & 0xff的顺序输出字节。


针对你的"abc"测试案例修正

  • 填充后的第一块前4字节是61 62 63 80,用big_endian_bytes_to_u32转换后得到w[0] = 0x61626380,这是正确值。
  • 基于正确的w[0]计算w[16]、w[17],就能和参考结果一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 10:02:25