SM4分组密码算法原理归纳总结
各位,今天我们聊SM4。这是国密标准里最基础的一块基石。说白了,它就是一个128位密钥、128位分组、32轮迭代的分组密码。你想想看,这个参数跟AES-128很像,但轮数比AES多了一倍。为什么?因为SM4的设计更加保守,用更多轮数来保证安全性。
我记得刚开始接触SM4时,第一个坑是端序。SM4标准里明文和密钥都是大端序,但很多嵌入式平台默认小端。我曾在ARM上直接算了半天,结果加密结果死活对不上标准向量。嗯,从那以后我养成了一个习惯:写SM4前先查一次端序转换。
1. 算法概览
我把SM4的核心参数归纳在一张表里,方便你对照:
| 参数项 | 值 | 说明 |
|---|---|---|
| 分组长度 | 128 bit | 每次加密/解密一个16字节块 |
| 密钥长度 | 128 bit | 输入密钥直接用于扩展 |
| 轮数 | 32 | 每轮使用一个32位轮密钥 |
| 轮函数结构 | Feistel网络 | 每轮仅改变左半部分32位 |
| S盒 | 8×8非线性替换 | 与AES不同,SM4只有一个S盒 |
| 操作模式 | ECB/CBC/CTR等 | 由上层协议决定,算法本身只定义ECB底层 |
经验小贴士:SM4的Feistel结构意味着加密和解密可以用同一套硬件,只是密钥使用顺序相反。这个特性在做嵌入式IP核时特别省资源。
2. 加密流程
整个加密过程可以拆成三步:
- 初始变换:将128位明文分成4个32位字
(X0, X1, X2, X3),与密钥无关,直接进入第一轮。 - 32轮迭代:每轮用当前最左边的字和轮密钥计算,结果异或到右边字上,然后整体左循环。
- 反序变换:把最后四轮输出的顺序反转,作为密文输出。
我当初画流程图时特意标出了Feistel结构的左右交换。下面这张SVG图可以直接展示整体流程:
3. 密钥扩展算法
给一个128位的初始密钥,怎么算出32个轮密钥?SM4的密钥扩展分两步走:
- 初始化系统参数:利用固定常数FK和CK。FK是4个32位系统参数,CK是32个固定32位常数。
- 32轮循环生成:
// 伪代码展示密钥扩展核心
MK = (MK0, MK1, MK2, MK3) // 初始密钥,每个32位
K = (K0, K1, K2, K3) = MK xor FK
for i in range(32):
temp = K[i+1] xor K[i+2] xor K[i+3] xor CK[i]
rk[i] = K[i] xor Sbox(temp)
K.append(rk[i]) // 更新滑动窗口
核心要点:密钥扩展中的S盒与加密轮函数中的S盒完全相同,都是同一个8×8替换表。这意味着你可以复用S盒电路,节省面积。
4. 轮函数F(加密核心)
每一轮输入是四个32位字 (X[i], X[i+1], X[i+2], X[i+3]),输出新的 X[i+4]。计算公式为:
X[i+4] = X[i] xor T( X[i+1] xor X[i+2] xor X[i+3] xor rk[i] )
其中T变换由两步组成:
- S盒非线性变换:对32位数据拆成4个字节,每个字节查同一个S盒表。
- 线性变换L:将S盒输出的32位做循环左移和异或。公式为
L(B) = B xor (B <<< 2) xor (B <<< 10) xor (B <<< 18) xor (B <<< 24)。
我个人习惯把L变换看作一个轻量级MDS矩阵,虽然没有AES的MixColumns那么复杂,但扩散效果足够好。我在一次硬件实现中,发现L变换可以用一个五输入的异或树在一拍内完成,完全不需要流水线。
5. S盒详解
SM4的S盒是一个8位输入8位输出的替换表,总共有256个条目。与AES的S盒不同,SM4的S盒不是基于有限域逆运算,而是由仿射变换和查表直接定义的。你可以把S盒当成一个只读ROM,输入地址,输出数据。
下面列出前16个码值做样例:
| 输入(hex) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 输出(hex) | D6 | 90 | E9 | FE | CC | E1 | 3D | B7 | 16 | B6 | 14 | C2 | 28 | FB | 2C | 05 |
常见误区:我曾经以为SM4的S盒可以随便用软件算出来,但实际标准里直接给了查表值。如果你自己去算仿射变换,很可能因为乘法逆元不同而算出错误结果。直接用标准表是最可靠的。
6. 解密过程
解密和加密的结构完全对称。你只需要把32个轮密钥的使用顺序反转:加密时按rk[0]到rk[31]顺序使用,解密时按rk[31]到rk[0]逆序使用。同一个Feistel网络,同一个轮函数F,输入密文,输出明文。
我记得第一次实现解密时,我直接复制了加密代码,只把while i<32改成了while i>=0,结果验算完美通过。这就是Feistel结构的好处——加解密硬件可以共用。
7. 安全性分析
SM4经历了多年密码分析考验,目前没有发现实际可行的攻击。一些关键安全指标:
- 差分分析:32轮迭代的活跃S盒足够多,差分路径概率极低。
- 线性分析:线性逼近的偏差被压制到安全阈值以下。
- 密钥相关攻击:密钥扩展中的非线性S盒和CK常数有效地消除了滑动性质。
实战建议:如果你在国密合规项目中使用SM4,推荐采用CBC或CTR模式,并搭配消息认证码(如SM3-HMAC)。仅仅使用ECB模式记录日志可能会暴露重复模式,我曾在一个安全审计中遇到过这样的问题。
总而言之,SM4是一个设计保守、实现简洁、安全性经过充分验证的分组密码。只要注意端序和S盒的正确查表,实现起来并不比AES难。希望这部分总结能帮你在项目中快速上手。