第一章:SM3算法概述

咱们做嵌入式或安全协议开发的,迟早会跟SM3打交道。说白了,它就是国家密码管理局发布的密码杂凑算法标准,2010年就公布了。你可能听过SHA-256,SM3跟它有点像,但咱们自家有自家的规矩。

我最早接触SM3是在一次国密改造项目上。客户说「必须用SM3做完整性校验」,我当时还嘀咕:这不就是个哈希嘛,换一个库不就行了?结果真踩了不少坑——有的库实现不标准,有的平台跑起来性能差得离谱。所以这一章先打好基础,后面排查失败场景才有底气。

SM3到底是什么?

SM3是一种密码学哈希算法。输入任意长度的消息,输出固定长度的摘要,这个摘要就是消息的「指纹」。它继承了一些经典设计思路,但算法细节完全是自主研发的。

核心指标:SM3输出256位(32字节)的摘要。
一句话记住:SM3 = 国标哈希,256位输出,跟SHA-256安全强度同级,但算法不同。

我习惯把它跟SHA-256作对比,这样容易理解差异:

对比项 SM3 SHA-256
输出长度 256 bit / 32 Byte 256 bit / 32 Byte
消息分组大小 512 bit 512 bit
轮函数结构 64轮(含消息扩展) 64轮
国标状态 GB/T 32905-2016 FIPS 180-4(国际)
核心设计 基于Feistel结构的压缩函数 基于Davies-Meyer结构

看到没?输出长度相同,但内部轮函数、消息扩展、压缩函数都不一样。所以你不能简单把SHA-256的实现改几个常数就冒充SM3——我曾经见过有人这么干,验签当然失败了。

SM3的基本原理

SM3的处理流程可以拆成几个步骤。嗯,这里我画了张图,你看一下整体脉络:

SM3 算法核心流程 任意长度消息 填充 + 512 bit 分组 迭代压缩(64轮) 消息扩展 → 压缩函数 → 中间状态更新 256 bit 摘要 注意:每个分组必须经过消息扩展(Wj 和 Wj')生成132个字,再进入64轮压缩。输入长度以位为单位,填充包含1、0和64位长度域。

我再详细拆开讲:

  1. 消息填充:先把消息末尾补一个'1',然后补若干'0',再用64位表示原始消息长度(bit)。最终长度必须是512的整数倍。这一块我曾经踩过坑——有个平台上用32位整数存长度,消息超过4G字节就溢出,校验结果当然不对。
  2. 分组处理:每个512 bit分组进来,先进行消息扩展。扩展出132个32位字(W0~W67, W0'~W63')。然后进入64轮压缩函数,每一轮用布尔函数、循环移位、模加运算更新中间状态。
  3. 初始值:IV(初始向量)是固定的8个字(V0~V7),每个字32位。具体值在GB/T 32905里能查到,我就不列了。
  4. 输出:所有分组处理完,最后8个字的串联就是256位摘要。
我个人习惯:看标准时先画一遍流程图。把「填充—消息扩展—64轮压缩—状态更新」四步画下来,再对照程序走一遍,哪里容易出Bug一目了然。特别是消息扩展那部分,很多实现漏了Wj'的计算,导致校验失败。

SM3的应用场景

说实话,SM3现在已经不是「备选项」了。在很多行业里,它是「必选项」。你想想看:

  • 数字签名:SM2签名算法底层就用SM3做消息摘要。我在一个政务系统里见过,签名验签全程用国密,SM3算完摘要再给SM2签名。
  • 完整性校验:固件升级、文件传输、日志审计——这些场景你用MD5可能被笑话不安全,用SM3就合规。我记得有一次给某银行做U盾固件签名,客户明确要求不能用SHA,必须SM3。
  • 消息认证码(HMAC-SM3):用SM3替代SHA-256构造HMAC,很多API签名方案已经在用了。
  • 随机数生成 / 密钥派生:一些国密协议会用SM3做熵源或派生函数。不过这里要小心,SM3不是专为KDF设计的,用之前最好参考GMT 0005标准。
场景 典型要求 为什么不选其他算法
数字签名(SM2) 摘要长度必须256位 SM2标准规定必须配SM3
金融领域MAC计算 国密合规、抗碰撞 SHA-256无国密认证
电子政务系统 全链路国产化 政策强制要求
固件/软件包校验 防篡改,兼容性 SM3效率高,软硬件支持好
曾经有个教训:我在一个IoT项目里用SM3做OTA固件校验,结果设备在校验时总是失败。排查了好久才发现是芯片的SIMD加速单元没有正确初始化,导致部分消息扩展计算错误。所以——用硬件加速SM3时,一定要确认驱动和寄存器配置对了,否则软件实现和硬加速结果不一致,你会怀疑人生的。

好了,SM3的基本面就这些。把「输出256位、填充规则、64轮迭代」这几个概念记住,后面章节排查校验失败场景时,你才能快速定位问题出在填充阶段还是压缩阶段,或者干脆是库实现不标准。我见过太多人连自己用的是什么哈希都没搞清楚就开始Debug,那效率肯定高不了。