2. SM3 算法概述

哈希函数,说白了就是给任意长度的数据打一个“数字指纹”。你输入一段文字、一张图片,甚至一个几百 MB 的文件,它都能给你算出一个固定长度的摘要。这个摘要几乎不可能反向还原出原文——对,这就是单向性。

我刚开始接触密码学的时候,总觉得哈希不就是个校验和吗?后来被项目坑过一次才明白:校验和(比如 CRC)是专为错误检测设计的,哈希函数得扛得住恶意碰撞攻击。你想想看,攻击者要是能故意造出两个不同文件却拥有同一个哈希值,那签名、证书就全废了。

2.1 哈希函数原理

一个合格的哈希函数,必须满足三个核心性质:

  • 单向性(Preimage Resistance):给定 y = H(x),几乎不可能找到任何 x' 使得 H(x') = y。说白了,就是只能正向算,不能反向推。
  • 第二原像抗性(Second Preimage Resistance):已知 x 和 y = H(x),几乎不可能找到另一个 x' ≠ x 使得 H(x') = y。
  • 碰撞抗性(Collision Resistance):找不到任意两个不同的 x1, x2 使 H(x1) = H(x2)。

为什么第三点特别重要?我举个例子:你在证书上签名,签的是哈希值。如果有人能造出两份不同合同但哈希值相同,就能拿一份合法的合同去申请签名,然后用另一个恶意版本去骗人。嗯,这叫碰撞攻击,SM3 的设计里特别考虑了这一点。

2.2 SM3 国家标准(GM/T 0004)

SM3 是国密标准里的哈希算法,全称叫“GM/T 0004-2012 SM3 密码杂凑算法”。它是中国国家密码管理局在 2012 年发布的,后来 2016 年更新过一版。标准里规定了算法步骤、初始值、常量、消息填充方式、迭代压缩函数,甚至给了一份 C 参考实现。

我在做金融系统国密改造时,发现很多同事会把 SM3 和 SHA-256 混用,觉得“反正都是 256 位输出”。其实不对——SM3 的压缩函数结构和 SHA-256 差异很大,安全边界也不一样。

2.3 SM3 算法核心流程

SM3 的处理流程大体分三步:

  1. 消息填充:先在消息末尾加一个 1 bit,再加若干个 0 bit,使消息长度模 512 等于 448。最后附加 64 bit 的原始消息长度(大端序)。
  2. 消息分组:填充后的消息按 512 bit(64 字节)一组分成 B0, B1, ..., Bn-1。
  3. 迭代压缩:每一组经过 64 轮压缩,更新 256 bit 的中间状态,最终输出 256 bit 摘要。
小提示:SM3 的初始值 IV 也是 8 个 32 bit 字,具体是 0x7380166f, 0x4914b2b9, ...。可以在标准文档里查到。
SM3 算法总体流程 原始消息 M 消息填充 (M' = M || 1 || 0* || len) 分组为512bit块 B0, B1, ..., Bn-1 迭代压缩 (64轮, 更新V) 初始值IV → 逐块处理 → 最终V 256bit 摘要

2.4 SM3 与 SHA-256 的对比分析

很多同学问我:“直接用 SHA-256 不行么?SM3 有什么特别的?” 我的回答是:两者都是 256 位哈希,但设计细节和安全性不同。咱们直接看对比表:

对比维度SM3 (GM/T 0004)SHA-256 (FIPS 180-4)
输出长度256 bit256 bit
消息块大小512 bit512 bit
轮数64 轮64 轮
压缩函数结构类 ARX + 布尔函数类 ARX
布尔函数FF, GG 四个变体Ch, Maj
常量方式每轮有固定常量 Tj前 64 个质数平方根小数部分
消息扩展Wj 由前 16 字递推,Wj' 额外生成Wt 由前 16 字递推
国家/标准中国 GM/T 0004美国 FIPS 180-4
典型应用国密证书、电子签章、密码机全球通用、SSL/TLS、区块链

你看,轮数虽然相同,但 SM3 在消息扩展阶段多了一个 Wj',而且每轮的布尔函数 FF 和 GG 会在不同轮次切换。这些细节让 SM3 在理论安全性上略高于 SHA-256(比如更好的抗侧信道攻击能力)。不过实际应用中,只要哈希函数没被攻破,两者在安全强度上差别不大。

2.5 避坑与项目经验

我曾经踩过的坑:有一次在某国密网关项目中,客户端用 SM3 哈希然后发到服务端做签名验证。结果签名验证老失败。排查了半天才发现:客户端代码用 Python 的 hashlib 里 sm3 底层调的是 OpenSSL 的实现,但 OpenSSL 3.0 里 SM3 默认是 EVP_MD 模式,和 GM/T 标准里定义的初始向量有一点点字节序差异。后来我把两边的实现都换成 gmssl 库(国产封装)才对齐。

说到底,做国密开发有三点要盯紧:

  • 确认使用的库是否通过商密认证(比如 GmSSL、Trusted Key Management Client)。
  • 消息填充方式一定按标准来,不要自己拍脑袋改长度编码的字节序。
  • SM3 和 SHA-256 不能混用,混用意味着脱离国密体系,很多合规审查会通不过。

一句话总结:SM3 是国密标准里的 256 位哈希,结构和 SHA-256 相似但细节有差异。选型时优先看产品是否支持 GM/T 0004 认证,而不是只看输出长度。