第三章 SM2算法原理快速入门
聊到国密算法,SM2是绕不开的核心。它是基于椭圆曲线的公钥密码体制,对标国际的ECDSA和ECIES。坦白说,椭圆曲线密码学在刚入行时是有点抽象——一群点落在曲线上,还搞什么加法运算?但真正上手做接口改造时你会发现,理解这套理论能让你少踩很多坑。
3.1 椭圆曲线密码学基础
椭圆曲线密码学,英文简称ECC。它依赖的是椭圆曲线在有限域上的离散对数问题。你想想看,如果给你一个基点G和它的倍数kG,计算kG很容易,但从kG反推出k却非常困难。这就是ECC的安全基石。
SM2使用的椭圆曲线方程是:
y² = x³ + ax + b (mod p)
其中p是一个大素数。SM2的a、b、p、G等参数都已经标准化了。我建议在实现时直接使用国家发布的参数,千万别自己随便挑曲线——我之前见过有人为了对比性能自己造曲线,结果根本没考虑安全强度。
具体来说,曲线上的加法可以这样理解:对于两个不同的点P和Q,连接它们的直线会与曲线相交于第三个点R',这个R'关于x轴的对称点就是P+Q的结果。当P和Q重合时,就变成了点倍运算——过P做切线,交点再对称。说白了,椭圆曲线的点乘就是这么一步步算出来的。
| 概念 | 说明 |
|---|---|
| 基点G | SM2标准曲线上的公共生成点 |
| 阶数n | G的倍数构成的循环群的元素个数 |
| 私钥d | 随机选取的大整数,范围在[1, n-2] |
| 公钥Q | Q = d * G,即私钥乘基点 |
嗯,这里要注意:椭圆曲线密码体制设计的好坏,很大程度上取决于曲线的选择。SM2选的是素域上的Fp曲线,计算效率和安全强度都是经过仔细权衡的。我在项目里对比过SM2和ECDSA,同样的安全强度下SM2的公钥长度比RSA短得多。
3.2 密钥对生成
SM2的密钥对生成过程其实很简单:
- 选取随机数d ∈ [1, n-2]
- 计算公钥Q = d * G
- 私钥保存d,公钥发布Q
看吧,就这么几步。但随机数生成的质量非常关键。我记得有一次项目中,同事直接用了Java的Random类生成密钥,结果导致部分密钥出现了重复。因为伪随机数生成器在没有足够种子熵的情况下,会出现周期性。我建议使用系统级的加密安全随机数生成器,比如Java的SecureRandom或OpenSSL的RAND_bytes。
另外,公钥的存储格式也很重要。SM2公钥通常包含两个分量:x坐标和y坐标。这两个值一起才能唯一确定公钥点。如果只存x坐标,验签时会多出一个重建y坐标的步骤,既麻烦又容易出错。
3.3 签名与验签流程
SM2的数字签名算法比RSA签名更复杂一些——它引入了用户身份标识ZA。说白了,签名时不仅要防消息被篡改,还要防签名被重用到其他用户或场景中。我用一个流程图来展示SM2签名验签的核心逻辑:
你看签名过程里有个随机数k。这个k值必须严格保密且每次签名都要重新生成。为什么?因为一旦k泄露,私钥就可以被推导出来。我曾经见过一个系统因为性能压力,对同一笔交易重复使用了相同的k,结果验签虽然正常通过了,但被外部攻击者拿到了重复签名的数据,一下就把私钥算出来了。
3.4 加解密过程
SM2的加解密与签名验签名不同。加密时,它用接收方的公钥对数据做加密;解密时,用接收方的私钥把数据恢复出来。SM2加密采用的是混合加密框架——说白了,就是用SM2公钥加密一个对称密钥,然后用这个对称密钥加密真正的消息。
具体步骤我列在下面:
- 加密:先生成一个随机数k,计算点C1 = kG。然后用k与接收方公钥Q的乘积生成一个共享秘密点S = kQ。通过S的x坐标派生出对称密钥,加密消息得到密文C2。最后计算杂凑值C3。最终密文是C1 || C2 || C3。
- 解密:先检查C1是否在曲线上,然后用私钥d计算S = d * C1。用同样的KDF从S的x坐标派生出对称密钥,解密C2得到原始消息。最后验证C3是否匹配。
这里有个细节——SM2加密时生成的C1其实是椭圆曲线上的一个点,它包含了x和y两个坐标。在传输时可以压缩存储,但我在实际开发中发现直接存两个整数更安全,省去了解压缩步骤可能引入的偏差。
| 步骤 | 加密方 | 解密方 |
|---|---|---|
| 生成随机数 | k | — |
| 计算共享点 | S = kQ | S = d * C1 |
| 派生密钥 | 从S.x派生 | 从S.x派生 |
| 加密/解密 | SM4对称加密 | SM4对称解密 |
| 完整性 | 计算C3 | 验证C3 |
嗯,第三章节的主要内容就是这些。椭圆曲线基础、密钥对生成、签名验签、加解密,每个环节都有它存在的理由。你想想看,SM2能够在1024位RSA差不多的性能下提供更高的安全强度,这都是因为它建立在离散对数困难的基础上。搞懂这些,后面的SM3和SM4加解密改造就会顺畅很多。