国密标准与SM4算法概述

说起国密SM4,我得先跟你聊聊这个背景。
国家密码管理局在2006年发布了SM4算法,当时叫SMS4。到了2012年,它正式成为国家标准——GB/T 32907-2016。
说白了,这就是咱们中国自己的分组密码标准。跟AES一个级别,但实现逻辑完全不同。

我个人习惯把SM4叫做“32轮的轻量级选手”。
它为啥重要?在物联网、金融芯片、政府数据系统里,你绕不开它。
嗯,这里要注意:SM4是必选算法,不是备选。

算法参数一览

先看张表,基本参数一目了然:

参数项 SM4数值
分组长度 128 bits(16字节)
密钥长度 128 bits(16字节)
轮数 32轮
结构类型 Feistel 网络
轮函数 非线性τ + 线性变换L
密钥扩展 基于32轮非线性迭代

核心点:SM4是Feistel结构,加密和解密用同一套逻辑。轮密钥顺序反过来就行。这在硬件实现上太友好了。

算法原理——我拆开来讲

SM4加密一次处理128位数据,也就是4个32位的字。
为什么是32位?因为现代CPU的寄存器宽度就是32或64位,对齐了效率高。

加密流程

  1. 输入128位明文,拆成4个32位字:X0, X1, X2, X3
  2. 进行32轮迭代,每轮用1个轮密钥
  3. 第32轮结束后,把最后4个32位字倒序组合,输出128位密文

我做个避坑指南:
我曾经见过有人直接把最后一轮输出当作密文,忘了把X32~X35倒序。结果数据死活解不回来。这个倒序步骤,千万别省。

轮函数F

这是SM4最核心的部分。每轮输入是 (Xi, Xi+1, Xi+2, Xi+3),输出是下一个32位字 Xi+4:

公式大概长这样:

X_{i+4} = X_i ⊕ T(X_{i+1} ⊕ X_{i+2} ⊕ X_{i+3} ⊕ rk_i)

其中T是一个复合变换,分两步走:

  1. 非线性变换τ:把输入的32位拆成4个字节,每个字节过一遍S盒。SM4的S盒是固定的8×8查找表,值跟AES的S盒不一样。
  2. 线性变换L:对τ输出的32位做循环移位异或操作。

一个小经验:S盒查表时,建议用静态const数组预加载,别每次都算。速度差一个数量级。我当年做TF卡加密时,S盒死记硬背写死在代码里,IO性能直接飙上去。

密钥扩展算法

加密密钥是128位,但我们有32轮,需要32个轮密钥。
怎么变出来的?也是Feistel迭代。

过程大概是这样:

  • 将128位密钥拆成4个32位字:MK0, MK1, MK2, MK3
  • 先跟4个固定参数FK做异或,得到初始状态值
  • 然后迭代32轮,每轮生成一个轮密钥rki
  • 生成过程中线性变换L变成了L',这个L'和加密里的L有一字之差

你想想看:为什么密钥扩展和加密共用S盒?
因为这样可以减少电路面积。硬件工程师最喜欢这种设计。软件上也能复用代码。

SM4的核心逻辑结构图

下面这张SVG图,把SM4的整体框架给你捋清楚:

SM4算法核心结构 SM4 算法整体结构 加密/解密主流程 128位明文输入 拆分为 X0,X1,X2,X3 32轮 Feistel 迭代 每轮使用一个轮密钥 rk_i 轮函数 F 异或 → S盒查表(τ) → L变换 输出 X_{i+4} 倒序组合 → 128位密文 密钥扩展流程 128位加密密钥 MK 异或 FK0,FK1,FK2,FK3 32轮密钥迭代 每轮输出 rk_i(32位) 密钥生成函数 异或 → S盒查表(τ) → L'变换 重复32次 输出 32 个轮密钥 关键连接: 轮密钥供应

从图中可以清楚看到:左侧加密流程和右侧密钥扩展各走各的迭代,但共享同一个S盒和相似的τ函数。密钥扩展生成的32个rki,顺序喂给加密流程的每一轮。解密时只要把这些轮密钥倒过来用就行。

加密与解密的关系

前文提到了,SM4的解密和加密完全一样。
唯一的区别:解密时轮密钥顺序反过来。

  • 加密用:rk0, rk1, rk2, ..., rk31
  • 解密用:rk31, rk30, ..., rk0

这个特性让我在项目中省了不少事。做过硬件加速的同学都知道,加解密共用一套逻辑,面积直接省一半。

注意:SM4不是对称算法里唯一这么做的,但能同时满足安全和轻量级的并不多。不要因为它实现简单就轻视它。32轮迭代的安全强度,在目前计算能力下是完全够用的。

算法对比——为什么选SM4

对比项 SM4 AES-128
分组长度 128 bit 128 bit
密钥长度 128 bit 128 bit
轮数 32轮 10轮
结构 Feistel SPN
安全性 国密认证等级 国际主流标准
合规场景 国内金融/政务必选 国际通用

说白了,如果你的产品要过国密局的合规检测,别想别的,上SM4。
AES再强,在国密合规场景里不认账。我遇到过客户非要两个都支持,结果硬件面积和代码复杂度都翻倍。除非你有海外市场,否则一把梭SM4就够了。

我的一点实践感受

最后聊点经验。
SM4代码实现其实不难,就几百行C代码。但你真的用起来,有几个点容易掉坑里:

  • 字节序问题:大部分嵌入式平台是小端,SM4标准按大端定义。转换时一个不小心,加解密结果就对不上。
  • 轮密钥缓释:别每加密一块都重新算轮密钥。把rk[32]存起来,性能提升肉眼可见。
  • 填充模式:SM4本身是分组密码,消息长度不一定是16的倍数。PKCS7填充是最常见的,但你得确认你的SDK支持哪种填充方式。

记住SM4是基础,但却是一切合规的起点。后面章节我们会扎到集成细节里去,把轮函数、S盒、密钥扩展一行一行敲出来。本章先把脑图搭好,后面才好操作。