2. SM4 算法核心原理:轮函数、S盒与密钥扩展
好,咱们直接切入正题。
SM4 算法,说白了就是一种分组密码。跟 AES 类似,它把数据切成 128 位一块,然后用一个 128 位的密钥去加密。
我个人习惯,先不看那些复杂的数学公式,先搞清楚它的骨架——轮函数、S 盒、密钥扩展。这三个东西搞明白了,整个算法基本就通了。
2.1 整体结构:一种“非线性-线性-异或”的迭代结构
SM4 用的是 32 轮迭代 的结构。
每一轮做的事情,核心就三个步骤:
- 非线性变换:通过 S 盒做字节替换,引入混淆(Confusion)。
- 线性变换:通过移位和异或,把局部的影响扩散到整个分组(Diffusion)。
- 轮密钥加:把这一轮的密钥异或进去。
你可以这么理解:一轮就是一个“搅拌”过程。32 轮下来,明文和密钥的关系被彻底打乱。
2.2 轮函数 F:每一轮的核心运算
轮函数 F 的输入是 4 个 32 位的字(X0, X1, X2, X3),加上一个 32 位的轮密钥 rk。
输出是一个 32 位的字。它的数学表达式很简单:
F(X0, X1, X2, X3, rk) = X0 ⊕ T(X1 ⊕ X2 ⊕ X3 ⊕ rk)
说白了,就是三步走:
- 先做一次异或:把 X1, X2, X3 和轮密钥 rk 异或起来。
- 然后走 T 变换:这个 T 是“非线性 + 线性”的组合。
- 最后再跟 X0 异或:得到本轮的输出。
这里的 T 变换,是 SM4 的精髓。我单独拆开讲。
2.3 T 变换:S盒 + L变换
T 变换由两部分串联:
2.3.1 非线性变换 τ:S 盒的天地
τ 变换把输入的 32 位,拆成 4 个 8 位的字节。每个字节单独查一个固定的 S 盒。
这个 S 盒是 SM4 算法设计好的,一个 8x8 的替换表。你想想看,它定义好了每个输入字节应该替换成什么输出字节。
为什么要有 S 盒?
为了防止代数攻击。如果全是线性运算,那这个密码就太脆弱了。S 盒是非线性的,它是整个算法安全性的基石。
2.3.2 线性变换 L:把雪崩效应拉满
τ 变换的输出是一个 32 位的字 B。对它再做一次线性变换 L:
L(B) = B ⊕ (B <<< 2) ⊕ (B <<< 10) ⊕ (B <<< 18) ⊕ (B <<< 24)
这里 <<< 表示 32 位的循环左移。你看,就 4 次异或,3 次移位。你看明白了吗?这步操作的目的,就是让 S 盒替换后的任意一个比特变化,能够迅速扩散到整个 32 位输出。这就是所谓的“雪崩效应”。
所以,轮函数 F 的整体流程,可以用一个简单的图来表示:
2.4 S 盒:算法的“保险柜”
SM4 的 S 盒是固定的,由算法设计者用某种特定的数学方法构造出来。
我直接给你看它的真值表(部分),方便你理解数据结构:
| 输入 (十六进制) | 输出 (十六进制) | 备注 |
|---|---|---|
| 0x00 | 0xD6 | 查表:第 0 行第 0 列 |
| 0x10 | 0x5E | 查表:第 1 行第 0 列 |
| 0x55 | 0xBE | 一个中间结果 |
| 0xFF | 0x7A | 最后一个值 |
2.5 密钥扩展:从 128 位主密钥到 32 个轮密钥
这是很多人容易搞混的地方。SM4 的主密钥是 128 位的,但加密过程需要 32 个 32 位的轮密钥。怎么来的?靠密钥扩展算法算出来的。
密钥扩展跟加密过程的结构非常相似,可以说是“加密过程的镜像”。
步骤是这样的:
- 把 128 位主密钥 MK 拆成 4 个 32 位字:MK0, MK1, MK2, MK3。
- 跟 4 个系统参数 FK 异或,得到初始状态 K0, K1, K2, K3。
- FK0 = 0xA3B1BAC6
- FK1 = 0x56AA3350
- FK2 = 0x677D9197
- FK3 = 0xB27022DC
- 然后迭代 32 轮,生成轮密钥 rk0 ~ rk31。每一轮的公式是:
K_{i+4} = K_i ⊕ T'(K_{i+1} ⊕ K_{i+2} ⊕ K_{i+3} ⊕ CK_i)
这里的 T' 变换,跟加密用的 T 变换基本一样。唯一的区别是,T' 中的线性变换 L 不一样。加密时用的 L,而密钥扩展用的是 L':
L'(B) = B ⊕ (B <<< 13) ⊕ (B <<< 23)
看到了吗?就是移位参数不同。加密用 2, 10, 18, 24;密钥扩展用 13, 23。我刚开始看的时候,心里也犯嘀咕:为什么要设计两套参数?后来一想,这是为了安全。你想想看,如果加密和密钥扩展的结构完全一样,就可能会产生一种叫“相关密钥攻击”的漏洞。现在这样错开,就安全多了。
CK_i 是一组 32 个固定的常数,由算法定义。它们是按某种特定规律生成的,你直接用一个数组存起来就行。
2.6 总结一下这一块的核心
看完上面的内容,你可能觉得有点多。别急,我用一张对照表帮你收个尾:
| 核心组件 | 输入 | 输出 | 作用 |
|---|---|---|---|
| S 盒 (τ) | 8 位 | 8 位 | 提供非线性,抵抗攻击 |
| L 变换 (加密) | 32 位 | 32 位 | 提供扩散,产生雪崩效应 |
| L' 变换 (密钥扩展) | 32 位 | 32 位 | 保证轮密钥之间没有相关性 |
| 轮函数 F | 4×32bit + 1×32bit | 32 位 | 完成一轮核心混合操作 |
嗯,现在再看“SM4 算法原理”,是不是感觉清晰了很多?
说白了,它就是围绕着一个精心设计的 S 盒,加上两组不同的线性变换,反复迭代 32 次。把这个框架刻在脑子里,后面写代码就不会跑偏了。