第2章:对称加密与非对称加密原理 —— AES、RSA、ECC 等常见算法简介与适用场景
聊到加密,很多朋友第一个反应就是「到底用对称还是非对称?」。这个问题我几乎在每个安全方案评审会上都会被问一遍。其实没那么玄乎,说白了就是一把钥匙和两把钥匙的区别。
对称加密:一把钥匙开一把锁
对称加密,我的理解很直白——加密和解密用的是同一把钥匙(密钥)。发信方用密钥加密,收信方用同样的密钥解密。速度快,适合批量数据。
举个我实际遇到过的场景:你要把 1GB 的数据库备份文件上传到对象存储,用 RSA 慢慢磨?别闹了。这种场景下,对称加密是唯一合理的选择。
AES 算法
AES(Advanced Encryption Standard)是目前最主流的对称加密算法。它取代了老旧的 DES 和 3DES。
- 密钥长度:AES-128、AES-192、AES-256。位数越高越安全,但开销也大一些。
- 工作模式:ECB、CBC、GCM 等。这里我要重点提一句。
注意:我个人习惯 永远不要用 ECB 模式。它把明文分成独立块分别加密,相同的明文块会得到相同的密文。这就直接暴露了数据的模式信息,攻击者可以轻松推断出内容。我见过有团队在日志加密里用了 ECB,结果被安全审计打回来重做。
GCM 模式是我现在最推荐的。它自带认证标签,能同时保证机密性和完整性,而且是流式处理,不需要填充。
适用场景
- 大量数据的存储加密(如文件、磁盘、数据库)
- 网络传输中的批量数据加密(如 TLS 中用于加密实际内容)
- 需要高性能加密的场景
// AES-GCM 示例(伪代码,展示密钥和 nonce 的使用)
byte[] key = randomBytes(32); // AES-256
byte[] nonce = randomBytes(12); // 12字节随机数
byte[] ciphertext = AES_GCM_encrypt(plaintext, key, nonce);
byte[] decrypted = AES_GCM_decrypt(ciphertext, key, nonce);
你看代码里有个 nonce(随机数)。这东西很重要——同一个密钥下不能重复使用同一个 nonce,否则加密的保密性会崩塌。我见过出过这样的生产事故。
其他对称算法
- SM4:国密标准,国内合规场景必备。结构和 AES 类似,但轮函数不同。别以为它只在中国用,我记得有次对接东南亚的客户,人家也要求支持 SM4。
- ChaCha20:流加密算法,在没有 AES 硬件加速的移动设备上效率极高。Google 在 Android 上已经把它作为 TLS 的默认加密套件了。
非对称加密:公钥 / 私钥
非对称加密,逻辑上更绕一些。用公钥加密的数据,只有配对的私钥能解开;或者反过来,私钥签名,公钥验证。
为什么需要它?对称密钥的分发是个死循环——你怎么安全地把密钥传给对方?非对称加密解决了这个鸡生蛋蛋生鸡的问题。
RSA 算法
RSA 的基础是大整数分解的数学难题。选两个大质数相乘容易,但从乘积反推质数极难。
- 密钥长度:2048 位是目前底线,4096 位更安全但更慢。
- 性能:非常慢。我实测过,RSA-2048 加密 256 字节大概需要几千微秒,而 AES-256 加密 1GB 数据也就几百毫秒。
- 填充方案:OAEP 是最推荐的,PCS#1 v1.5 已经被证明有漏洞。
小提示:RSA 不适合直接加密大量数据。常见的做法是「混合加密」——用 RSA 加密一个临时生成的对称密钥(如 AES 密钥),再用这个对称密钥加密实际数据。TLS 协议就是这么干的。
ECC / ECDSA / ECDH
椭圆曲线密码学(Elliptic Curve Cryptography),安全性基于椭圆曲线上的离散对数难题。同样的安全强度下,ECC 的密钥长度比 RSA 短得多(256 位的 ECC ≈ 3072 位的 RSA)。
我记得在 IoT 设备上做固件签名时,RSA-4096 的验签时间太长了,换到 ECDSA P-256 后,性能和功耗都降下来了。
- 密钥长度:P-256、P-384、P-521 是 NIST 推荐曲线。
- 性能:签名比 RSA 快很多,但验签稍微慢一点。
- 曲线选择:优先用 NIST P-256 或 Curve25519。网上流传的一些自定义曲线往往有后门,我建议别碰。
适用场景
- 密钥交换(ECDH)
- 数字签名(ECDSA、EdDSA)
- 混合加密方案
- 资源受限环境(如芯片、移动端)
// ECDH 密钥交换示例
// 双方各自生成密钥对
KeyPair aliceKeys = generateECCKeyPair(P256);
KeyPair bobKeys = generateECCKeyPair(P256);
// 交换公钥后,各自计算出共享密钥
byte[] sharedSecretAlice = ECDH_derive(aliceKeys.private, bobKeys.public);
byte[] sharedSecretBob = ECDH_derive(bobKeys.private, aliceKeys.public);
// sharedSecretAlice == sharedSecretBob
对称 vs 非对称:核心对比
| 对比维度 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个(共享密钥) | 2 个(公钥 + 私钥) |
| 加解密速度 | 快(硬件加速可达几十 Gbps) | 慢(RSA 约几 MBps) |
| 密钥分发 | 困难,需要安全通道 | 公钥可直接公开,私钥不外传 |
| 典型密钥长度 | 128-256 位 | 2048-4096 位 |
| 典型用途 | 数据加密 / 脱敏 | 密钥传输 / 数字签名 |
| 量子安全 | 256 位 AES 尚可 | RSA、ECC 均脆弱 |
为什么 RSA 和 ECC 都怕量子计算机?因为 Shor 算法能在多项式时间内破解大数分解和离散对数。但对称加密只要把密钥翻倍(比如 AES-256 升级到 AES-512),量子优势就会被大幅削弱。
混合加密:现实中的最优解
现实中不太有人只用非对称去加密几十 GB 的数据,也不会只用对称不停交换密钥。所以就有了混合加密方案。
流程大概是:
- 生成一个临时的对称密钥(比如 AES-256 的 32 字节密钥)
- 用接收方的公钥(RSA 或 ECC 公钥)加密这个临时密钥
- 用这个对称密钥加密实际数据
- 把加密后的临时密钥 + 加密数据一起发送
- 接收方先用自己的私钥解开临时密钥,再用它解密数据
TLS 1.3 本质上也是这个思路,只不过密钥交换用了 ECDHE 来保证前向安全性(即使长期私钥泄露,历史通信也无法解密)。
避坑指南
- 不要自己实现加密算法。我曾经见过同事手写了一个 RSA 加解密——跑起来是完全错误的,还拖慢了整个服务。用已经审定的库,比如 OpenSSL、BoringSSL、Go 标准库、Java JCA/JCE。
- 密钥管理远比算法选择重要。你再厉害的 AES-256,如果密钥硬编码在代码仓库里,就跟没加密一样。
- 定期轮换密钥。密钥用久了就有被暴力破解或侧信道攻击的风险。我记得有个合规要求里明文写着:对称密钥至少每 90 天更换一次。
这张图把三种加密方式的关系画得很清楚。左边是对称加密,右边是非对称加密,中间是混合加密的完整流程——这也是你在云加密 SDK 中实际会用到的模式。
总的来说,对称加密和非对称加密不是替代关系,而是互补关系。你在做云加密 SDK 选型时,核心就是搞清楚哪一步该用哪种加密,以及如何把它们组合起来。我自己的习惯是:能用 ECDH + AES-GCM 解决的方案,绝不硬套 RSA-OAEP。