1. SM4 算法基础
1.1 算法背景
SM4 这个名字,做国产化的同行应该不陌生。它是中国国家密码管理局在 2006 年公布的无线局域网安全标准,后来在 2012 年正式成为国密标准(GM/T 0002-2012),2016 年又成了 ISO/IEC 国际标准。说白了,这是咱们自己的分组密码算法,和 AES 是一个量级的东西。
我记得 2019 年做一个政务云项目,客户红头文件明确要求"必须使用国密算法"。那时候硬件加速还不普及,纯软件实现 SM4 跑得吭哧吭哧的。也就是从那个项目起,我开始认真抠 SM4 的性能细节——吞吐量为什么上不去?瓶颈到底在哪儿?这些经验后来全用在了这门课里。
SM4 的应用场景比你想象的广:
- VPN 网关和 IPSec 中的国密改造
- 金融 IC 卡与移动支付终端
- 物联网模组与轻量级加密通信
- 数据库透明加密(TDE)
1.2 基本原理
SM4 是分组密码,分组长度 128 位,密钥长度也是 128 位。它用了 32 轮迭代结构,每一轮的处理方式相同,但轮密钥不同。你想想看,32 轮是不是有点多?我第一次看规范也这么想。后来做差分分析时才明白,这 32 轮不是白给的,少了安全性扛不住。
先看整体架构,我画了一张图帮大家理清数据流和密钥流的关系:
从上图你能看到,SM4 的核心链路很清晰:明文进来,经过 32 轮迭代,再做一次反序变换,输出密文。密钥那边独立扩展出 32 个轮密钥,每轮喂一个。解密时把轮密钥倒过来用就行,其他一模一样。
轮函数 F 详解
轮函数 F 是 SM4 的"心脏"。它的输入是三个 32 位字 (X₁, X₂, X₃) 和一个轮密钥 rk,输出一个 32 位字。公式长这样:
F(X₁, X₂, X₃, rk) = L( S( X₁ ⊕ X₂ ⊕ X₃ ⊕ rk ) )
分三步走:
- 异或加扰: 把三个字和轮密钥异或在一起,得到一个 32 位中间值。
- S盒替换: 把 32 位拆成 4 个字节,每个字节过一遍 8×8 的 S 盒。SM4 的 S 盒设计得挺讲究,非线性度和差分均匀性都很好。我在项目中试过用查表法还是 SIMD 指令算 S 盒——查表简单,但容易触发缓存抖动;SIMD 快,但代码量翻倍。
- 线性变换 L: 对 S 盒输出的 32 位字做循环移位和异或:
L(B) = B ⊕ (B <<< 2) ⊕ (B <<< 10) ⊕ (B <<< 18) ⊕ (B <<< 24)
这个 L 变换说白了就是让一个比特的变化能快速扩散到整个字。你想想看,如果只靠 S 盒,扩散速度太慢,32 轮都不够用。
密钥扩展
密钥扩展和加密共用一套轮函数结构,但线性变换换成了 L':
L'(B) = B ⊕ (B <<< 13) ⊕ (B <<< 23)
为什么用不同的 L'?因为加密和密钥扩展的安全需求不一样。密钥扩展需要更强的"雪崩效应",主密钥差一比特,所有轮密钥都得面目全非。我在做测试向量验证时,用全 0 密钥和全 1 密钥对比,确认扩展后的轮密钥确实没有统计相关性——这一步是 FIPS 验证的必选项,千万别跳。
| 组件 | 输入 | 输出 | 备注 |
|---|---|---|---|
| S 盒 | 8 位 | 8 位 | 唯一非线性组件,查表或 SIMD |
| 线性变换 L(加密) | 32 位 | 32 位 | 循环移位 + 异或,扩散用 |
| 线性变换 L'(密钥扩展) | 32 位 | 32 位 | 与 L 不同,用于密钥派生 |
| 轮函数 F | 3×32 位 + 32 位密钥 | 32 位 | S 盒 + L 变换组合 |
1.3 工作模式
SM4 本身只定义了单块加密,实际使用时需要搭配工作模式。常见的有三种:
- ECB(电子密码本) — 最简单,每个块独立加密。缺点也明显:相同的明文块得出相同的密文块,容易泄露模式。我在等保测评项目中遇到过,客户用 ECB 加密图片,结果轮廓还在,直接被判定不合规。
- CBC(密码分组链接) — 每个块加密前和上一个密文块异或。引入了 IV,安全性好很多。但加密不能并行,解密可以。吞吐量受限于串行链路。
- CTR(计数器) — 用递增计数器生成密钥流,再和明文异或。加密和解密都能完全并行,还能随机访问。我强力推荐高吞吐场景用 CTR。
| 模式 | 并行加密 | 并行解密 | 随机访问 | 典型吞吐量(相对) |
|---|---|---|---|---|
| ECB | ✔ | ✔ | ✔ | 1.0x(基准) |
| CBC | ✘ | ✔ | ✘ | 0.7x ~ 0.9x |
| CTR | ✔ | ✔ | ✔ | 1.1x ~ 1.3x |
嗯,说到这,SM4 的基础结构你应该心里有数了。分组 128 位,32 轮迭代,S 盒加 L 变换的组合拳,再加上合适的工作模式。这些知识是后面排查吞吐量波动的"扳手"——你得先知道引擎怎么转,才能听出哪儿有杂音。
- SM4 分组长度 = 密钥长度 = 128 位,32 轮迭代结构。
- 轮函数 F = L( S( X₁⊕X₂⊕X₃⊕rk ) ),S 盒是非线性的关键。
- 解密与加密结构相同,轮密钥逆序使用。
- CTR 模式在吞吐量和并行性上表现最好,CBC 安全性适中,ECB 慎用。