第1章 SM2算法概述:国密标准、椭圆曲线密码学基础与签名验签应用场景

1.1 国密标准的前世今生

我第一次听说“国密”这个词,还是在十年前做政务系统的时候。那时候客户要求必须用SM2签名,我翻遍了文档,发现这东西跟ECDSA长得挺像,但细节上有很多不一样的地方。后来才慢慢理解,国密标准不是简单抄个曲线,它背后有一套完整的设计逻辑。

国密标准由国家密码管理局发布,主要包括:

  • SM2 – 椭圆曲线公钥密码算法(签名、密钥交换、加密)
  • SM3 – 密码杂凑算法(输出256位)
  • SM4 – 分组密码算法(对标AES)
  • SM9 – 标识密码算法(基于双线性对)

其中SM2是核心中的核心。很多银行、政务、电力系统已经从国际算法迁移到SM2。我个人习惯在项目里先把国密标准文档打印出来,对照着写代码,因为细节太容易踩坑了。

关键点:SM2使用的椭圆曲线参数是固定的(sm2p256v1),不像ECDSA可以临时选曲线。曲线方程 y² = x³ + ax + b,其中 a = 0xFFFFFFFE…(固定值),b和基点G也是标准定义的。

1.2 椭圆曲线密码学基础

椭圆曲线密码(ECC)靠的是“椭圆曲线上的离散对数问题”。说白了:给定基点G和私钥d,很容易算公钥Q=dG;但给Q和G,想反推d几乎不可能。这个不对称性就是安全的基石。

SM2用的椭圆曲线比特长度是256位,安全强度相当于3072位的RSA。你想想看,同样安全等级,SM2的密钥长度只有RSA的十分之一,签名长度也只有64字节,在移动设备上优势特别明显。

我在项目中遇到过一个小困惑:SM2的签名值由两个整数(r, s)组成,每个32字节,一共64字节。但验签的时候需要把s转换成其模n的逆元,这个步骤跟ECDSA不太一样。这里有一张对比表:

算法 签名过程 验签过程 签名长度
SM2 计算e = SM3(ZA || M),用随机数k计算椭圆曲线点,再算r和s 验证 sG + tP 是否等于 r'G(t = r + s mod n) 64字节
ECDSA 计算e = SHA-256(M),用随机数k计算椭圆曲线点,再算r和s 验证 u1G + u2P 是否等于某点(u1 = e·s⁻¹, u2 = r·s⁻¹) 64~72字节

可以看到,SM2的验签公式比ECDSA多了个“ZA”杂凑预处理,这是防止多公钥重用和中间人攻击的设计。嗯,这里要注意——ZA是把用户标识、曲线参数和公钥一起哈希,然后再跟消息拼接。这个细节在对接时特别容易被忽略。

小经验:在写SM2验签的时候,一定要先确认对方是否在消息前面拼了ZA。我见过好几个项目因为没拼ZA导致验签失败,排查了一整天。如果你用PEM格式传输公钥,别忘了把公钥里的x、y坐标原样提取出来。

1.3 SM2签名验签的应用场景

SM2广泛应用于以下场景:

  1. 电子证照与电子印章 – 各级政务系统、电子合同平台
  2. 金融交易签名 – 网银、手机银行、第三方支付
  3. 身份认证与数字证书 – 国密SSL证书、VPN认证
  4. 区块链与数据存证 – 部分联盟链采用SM2作为核心签名算法
  5. 物联网设备身份 – 智能电表、车联网T-Box等低算力设备

讲一个我自己带团队时踩过的坑。有一次做车联网平台,设备端签名后把原始r和s直接拼成64字节发过来。我们服务端用标准库验签,总是失败。后来发现设备端在计算ZA时用的是空用户标识(空字符串),而服务端默认用“1234567812345678”作为用户标识。你想想看,ZA不同,整个哈希值就不同,签名当然验不过。那把用户标识作为业务参数显式传递,才能解决这个问题。

下面是SM2签名验签的核心流程,我画了一张结构图帮助你理解:

SM2签名验签核心流程图 消息 M 用户标识 ZA (ID+曲线参数+公钥) SM3 哈希 e = SM3(ZA || M) 随机数 k 点运算 k·G 得到点 (x1,y1) 计算 r = e + x1 (mod n) 计算 s s = (1+d)⁻¹·(k - r·d) (mod n) 签名 (r, s) 说明 ① 签名方持有私钥 d,公钥 P = d·G ② 验签方用公钥 P、用户标识和消息 M,按逆运算验证 (r, s) 是否合法

⚠️ 避坑指南:我曾经在实现SM2签名的时候,直接把ECDSA库改了几个参数就想跑通,结果签名长度对不上(ECDSA的s可能是32字节也可能是33字节,但SM2固定32字节)。另外,SM2的签名结果(r,s)如果r=0或s=0,必须重算,而ECDSA只要求s≠0。这些边界条件一定要仔细处理。

1.4 本章小结

这一章我们走通了SM2的核心脉络:

  • 国密标准是一套完整的密码体系,SM2是其中的公钥算法。
  • 椭圆曲线安全基于离散对数困难问题,256位SM2曲线对标3072位RSA。
  • 签名验签流程中,ZA预处理和固定参数是关键差异点。
  • 应用场景覆盖政务、金融、物联网等,还在不断扩展。

最后留一道自测题:假设你收到一段SM2签名(64字节),但不知道对方用了什么用户标识,你能验签吗?答案是不能——ZA缺失会使哈希结果完全不同。所以实际系统中,用户标识通常作为协议字段明文传递,或者用空字符串约定。这个细节我在多个项目中反复提醒过,希望你能记牢。