3. 非对称加密原理:RSA、ECC、SM2算法原理与使用场景归纳总结
做SDK封装最头疼的事情是什么?我自己的体会是——加密场景太多样了。有的客户必须用RSA,有的偏爱国密SM2,还有的非要ECC。你要是每样都重新写一套,代码迟早变成一坨“加密面条”。
所以在讲具体怎么封装之前,咱们先把这三个主流非对称算法的核心原理和适用场景捋清楚。你想想看,搞懂了“区别”,才知道怎么“统一”。
3.1 非对称加密到底在解决什么问题?
说白了,对称加密就像你和朋友共用一个保险箱,两边各拿一把相同的钥匙。问题来了——钥匙怎么安全地送到对方手上?
非对称加密的妙处就在于:你有两把钥匙,公钥随便给,私钥自己藏着。别人用公钥加密的数据,只有私钥能解开。反过来,你用私钥签名,别人用公钥验签,就能证明这条消息确实是你发的。
不过,非对称加密也有短板。计算量大、速度慢,不适合直接加密大文件。实际项目中,通常把它和对称加密配合着用——非对称加密用来交换对称密钥,对称密钥再加密实际数据。这个模式也叫“混合加密”。
3.2 RSA:最经典,但已经有点“老态”了
RSA的原理基于一个大整数分解难题:给定两个大素数,算乘积很容易,但反过来把乘积分解回素数就难到要命。
简单说,RSA的密钥对生成过程是这样的:
- 随机选两个大素数 p 和 q
- 计算 n = p × q
- 计算 φ(n) = (p-1) × (q-1)
- 选一个与φ(n)互质的整数 e(常用65537)
- 计算 d 使得 e×d ≡ 1 (mod φ(n))
最终公钥为 (n, e),私钥为 (n, d)。加密时用公钥,解密用私钥。
听起来挺完美?但我在项目中遇到过一个大坑:RSA的密钥长度决定了安全强度。现在普遍推荐用2048位或更高,2048位以下基本不安全了。可密钥一长,性能就成问题。签名验签还凑合,加解密几百字节的数据,肉眼可见的慢。
| 特性 | RSA | 建议 |
|---|---|---|
| 安全强度 | 依赖密钥长度 | 建议至少2048位 |
| 性能 | 加密慢,解密更慢 | 仅用于密钥交换或签名 |
| 适用场景 | 旧系统、兼容性优先 | 金融、PKI基础设施 |
3.3 ECC:用更短的密钥,提供更强的安全
ECC(椭圆曲线密码学)的原理比RSA复杂不少。它利用的是椭圆曲线上的“点加法”与“标量乘法”构成的单向函数。给一个基点G和一个整数k,算出kG很容易;但给你P和G,要反推出k——这就是“椭圆曲线离散对数难题”,难到炸裂。
ECC最大的优势:
- 256位的ECC密钥 ≈ 3072位的RSA密钥
- 计算量更小,适合移动端、IoT设备
- 密钥生成速度也快很多
我前几年封装过一个车载T-Box的SDK,里面必须支持安全通信。对方要求密钥长度不能超过256位,RSA根本塞不进去。后来换成ECC(secp256r1曲线),轻巧地就把事情办了。
不过ECC也有麻烦——曲线参数多。什么P-256、P-384、Curve25519……选错了曲线,两边就玩不转了。我在SDK里一般固定支持几条主流曲线,再给一个“自定义曲线”的扩展接口。
3.4 SM2:国标密码,合规必选项
SM2是国家密码管理局发布的椭圆曲线公钥密码算法,本质上还是ECC,但曲线参数是咱们自己定义的。它包含了加密、签名、密钥交换三个部分。
SM2的一个特点:签名与验签的输出格式跟ECDSA不太一样,签名结果是(r, s)两个大整数,但最后要做DER编码。而且SM2公钥是65字节的未压缩格式(前缀0x04 + x坐标 + y坐标)。
我做一个政务系统SDK时,客户要求必须纯国产密码,连openssl都不能用(某些审查环境)。怎么办?我只能手写SM2的椭圆曲线点乘运算……
| 指标 | RSA-2048 | ECC-256 | SM2 |
|---|---|---|---|
| 公钥长度 | 256字节 | 32字节(压缩) | 65字节 |
| 安全级别 | 112 bit | 128 bit | 128 bit |
| 运算速度 | 慢 | 快 | 中(受国产优化影响) |
| 标准状态 | 国际标准 | 国际标准 | 中国国标 |
| 主要领域 | 全球金融、Web | 移动端、区块链 | 政务、金融、能源 |
3.5 一张图看懂非对称加密选择
三种算法各有千秋,选哪个取决于场景。下面这张逻辑图是我自己梳理的,放在SDK文档里帮开发者快速决策:
3.6 封装接口时该注意什么
了解了原理,怎么把它们揉进同一个SDK里?我总结过几个原则:
- 统一输入输出格式: 不管底层是RSA还是SM2,上层接口都用字节数组收、字节数组发。具体编码(Base64、Hex)交给序列化层处理。
- 算法标识前置: 密钥对里加一个算法类型字段(enum: RSA, ECC, SM2),让SDK自动选择匹配的实现。
- 性能敏感场景开缓存: 比如RSA的模幂运算可以预计算部分值,ECC的椭圆曲线运算可以缓存查找表。我在一个高并发服务里用了这个技巧,签名速度提升了3倍。
- 异常处理统一: 不同算法抛出的异常类型五花八门,建议封装成统一的 CryptoException,带上错误码和附加信息。
最后说一句:你永远不知道下个对接方会用什么算法。所以我把RSA、ECC、SM2都支持了,并且提供一个“可插拔”的Provider接口。哪天出来个SM3+RSA的组合?往里加个Provider就行。这才是兼容性设计的精髓。