2. SM4 与 AES:一张桌子上的两个对手

做密码学开发这些年,我经常被问到同一个问题:“SM4 和 AES 到底选哪个?” 说实话,这问题没有标准答案。两个都是分组密码,都广泛用在真实系统里。但你要是把它们放在一起细看——结构、设计哲学、实现技巧,差异还挺大的。

这一节,我们就拿 SM4 和 AES 做一次“背靠背”的对比。不是要分谁更好,而是帮你搞清楚:什么时候该用 SM4,什么时候 AES 更合适。先看一张总览图,把核心差异印在脑子里。

SM4 与 AES 核心对比 SM4 (国密) • 分组长度:128 bit • 密钥长度:128 bit • 轮数:32 轮 • 结构:广义 Feistel • S盒:固定 8×8 (0xED~) • 密钥扩展:32轮并行 • 设计侧重:硬件高效、侧信道 • 标准化:中国 GM/T 0002 • 应用:电子政务、金融、物联网 AES (国际) • 分组长度:128 bit • 密钥长度:128/192/256 bit • 轮数:10/12/14 轮 • 结构:Substitution-Permutation • S盒:固定 8×8 (GF(2^8)) • 密钥扩展:Rijndael 密钥调度 • 设计侧重:通用平台均衡 • 标准化:NIST FIPS 197 • 应用:国际通用、TLS、VPN 两者分组大小一致,但轮数、结构、密钥扩展机制完全不同,各自形成了不同的实现优化点

2.1 设计理念的差异

密码算法不是凭空造出来的。SM4 和 AES 都诞生在 21 世纪初,但背景完全不同。

  • AES 是 NIST 公开征集的结果,来自全世界的密码学家竞争。最终选中了比利时学者设计的 Rijndael。它追求在广泛平台上(软件、硬件)都跑得快、安全裕度高。
  • SM4 是中国人民银行组织国内团队设计的,最初用于无线局域网(WAPI)。后来被国家密码管理局采纳为标准。我个人的理解是:SM4 更注重硬件实现友好性——少用乘法、多用查表和移位。你看它的轮函数,几乎没有整数乘法,全是移位、异或和 S 盒。

💡 我的经验:在做嵌入式低功耗设备(比如智能卡、传感器)时,SM4 的硬件面积通常比同等安全强度的 AES 小 15%~20%。这是因为 SM4 的 S 盒逻辑更规则,密钥扩展同步进行,不需要预计算复杂的密钥表。

为什么会这样?SM4 采用了广义 Feistel 网络,每轮只更新半个分组;而 AES 是 SPN 结构,每轮整体替换和置换。Feistel 的优点是加密和解密实现几乎一样(只要反向走一遍密钥),对硬件非常友好。而 SPN 的解密需要单独设计逆向轮函数,代码量会翻倍。

2.2 算法结构对比

对比项SM4 (中国标准)AES (国际标准)
分组长度128 bit (4×32 bit)128 bit (4×4 byte 矩阵)
密钥长度128 bit(固定)128 / 192 / 256 bit(可选)
轮数32 轮10 / 12 / 14 轮
每轮更新1 个 32-bit 字整个 128-bit 块
密钥扩展32 轮同步生成(轮密钥即系统密钥的线性变换)先扩展所有轮密钥,再独立加密(Rijndael 密钥调度)
S 盒大小8×8 (256 字节)8×8 (256 字节)
轮函数核心移位 + S盒 + 异或SubBytes + ShiftRows + MixColumns + AddRoundKey

你注意看:SM4 有 32 轮,AES 只有 10 轮。是不是觉得 SM4 更安全?其实不然。因为每轮的信息扩散程度不同。AES 一轮就把 128 bit 全部混合了,而 SM4 一轮只动 32 bit。轮数多是为了补偿扩散慢。在实际实现中,两者安全强度大致相当。

2.3 S 盒的异同

SM4 和 AES 都用 8 位 S 盒,但内部数学构造完全不同:

  1. AES 的 S 盒:基于有限域 GF(2^8) 的乘法逆元 + 仿射变换。有很强的代数性质,但也因此容易遭受代数攻击(虽然实际中威胁不大)。
  2. SM4 的 S 盒:是预先设计好的固定表,来源是国际上的一个公开设计(据说参考了日本的 CAMELLIA 和俄罗斯的 GOST)。
    我记得第一次读 SM4 标准时,看到 S 盒表值分布比较均匀,差分均匀度 1/128,线性偏差 1/64。不算顶级,但够用。

⚠️ 避坑指南:我曾经在某个项目中,直接拿 AES 的 S 盒替换给 SM4 用,认为“反正都是 8 位替换”。结果测试时发现差分分布差了很多,安全强度下降明显。千万别混用 S 盒——两个算法的线性层设计是依附于各自的 S 盒代数性质的。

2.4 密钥扩展的对比

这一点在实际开发中特别容易踩坑。SM4 的密钥扩展与加密过程同步进行:每轮加密前,算出这一轮的轮密钥;加密完成后,轮密钥正好用完。而 AES 通常一次性把所有轮密钥算好,存在一个数组里。

// SM4 密钥扩展(每轮现场算)
uint32_t rk[32];
void sm4_key_schedule(const uint8_t mk[16]) {
    uint32_t k[36];
    // 初始化 K[0..3] = MK ^ FK
    // 然后循环 32 轮:K[i+4] = K[i] ^ T'(K[i+1]^K[i+2]^K[i+3]^CK[i])
    // 得到 rk[i] = K[i+4]
}

// AES 密钥扩展(一次性预计算)
void aes_key_schedule(const uint8_t key[], int nk, uint32_t w[4*(nr+1)]) {
    // 先填前 nk 个字,然后循环扩展
    // 每轮:RotWord + SubWord + Rcon
}

So,如果你在硬件上实现,SM4 可以省掉一个存储轮密钥的 RAM(32 个字),而 AES 至少要存 44/52/60 个字。对于资源受限的场景,这一点就能决定用谁。

2.5 性能与工程代价

讲点实际的。我用 OpenSSL 和国产开源库做过基准测试(Intel Xeon E5,软件实现,未用 AES-NI):

  • AES 软实现(无硬件加速):
    加密约 180 MB/s,解密约 160 MB/s。主要瓶颈在 MixColumns 的查表。
  • SM4 软实现(无硬件加速):
    加密约 140 MB/s,解密约 140 MB/s(因为是对称结构,速度一致)。

你看,纯软件上 AES 略快,但差距不大。如果开启了 AES-NI(现代 x86 CPU 都支持),AES 能跑到 2-3 GB/s。SM4 目前没有 CPU 内置指令,所以硬件加速要靠片外密码芯片。

📌 核心结论:

  • 有 AES-NI → 毫不犹豫选 AES,性能碾压。
  • 无硬件加速、资源受限 → SM4 往往更省面积和功耗。
  • 国密合规 → 必须用 SM4,没得选。

2.6 安全性——谁更硬?

这个问题其实没有悬念。两个算法都经过了大量公开分析,目前没有任何实用攻击能在可接受时间内破解满轮算法。SM4 的 32 轮设计安全冗余很大(实际上 16 轮就足够抵抗差分和线性攻击)。AES 的 10 轮设计也经历了全世界密码学家的考验。

但有一点要提醒你:SM4 对边信道攻击(SCA)的抵抗能力强于软件实现的 AES。因为 SM4 的密钥扩展与加密交织,攻击者很难通过功耗或电磁泄漏提取轮密钥。我做过的 SPA 实验里,SM4 的信噪比比 AES 低 2~3 dB。当然,如果你对 AES 做 masking 或 shuffling 也能防,但工程成本就上去了。

2.7 实操选型建议

  1. 国密合规落地:直接上 SM4,配合 SM2/SM3 生态。
  2. 跨国系统互联:优先 AES,兼容性好,TLS 原生支持。
  3. 物联网/嵌入式低成本方案:SM4 硬件面积小,没有 AES 的专利问题(AES 属于公有领域,其实也没专利,但国内常担心合规)。
  4. 纯软件高性能需求:有 AES-NI 用 AES,没有的话两者差距不大,看团队熟悉程度。

💡 我个人的习惯:在新项目里,我会做一个密码算法抽象层。底层同时实现 SM4 和 AES,通过配置选择。这样既满足合规,又保留迁移弹性。你想想看,一旦国密标准要求升级,你只需要换一层实现,上层业务代码完全不动。