第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广泛应用于以下场景:
- 电子证照与电子印章 – 各级政务系统、电子合同平台
- 金融交易签名 – 网银、手机银行、第三方支付
- 身份认证与数字证书 – 国密SSL证书、VPN认证
- 区块链与数据存证 – 部分联盟链采用SM2作为核心签名算法
- 物联网设备身份 – 智能电表、车联网T-Box等低算力设备
讲一个我自己带团队时踩过的坑。有一次做车联网平台,设备端签名后把原始r和s直接拼成64字节发过来。我们服务端用标准库验签,总是失败。后来发现设备端在计算ZA时用的是空用户标识(空字符串),而服务端默认用“1234567812345678”作为用户标识。你想想看,ZA不同,整个哈希值就不同,签名当然验不过。那把用户标识作为业务参数显式传递,才能解决这个问题。
下面是SM2签名验签的核心流程,我画了一张结构图帮助你理解:
⚠️ 避坑指南:我曾经在实现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缺失会使哈希结果完全不同。所以实际系统中,用户标识通常作为协议字段明文传递,或者用空字符串约定。这个细节我在多个项目中反复提醒过,希望你能记牢。