4. SM3 密码杂凑算法:从原理到实战
SM3 是国密标准里的杂凑算法,说白了就是给任意长度的数据算出一个固定长度的“指纹”。我最早接触它是在一个政务系统项目里,当时甲方明确要求必须用国密,不能用 SHA-256。嗯,从那以后我就把 SM3 的细节啃了个透。
这一章咱们就把它讲清楚:消息怎么填充、怎么迭代压缩、消息怎么扩展,再跟 SHA-256 做个对比,最后看看它在 HMAC 和区块链里怎么落地。
4.1 SM3 算法原理
SM3 的输出长度是 256 位,也就是 32 个字节。整个流程分三步:消息填充、迭代压缩、消息扩展。我习惯把这三步记成“填平、揉碎、再拧紧”。
4.1.1 消息填充
SM3 处理消息的最小单位是 512 位(64 字节)的分组。如果消息长度不是 512 的倍数,就得填充。
填充规则很简单:
- 先在消息末尾补一个 1 比特(二进制 1)
- 然后补 0,直到长度满足 (消息长度 + 填充长度 + 64) mod 512 = 0
- 最后 64 位放原始消息的长度(大端序)
举个例子:原始消息是“abc”,长度 24 比特。填充后:
原始: 01100001 01100010 01100011
补1: 01100001 01100010 01100011 1
补0: ... 后面补 0 直到长度 = 512 - 64 - 24 - 1 = 423 个 0
最后64位: 00000000...00011000 (24 的大端表示)
4.1.2 迭代压缩
填充完成后,消息被分成若干个 512 位的分组。每个分组经过 64 轮压缩,最终输出 256 位的杂凑值。
初始值 IV 是固定的 8 个 32 位字:
IV = 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600,
0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E
每一轮压缩函数 CF 接收当前分组和上一轮的 256 位状态,输出新的 256 位状态。64 轮结束后,把最终状态和初始 IV 异或,得到该分组的杂凑值。
核心公式(简化版):
V(i+1) = CF(V(i), B(i))
其中 V(0) = IV,B(i) 是第 i 个消息分组。
4.1.3 消息扩展
每个 512 位的分组需要扩展成 132 个 32 位字(W0 ~ W67 和 W'0 ~ W'63),供 64 轮压缩使用。
扩展规则:
- 前 16 个字 W0 ~ W15 直接从分组中取
- W16 ~ W67 通过异或和循环移位生成
- W'j = Wj XOR Wj+4
你想想看,为什么要扩展?说白了就是为了让每一轮的输入都跟其他轮次充分“搅和”在一起,避免碰撞。
4.2 与 SHA-256 的对比分析
SM3 和 SHA-256 都是 256 位输出,结构也很像。但细节上差别不小。我整理了一个对比表:
| 对比项 | SM3 | SHA-256 |
|---|---|---|
| 输出长度 | 256 位 | 256 位 |
| 分组大小 | 512 位 | 512 位 |
| 压缩轮数 | 64 轮 | 64 轮 |
| 消息扩展 | 132 个字 | 64 个字 |
| 布尔函数 | GG, FF(含异或和与运算) | Ch, Maj(较简单) |
| 循环移位 | 多种移位组合 | 固定右移 |
| 安全性 | 抗碰撞性优于 SHA-256 | 已被理论攻击削弱 |
我个人觉得,SM3 在布尔函数和消息扩展上比 SHA-256 更复杂,所以安全性也更高。但代价就是性能稍慢——大概慢 10%~15%。不过现在硬件加速普及,这点差距基本可以忽略。
4.3 SM3 在 HMAC 中的应用
HMAC(基于哈希的消息认证码)需要底层杂凑算法。用 SM3 做 HMAC,流程跟 HMAC-SHA256 一样:
HMAC-SM3(K, M) = SM3( (K' XOR opad) || SM3( (K' XOR ipad) || M ) )
其中:
- K' 是密钥经过填充后的 512 位值
- ipad = 0x36 重复 64 次
- opad = 0x5C 重复 64 次
我在做国密改造时,经常遇到的一个坑是:密钥长度超过 64 字节时,需要先用 SM3 对密钥做一次杂凑,再用杂凑值作为密钥。这个细节很多文档没写清楚。
4.4 SM3 在区块链中的应用
区块链里哈希算法是核心。比特币用 SHA-256,以太坊用 Keccak-256。国密区块链自然用 SM3。
主要用在三个地方:
- 交易哈希:每笔交易的唯一标识
- 区块哈希:区块头的指纹,链接前后区块
- Merkle 树:验证交易是否被篡改
我记得有个联盟链项目,客户要求所有交易哈希必须用 SM3。当时我们直接把底层哈希接口替换成 SM3,上层逻辑完全不用改。但要注意:SM3 的输出是 32 字节,跟 SHA-256 一样,所以数据结构兼容性很好。
下面这张图展示了 SM3 在区块链 Merkle 树中的角色:
从图中可以看到,每个交易先单独算 SM3 哈希,然后两两拼接再算哈希,最终得到 Merkle 根。只要有一个交易被篡改,根哈希就会变。这就是区块链防篡改的基础。
关键点:SM3 在区块链里不只是算哈希,还参与数字签名(SM2)和密钥派生。三者配合才能构成完整的国密区块链安全体系。