2. SM4算法数学基础:有限域、S盒与变换

聊SM4之前,得先把它的数学底子摸清楚。说实话,很多人学对称密码上来就背S盒、记轮函数,结果遇到密钥派生或者侧信道防护时一头雾水。我个人习惯是先把有限域、S盒构造、线性变换这三块啃透,后面看SM4的密钥编排和加解密流程就跟看流水线一样清楚。

2.1 有限域GF(2⁸)——SM4的“数字地基”

SM4所有操作都在GF(2⁸)上完成。什么叫GF(2⁸)?说白了就是一个只有256个元素的集合,每个元素可以用一个字节(8比特)表示。加法和乘法都在这个集合里封闭,不会跑出去。

加法:就是按位异或(XOR)。比如0x57 + 0x83 = 0xD4。你想想看,在GF(2⁸)里加法和减法是一回事,因为异或的逆操作还是异或。我在做密钥校验的时候经常利用这个性质——两次异或同一个数就能还原数据,调试起来特别方便。

乘法:稍微复杂点。它基于一个不可约多项式,SM4用的是x⁸ + x⁴ + x³ + x + 1(对应二进制1 0001 1011)。两个字节相乘,先做多项式乘法,再对这个不可约多项式取模。结果还是一个字节。

为什么非要用不可约多项式?

保证每个非零元素都有乘法逆元。没有逆元就没法做除法,S盒的仿射变换也就无从谈起。SM4选这个多项式,跟AES的0x11B只差一位,但SM4的S盒构造路径完全不同。

我的小技巧:实际工程里很少手算GF乘法。查表法最快——预计算256×256的乘法表,或者用对数/反对数表。我在嵌入式芯片上做过优化,用256字节的log表和alog表,乘法变成三次查表加一次加法,速度提升明显。

2.2 S盒构造原理——从代数到查表

SM4的S盒是8×8的,输入8比特,输出8比特。它由两步构成:

  1. 求乘法逆元:在GF(2⁸)里,把输入字节(0x00映射为自身)换成它的乘法逆元。
  2. 仿射变换:对逆元结果做一个仿射变换(矩阵乘法加常数)。

仿射变换的公式长这样:

b_i = a_i ⊕ a_{(i+2) mod 8} ⊕ a_{(i+5) mod 8} ⊕ a_{(i+7) mod 8} ⊕ c_i
其中 c = 0xD5 (二进制 1101 0101)

嗯,这里要注意:SM4的仿射常数是0xD5,而AES用的是0x63。别看就差这么点,整个S盒的代数性质全变了。我记得有一次做差分分析,把SM4的S盒跟AES的S盒对比,发现SM4的差分均匀度略高一点,但线性逼近的偏差更小——这是设计者有意做的权衡。

最终S盒的256个值可以直接查表。下面是SM4 S盒的前16个值(输入0x00~0x0F):

输入0x000x010x020x030x040x050x060x07 0x080x090x0A0x0B0x0C0x0D0x0E0x0F
输出 0xD60x900xE90xFE0xCC0xE10x3D0xB7 0x160xB60x140xC20x280xFB0x2C0x05

避坑指南:我曾经在移植SM4到DSP平台时,直接复制了AES的S盒代码,只改了常数。结果加解密结果全错。后来排查发现,SM4的仿射变换矩阵顺序跟AES不一样——SM4用的是行主序,AES是列主序。所以千万别偷懒,S盒必须按SM4标准重新生成。

2.3 线性变换与非线性变换——轮函数的“双引擎”

SM4的轮函数由非线性变换τ和线性变换L组成。τ就是S盒的并行应用,L是32比特的循环移位异或。

非线性变换τ:把32比特分成4个字节,每个字节过S盒。说白了就是4个S盒并行查表。这个操作提供了密码算法最核心的“混淆”能力——输入改变1比特,输出平均改变4比特。

线性变换L:对τ的输出做32比特的循环移位异或。SM4的加密轮函数用L,密钥编排用L'(略有不同)。

加密轮函数的L:

L(B) = B ⊕ (B <<< 2) ⊕ (B <<< 10) ⊕ (B <<< 18) ⊕ (B <<< 24)

密钥编排的L':

L'(B) = B ⊕ (B <<< 13) ⊕ (B <<< 23)

你想想看,为什么加密用5个移位项,密钥只用3个?因为密钥编排需要更快的扩散,但不需要跟加密轮一样的强度。我在做白盒SM4实现时,发现L的移位参数直接决定了查找表的大小——移位越多,表越大,但安全性也越高。

扩散效果对比:

  • τ(S盒):1比特输入变化 → 约4比特输出变化(非线性)
  • L(线性):1比特变化 → 经过一轮后影响约16比特(线性扩散)
  • τ+L组合:一轮下来,32比特中约20比特会受影响

这就是为什么SM4只需要32轮就能达到充分扩散——比DES的16轮多一倍,但比AES的10轮(128位)效率更高。

2.4 知识体系总览

下面这张图把本章的核心逻辑串起来了。从最底层的有限域,到S盒构造,再到轮函数里的τ和L,最后到密钥编排——每一步都环环相扣。

SM4数学基础知识体系 有限域 GF(2⁸) S盒构造 非线性变换 τ 线性变换 L / L' 轮函数 F 密钥编排算法 GF(2⁸) 为 S盒提供逆元运算 → S盒构成 τ → τ 与 L 组合成轮函数 F → F 驱动密钥编排

这张图我建议你存下来。每次做SM4相关开发时扫一眼,就能快速定位问题出在哪一层——是S盒查表错了,还是L的移位参数配错了。我在做密钥分散算法时,就靠这张图排查出一个L'用成L的bug,省了大半天调试时间。