第三章 SM3算法原理
SM3,说白了就是中国自己的密码学哈希标准。
它的全称是《SM3密码杂凑算法》,国标GM/T 0004-2012。在商用密码体系里,它负责干一件事:把任意长度的消息,压缩成固定256位的摘要。
我个人习惯把它看作数字指纹——消息哪怕改一个比特,指纹就完全不一样。
这一章,咱们就拆开SM3这个黑盒子,看看里面是怎么转的。同时我也会拿它和SHA-256做对比,毕竟它俩长得实在太像了。
哈希函数的通用骨架
绝大多数哈希函数都长一个模样,SM3也不例外。它们都遵循Merkle-Damgård结构。
这个结构很简单:
- 先把消息切成等长的块(SM3是512位一块)。
- 然后一块一块地喂给压缩函数。
- 前一块的输出作为下一块的输入。
- 最后一块处理完,输出的就是哈希值。
听起来就像流水线。每一块的中间结果叫做“链接变量”。一旦消息被篡改,链条就会断,摘要就会变。
消息填充:把数据弄整齐
SM3处理的数据是按512位分组的。但现实中的消息哪有这么巧?所以必须先做填充。
填充的规则很严格,我调过好几次因为填充顺序不对导致的bug。
填充步骤
- 先补一个“1”:在消息末尾追加一个比特1。对应字节就是0x80。
- 再补“0”:一直补0,直到满足一个条件——
填充后的长度 ≡ 448 (mod 512)。 - 最后附上原始长度:用64位大端整数,表示原始消息的比特长度。
为什么是448?因为448 + 64(长度域) = 512,刚好凑满一块。
举个例子
假设消息是"abc",3个字节=24比特。
- 填充后:
0x61 0x62 0x63 0x80 0x00 ... 0x00(补到448位) - 最后8字节:
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x18(24的十六进制)
你想想看,要是消息长度超过2^64比特怎么办?理论上不可能,实际也不会遇到。
迭代压缩:核心发动机
填充完之后,消息被分成了N个512位的消息块。接下来就是迭代压缩。
初始化
SM3有8个初始值,用16进制表示:
V0[0] = 0x7380166f
V0[1] = 0x4914b2b9
V0[2] = 0x172442d7
V0[3] = 0xda8a0600
V0[4] = 0xa96f30bc
V0[5] = 0x163138aa
V0[6] = 0xe38dee4d
V0[7] = 0xb0fb0e4e
消息扩展
每个512位的消息块(16个32位字)要先扩展成132个字:W0~W67和W'0~W'63。扩展规则是移位和异或的组合。我记得当初手写这个扩展时,算了好几遍才和标准对得上。
压缩函数
压缩函数迭代64轮。每一轮拿2个扩展后的字,加上当前的链接变量,通过一堆移位、异或、逻辑函数和加法的组合,更新这8个状态字。
具体公式我就不抄了,你查标准就行。但有一个关键:SM3用了两个特殊的布尔函数——FF和GG。它们是按轮数分段变化的:
- 0~15轮:FF = (X ∧ Y) ∨ (¬X ∧ Z),GG = (X ∧ Y) ∨ (¬X ∧ Z)
- 16~63轮:FF = (X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ Z),GG = ¬(X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ ¬Z)
说白了,就是前半段偏逻辑,后半段偏多数决。
一次迭代流程
处理第i个消息块时:
- 把当前链接变量V_i复制给临时变量A~H。
- 对A~H执行64轮压缩。
- 最后把A~H和V_i做异或加,得到新的V_{i+1}。
全部块处理完,V_N就是最终的哈希值,256位。
与SHA-256的异同
SM3和SHA-256都是256位输出,都基于Merkle-Damgård结构。但细节上有不少差别。我做项目时经常被问到:能不能直接用SHA-256的硬件代替SM3?答案是不行。你会碰壁的。
| 对比项 | SM3 | SHA-256 |
|---|---|---|
| 消息块大小 | 512位 | 512位 |
| 摘要长度 | 256位 | 256位 |
| 轮数 | 64轮 | 64轮 |
| 初始值 | 8个固定值 | 8个固定值(不同) |
| 消息扩展 | 生成132个32位字 | 生成64个32位字 |
| 布尔函数 | FF、GG,分两段变化 | Ch、Maj,全程不变 |
| 移位运算 | 循环左移和右移 | 右移和循环右移 |
| 加法常量 | 每轮固定常量 | 64个不同常量 |
| 大端/小端 | 全大端 | 全大端 |
| 安全性 | 已公开,国内商用密码强认证 | 已公开,国际通用标准 |
有一个核心区别:SM3的布尔函数在16轮后变了,这意味着它的扩散速度更快。我实测过,雪崩效应比SHA-256略好一点。
SM3核心流程总览
下面这张图,把SM3从输入到输出的整个流程串起来了。
你可以把它当作速查卡——每次写SM3代码前扫一眼,不容易漏步骤。
你看,从左到右、从上到下,逻辑很清楚。每一步都不能省,尤其填充那步最容易漏。我见过好几个同学直接拿原始消息去算,结果怎么算都不对。
SM3的安全特性
SM3被设计成具有以下性质:
- 抗原像性:给一个摘要,找不到原始消息。
- 抗第二原像性:给一个消息+摘要,找不到另一条消息产生相同摘要。
- 抗碰撞性:找不到任意两条消息有相同摘要。目前SM3还没有公开的有效碰撞攻击。
从我实际对比来看,SM3在一些国产密码评测中的表现和SHA-256相当,甚至在某些场景下扩散略快。但它最硬的优势就是:符合国标,不需要额外付费,也不涉及国际专利问题。
小结
这一章,我们把SM3的骨架讲透了。消息填充、迭代压缩、和SHA-256的那些异同,你都应该清楚了。