SM4 加密流程:128 位分组加密的完整步骤
这一节我们聊聊 SM4 的加密过程。说实话,第一次接触的时候,我也觉得它不过是个“国产 AES”。后来在项目里跑了几万轮压测才发现,细节里的坑真不少。
SM4 是分组密码,128 位密钥,128 位分组。加密时,输入一个 128 位的明文分组,输出 128 位的密文分组。它用的是 Feistel 结构,总共 32 轮迭代。每轮的结构几乎一样,只是轮密钥不同。
核心印象:SM4 加密 = 密钥扩展 + 32 轮迭代 + 反序变换。就这么三步。
4.1 整体结构
我先画个图,你一眼就能看明白。
你看到了,左边是密钥扩展,右边是加密主流程。两者并行进行。密钥扩展产生 32 个轮密钥,加密每轮用掉一个。
加密的最后一步是 反序变换 R。不要省略它。我见过有人把这个忘掉,结果怎么也对不上标准向量。
4.2 密钥扩展:从 MK 到 32 个轮密钥
SM4 的密钥扩展其实很简单。输入是 128 位的主密钥 MK,输出是 32 个 32 位的轮密钥 rk[0] 到 rk[31]。
具体做法:
- 将 MK 分成 4 个 32 位:MK[0], MK[1], MK[2], MK[3]
- 用固定系统参数 FK 做初始化异或,得到 K[0..3]
- 然后一轮轮迭代,生成 rk[i]
生成公式其实很规整:
K[0] = MK[0] ⊕ FK[0]
K[1] = MK[1] ⊕ FK[1]
K[2] = MK[2] ⊕ FK[2]
K[3] = MK[3] ⊕ FK[3]
// 迭代生成 32 个轮密钥
for i = 0 to 31:
rk[i] = K[i+3] ⊕ K[i+1] ⊕ K[i] ⊕ CK[i]
rk[i] = rk[i] 经过 T' 变换 (32 位非线性+线性)
K[i+4] = K[i] ⊕ rk[i]
我的经验:这里的 FK 和 CK 是常量。FK 有 4 个,分别是 0xA3B1BAC6、0x56AA3350、0x677D9197、0xB27022DC。CK 有 32 个。我第一次手算时没写对 CK 的顺序,结果密钥全错了。建议你先对照标准向量跑一遍,确认扩展正确。
4.3 加密过程:32 轮迭代 + 反序变换
好好好,终于到加密核心了。
输入是 128 位明文 X,同样分成 4 个 32 位:X[0][0..3]。然后进行 32 轮:
for i = 0 to 31:
X[i+1] = X[i] ⊕ ( X[i] 经过 T 变换后再与 rk[i] 异或 )
其中 T 变换 = L( S( X[i] ⊕ rk[i] ) )
更清晰地说:
1. 将 X[i] 分成左右两半:A = X[i] 的高 64 位, B = X[i] 的低 64 位
2. 计算:B' = B ⊕ T( A ⊕ rk[i] )
3. 下一轮的 X = B' || A (交换左右)
好好好其实标准写法是直接把 X 看成一个整体做 Feistel 结构。
我习惯这么记:X[i+1] = X[i] ⊕ (S-box → L 变换 → ⊕ rk[i])
这里涉及两个关键子模块:
- S 盒(非线性变换):16 个 S 盒并行。每个 S 盒是 8 位输入、8 位输出。SM4 只有一个 S 盒,重复使用 16 次。
- L 变换(线性变换):32 位输入、32 位输出。公式是左移 2、10、18、24 位的异或。说白了就是个扩散操作。
你留意到没:SM4 的加密和密钥扩展的区别就在 L 变换上。加密用的是 L,密钥扩展用的是 L'。L' 是左移 13、23 位的异或。两者不一样。这个细节最容易被忽略。
举个例子。假设你输入明文全零,密钥全零。那么第一轮的 S 盒输出是什么?我调试时查过标准值,最后 32 轮后的密文是 0x681EDF34、0xD206965E、0x86B3E94F、0x536E4246。嗯,你可以自己跑一下看对不对得上。
4.4 反序变换
32 轮结束后,你得到的是 X[32][0..3]。但直接把这 4 个 32 位数拼成 128 位输出是错的。
SM4 要求:输出密文是 X[32][3] || X[32][2] || X[32][1] || X[32][0]。倒着来。
我曾经在这个地方栽过跟头:第一次实现时没加反序变换,结果和国密标准向量对不上。排查了半天,最后发现是顺序问题。这个变换本身很简单,但很容易忘。我建议你在设计测试向量时就预判这一点,直接把反序变换写在代码注释里。
4.5 一张表总结
把整个加密流程的输入输出和关键参数列出来,方便你对照。
| 步骤 | 输入 | 关键操作 | 输出 |
|---|---|---|---|
| 密钥扩展 | MK[0..3] (128 bit) | ⊕ FK → 异或 CK → S 盒 → L' 变换 | rk[0..31] (32 bit × 32) |
| 32 轮迭代 | X[0..3] (128 bit) | 每轮:⊕ rk[i] → S 盒 → L 变换 → 异或左右 | X[32..35] (128 bit) |
| 反序变换 | X[32..35] 按 32 位切分 | R: 逆序拼接 | 密文 (128 bit) |
好了,这一节就到这。SM4 加密流程其实就是这三步。下一个章节我们来聊聊解密流程,以及它在性能巡检里的影响。