3. 非对称加密算法在SDK中的应用(RSA、ECC、SM2)
今天咱们聊聊非对称加密。这是加密SDK的基石之一,面试基本必问。
非对称加密,简单讲就是一对密钥——公钥加密,私钥解密。公钥满大街发都没事,私钥必须锁保险柜。SDK里用得最多的,就是RSA、ECC和SM2这三位。我个人的经验是,搞懂它们各自的脾气,比死记硬背公式重要得多。
3.1 RSA:老牌劲旅,但最近有点“胖”
RSA的性能,说白了就是慢。密钥越长越慢。我曾经在项目中用RSA-2048加密一个几百字节的AES密钥,每次耗时几十毫秒。相比之下,对称加密几乎是瞬间完成。
RSA在SDK里的核心应用场景:
- 密钥交换:客户端用服务器公钥加密一个对称密钥(比如AES Key),服务器用私钥解密。我建议你千万别用RSA直接加密业务数据,太亏了。
- 数字签名:私钥签名,公钥验签。比如软件更新包的数字签名,确保文件没被篡改。
- 证书验证:HTTPS握手时,服务器证明自己的身份,用的就是RSA签名。
避坑指南:我见过有人在SDK里用了512位的RSA密钥,说是“为了性能”。这是找死。现在推荐至少2048位,银行和政务场景甚至要求4096位。1024位在2010年左右就被认为不安全了。
3.2 ECC:短小精悍的现代选手
ECC(椭圆曲线加密)的好处是,在同等安全强度下,它的密钥长度比RSA短得多。256位ECC的安全强度大约等于3072位RSA。密钥短意味着计算量小、带宽占用低,对移动端SDK非常友好。
ECC在SDK里的常见姿势:
- ECDH密钥协商:双方各自生成临时密钥对,交换公钥后算出同一个共享密钥。这个过程叫密钥协商,不直接传输对称密钥。我个人觉得这是最优雅的方案。
- ECDSA签名:和RSA类似,但签名体积小。适合IoT设备、智能卡这种资源受限的环境。
- 证书链:很多新型CA开始签发ECC证书,比如Let's Encrypt。HTTPS握手时,服务端ECC证书的握手速度比RSA快不少。
我的经验:在实际SDK开发中,我强烈建议优先使用ECDHE(临时ECC密钥的DH握手)而不是静态ECDH。静态ECDH如果私钥泄露,所有历史会话都会暴露。临时密钥可以做到“前向安全性”。嗯,这一点面试时经常被问到。
3.3 SM2:国密标准,合规必备
SM2是国家密码管理局发布的椭圆曲线公钥密码算法。它跟ECC同属椭圆曲线体系,但曲线参数是国密局定的,自带“合规光环”。如果你的SDK要进政务、金融、电力等强监管行业,SM2是必选项。
SM2在SDK里的特殊之处:
- 算法逻辑:SM2的签名和密钥交换流程跟ECDSA、ECDH略有不同。比如签名时,它计算过程多了一步,并且输出的是DER编码格式(而非简单拼接)。
- 性能:SM2在大多数现代CPU上,用软件实现的性能接近P-256(ECC标准曲线)。但要注意,硬件加速支持不如RSA和ECC那么普遍。
- 证书格式:SM2证书和签名文件遵循GMT 0015-2012标准,跟X.509证书不太一样。SDK解析时不能直接用通用库,得用国密专用库(比如GmSSL、BSAFE)。
我曾经踩过的坑:有次做国密SDK适配,客户给的SM2签名数据是原始R||S格式(64字节),但SM2标准要求DER编码(70~72字节)。如果直接用OpenSSL的ECDSA接口去验,必失败。你得单独实现SM2的签名编解码逻辑。
3.4 实战对比:怎么选?
| 维度 | RSA-2048 | ECC (P-256) | SM2 |
|---|---|---|---|
| 密钥长度 | 2048 位 | 256 位 | 256 位 |
| 加密/解密速度 | 较慢(数百微秒级) | 快(微秒级) | 较快(微秒级) |
| 签名/验签速度 | 签名慢,验签快 | 签名快,验签快 | 签名和验签速度接近P-256 |
| 签名体积 | 256 字节 | 64 字节 | 64~72 字节(DER编码) |
| 计算消耗 | 高 | 低 | 低 |
| 安全强度(等价对称) | ~112位 | ~128位 | ~128位 |
| 合规场景 | 通用国际标准 | 通用国际标准 | 中国国家标准(GM/T) |
你想想看,如果SDK是给海外App用的,选ECC更省带宽、更快。如果客户有国密合规要求,SM2是硬门槛。至于RSA,现在主要用在老旧系统的兼容上,或者一些必须用PKCS#1标准的场景(比如某些硬件安全模块HSM)。
一句话总结选型:
- 纯性能优先 → ECC (P-256/X25519)
- 合规要求(中国) → SM2
- 历史兼容性 & 硬件HSM → RSA
- 混合方案 → 协商时支持RSA+ECC,业务数据用SM4或AES
3.5 SDK中的正确打开方式(伪代码)
展示一段典型的密钥协商和加密流程。你想想,SDK里最忌讳写死算法和密钥。
// 假设用户已导入SDK提供的公钥
// 1. 生成临时EC密钥对(用于前向安全)
KeyPair ephemeralKeyPair = KeyPairGenerator.getInstance("EC").generateKeyPair();
// 2. 与服务端进行ECDH密钥协商
byte[] sharedSecret = ECDH.agree(
ephemeralKeyPair.getPrivate(),
serverPublicKey
);
// 3. 用KDF派生会话密钥(不能让原始sharedSecret直接当密钥)
byte[] sessionKey = KDF.deriveBytes(sharedSecret, 32, "AES-256");
// 4. 使用对称加密保护业务数据(AES-GCM)
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sessionKey, "AES"));
byte[] iv = cipher.getIV();
byte[] ciphertext = cipher.doFinal(plaintext);
// 5. 发送临时公钥+IV+密文给服务端
sendToServer(ephemeralKeyPair.getPublic().getEncoded(), iv, ciphertext);
我建议你一定要加KDF(密钥派生函数)这一步。很多SDK开发者直接拿ECDH的输出当AES密钥用,这是典型的错误。因为ECDH输出并不是均匀随机的,必须用HKDF或PBKDF2再处理一次,才能保证安全。
下面这张图能帮你在面试时理清思路:什么时候该用哪种非对称算法。
3.6 再聊几点面试高频题
- Q: 为什么非对称加密不能直接替代对称加密?
A: 因为非对称慢一个数量级。而且算法复杂,对大文件加密不现实。它是用来解决“密钥如何安全传输”这个问题的。 - Q: ECC和RSA哪种更安全?
A: 同等密钥长度下,ECC更安全。目前的公开资料表明,P-256的攻破难度远高于RSA-2048。但ECC依赖于曲线参数的随机性,给一条坏曲线(比如P-192)那安全性还不如RSA-1024。 - Q: 在SDK中实现SM2必须用原生库吗?
A: 不一定。不过为了合规和性能,建议用经过商密认证的硬件加速或软件库。用纯Java/Go实现SM2曲线运算会非常慢,而且容易引入侧信道风险。