1. SM4 算法基础

1.1 算法背景

SM4 这个名字,做国产化的同行应该不陌生。它是中国国家密码管理局在 2006 年公布的无线局域网安全标准,后来在 2012 年正式成为国密标准(GM/T 0002-2012),2016 年又成了 ISO/IEC 国际标准。说白了,这是咱们自己的分组密码算法,和 AES 是一个量级的东西。

我记得 2019 年做一个政务云项目,客户红头文件明确要求"必须使用国密算法"。那时候硬件加速还不普及,纯软件实现 SM4 跑得吭哧吭哧的。也就是从那个项目起,我开始认真抠 SM4 的性能细节——吞吐量为什么上不去?瓶颈到底在哪儿?这些经验后来全用在了这门课里。

SM4 的应用场景比你想象的广:

  • VPN 网关和 IPSec 中的国密改造
  • 金融 IC 卡与移动支付终端
  • 物联网模组与轻量级加密通信
  • 数据库透明加密(TDE)
一个小观察: 我接触过的国产化项目中,80% 的性能问题都出在实现层,不是算法本身。了解 SM4 的底层结构,对后续排查吞吐量波动至关重要。

1.2 基本原理

SM4 是分组密码,分组长度 128 位,密钥长度也是 128 位。它用了 32 轮迭代结构,每一轮的处理方式相同,但轮密钥不同。你想想看,32 轮是不是有点多?我第一次看规范也这么想。后来做差分分析时才明白,这 32 轮不是白给的,少了安全性扛不住。

先看整体架构,我画了一张图帮大家理清数据流和密钥流的关系:

SM4 加密整体架构 128位明文 32轮迭代结构(第1轮 ~ 第32轮) 轮函数 F S盒替换 → 线性变换 L → 与轮密钥异或 ← 重复32次 (X32, X33, X34, X35) 反序变换 R 128位密文 128位主密钥 密钥扩展 生成32个轮密钥 轮密钥 (rk₀~rk₃₁) 每轮一个 数据节点 处理模块 密钥相关 数据流 密钥流

从上图你能看到,SM4 的核心链路很清晰:明文进来,经过 32 轮迭代,再做一次反序变换,输出密文。密钥那边独立扩展出 32 个轮密钥,每轮喂一个。解密时把轮密钥倒过来用就行,其他一模一样。

轮函数 F 详解

轮函数 F 是 SM4 的"心脏"。它的输入是三个 32 位字 (X₁, X₂, X₃) 和一个轮密钥 rk,输出一个 32 位字。公式长这样:

F(X₁, X₂, X₃, rk) = L( S( X₁ ⊕ X₂ ⊕ X₃ ⊕ rk ) )

分三步走:

  1. 异或加扰: 把三个字和轮密钥异或在一起,得到一个 32 位中间值。
  2. S盒替换: 把 32 位拆成 4 个字节,每个字节过一遍 8×8 的 S 盒。SM4 的 S 盒设计得挺讲究,非线性度和差分均匀性都很好。我在项目中试过用查表法还是 SIMD 指令算 S 盒——查表简单,但容易触发缓存抖动;SIMD 快,但代码量翻倍。
  3. 线性变换 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
踩过的一个坑: 我曾经在 ARM 平台上用 CTR 模式,以为并行加密肯定快。结果没注意计数器回绕——32 位计数器溢出后密文全乱套。CTR 一定要用 128 位全计数器或 96 位 nonce + 32 位计数器,别偷懒。

嗯,说到这,SM4 的基础结构你应该心里有数了。分组 128 位,32 轮迭代,S 盒加 L 变换的组合拳,再加上合适的工作模式。这些知识是后面排查吞吐量波动的"扳手"——你得先知道引擎怎么转,才能听出哪儿有杂音。

核心要点回顾:
  • SM4 分组长度 = 密钥长度 = 128 位,32 轮迭代结构。
  • 轮函数 F = L( S( X₁⊕X₂⊕X₃⊕rk ) ),S 盒是非线性的关键。
  • 解密与加密结构相同,轮密钥逆序使用。
  • CTR 模式在吞吐量和并行性上表现最好,CBC 安全性适中,ECB 慎用。