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. 加密流程

整个加密过程可以拆成三步:

  1. 初始变换:将128位明文分成4个32位字 (X0, X1, X2, X3),与密钥无关,直接进入第一轮。
  2. 32轮迭代:每轮用当前最左边的字和轮密钥计算,结果异或到右边字上,然后整体左循环。
  3. 反序变换:把最后四轮输出的顺序反转,作为密文输出。

我当初画流程图时特意标出了Feistel结构的左右交换。下面这张SVG图可以直接展示整体流程:

SM4加密算法总体流程 128位明文 分割为4个32位字 (X0,X1,X2,X3) 32轮迭代 每轮:轮函数F + 32位轮密钥 Feistel结构左右交换 S盒 + 线性变换L 反序变换 128位密文 ⚠️ 注意 轮密钥由密钥扩展 算法生成,共32个 每个32位

3. 密钥扩展算法

给一个128位的初始密钥,怎么算出32个轮密钥?SM4的密钥扩展分两步走:

  1. 初始化系统参数:利用固定常数FK和CK。FK是4个32位系统参数,CK是32个固定32位常数。
  2. 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难。希望这部分总结能帮你在项目中快速上手。