4. SM2加密算法:加密流程、解密流程、密文膨胀问题与优化思路
SM2加密,说白了就是公钥加密、私钥解密。但跟RSA那种直接拿公钥往数据上一糊不一样,SM2用的是混合加密——椭圆曲线上的点乘运算生成共享密钥,再用对称算法去保护实际数据。我刚开始接触SM2时也觉得绕,后来发现这种设计其实很巧妙,既解决了密钥分发问题,又兼顾了性能。
4.1 加密流程:三步走
SM2加密不是直接把明文变成密文,而是先生成一个临时密钥对,再用对方的公钥去派生一个共享密钥。具体流程我习惯拆成三步:
- 生成临时密钥对:随机选一个k,计算椭圆曲线上的点C1 = k * G。这个C1就是临时公钥,会随密文一起发给对方。
- 派生共享密钥:用临时私钥k和对方公钥PB做点乘,得到共享点S = k * PB。然后通过KDF(密钥派生函数)从S的x坐标和y坐标中提取出对称密钥t。
- 加密数据:用t对明文M做对称加密(SM4或XOR),得到C2。再对C2和共享点的相关信息做杂凑,得到C3作为校验码。
最终密文是C1 || C3 || C2。C1是椭圆曲线上的点,C3是杂凑值,C2才是真正的加密数据。
核心公式:C1 = k * G,S = k * PB,t = KDF(S.x || S.y, klen),C2 = M ⊕ t,C3 = Hash(S.x || M || S.y)
我在项目中遇到过一个问题:KDF的输入长度如果没对齐,不同实现算出来的t就不一样,导致解密失败。后来统一按SM2标准文档里的字节序来,才彻底解决。
4.2 解密流程:逆向操作
解密就是加密的逆过程。接收方拿到C1 || C3 || C2后,用自己的私钥dB去解:
- 恢复共享密钥:计算S = dB * C1。因为C1 = k * G,所以S = dB * k * G = k * PB,跟加密方算出来的S是同一个点。
- 派生对称密钥:同样用KDF从S中提取t。
- 解密数据:M = C2 ⊕ t,得到明文。
- 校验完整性:重新计算C3' = Hash(S.x || M || S.y),跟收到的C3比对。不一致就说明数据被篡改过。
你想想看,如果C3校验失败,说明要么密文被改过,要么密钥不对。我建议解密端一定要做这个校验,否则攻击者可以通过修改C1来诱导你算出错误的共享密钥,进而泄露信息。
避坑指南:我曾经在移植SM2到一款低端MCU时,发现解密偶尔会失败。查了两天才定位到问题——椭圆曲线点乘运算中,如果C1是无穷远点,解密方算出来的S就是无穷远点,KDF会输出全0。标准里其实要求检查C1是否在曲线上且不是无穷远点,但很多实现偷懒没做。后来我加了这个检查,问题就消失了。
4.3 密文膨胀问题:为什么SM2密文比明文大那么多?
这是SM2最让人头疼的地方。假设你要加密100字节的数据,最终密文是多少?
| 字段 | 大小 | 说明 |
|---|---|---|
| C1(临时公钥) | 64字节 | 椭圆曲线点,x和y各32字节 |
| C3(杂凑值) | 32字节 | SM3杂凑输出 |
| C2(加密数据) | 100字节 | 跟明文等长 |
| 总密文 | 196字节 | 膨胀了近2倍 |
为什么会这样?因为C1和C3是固定开销,跟明文长度无关。你加密1字节和加密1KB,C1和C3都是64+32=96字节。明文越短,膨胀比越离谱。
我记得有个项目要加密物联网设备上报的传感器数据,每条才20字节。如果用标准SM2,密文变成116字节,传输开销直接翻了5倍多。这在窄带物联网场景下几乎是不可接受的。
4.4 优化思路:怎么把膨胀压下来?
针对密文膨胀,我总结了几种优化思路,按推荐程度排序:
- 思路一:复用临时密钥对。如果一次会话要加密多条消息,可以只生成一次C1,后续消息直接复用。这样C1的开销只出现一次。但要注意,临时私钥k不能重复使用太久,否则会有安全风险。我一般建议一个会话最多复用100次就换。
- 思路二:压缩C1。椭圆曲线上的点可以用x坐标加一个标志位来表示y的奇偶性,这样C1从64字节压缩到33字节。解密时再根据x和标志位恢复出完整的点。这个方案完全兼容标准,只是计算量稍微大一点。
- 思路三:使用混合加密模式。对于长消息,先用SM2加密一个对称密钥(比如AES-256的密钥),再用这个对称密钥去加密实际数据。这样SM2只加密32字节的密钥,密文膨胀被限制在96+32=128字节,而实际数据用对称加密几乎没有膨胀。
- 思路四:裁剪C3。如果应用场景对完整性校验要求不高(比如数据本身有MAC保护),可以只保留C3的前16字节。标准里没有禁止这么做,但安全性会打折扣。我只有在极端资源受限的场景下才敢这么干。
我的建议:如果带宽不是瓶颈,优先用标准SM2,兼容性最好。如果带宽紧张,用压缩C1 + 复用临时密钥对,能把膨胀比从2倍降到1.2倍左右。如果还不行,再考虑混合加密模式。
4.5 加密/解密流程总览
下面这张图把加密和解密的完整流程串起来了,方便你对照着看: