第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 的数据,也不会只用对称不停交换密钥。所以就有了混合加密方案。

流程大概是:

  1. 生成一个临时的对称密钥(比如 AES-256 的 32 字节密钥)
  2. 用接收方的公钥(RSA 或 ECC 公钥)加密这个临时密钥
  3. 用这个对称密钥加密实际数据
  4. 把加密后的临时密钥 + 加密数据一起发送
  5. 接收方先用自己的私钥解开临时密钥,再用它解密数据

TLS 1.3 本质上也是这个思路,只不过密钥交换用了 ECDHE 来保证前向安全性(即使长期私钥泄露,历史通信也无法解密)。

避坑指南

  • 不要自己实现加密算法。我曾经见过同事手写了一个 RSA 加解密——跑起来是完全错误的,还拖慢了整个服务。用已经审定的库,比如 OpenSSL、BoringSSL、Go 标准库、Java JCA/JCE。
  • 密钥管理远比算法选择重要。你再厉害的 AES-256,如果密钥硬编码在代码仓库里,就跟没加密一样。
  • 定期轮换密钥。密钥用久了就有被暴力破解或侧信道攻击的风险。我记得有个合规要求里明文写着:对称密钥至少每 90 天更换一次。
对称与非对称加密核心对比与混合加密流程 对称加密 vs 非对称加密 & 混合加密流程 对称加密(AES、SM4、ChaCha20) • 加解密使用同一把密钥 • 速度快,适合批量数据 • 密钥分发困难 • 密钥长度:128-256 bit • 常见模式:GCM > CBC > ECB(❌) 非对称加密(RSA、ECC/ECDSA) • 公钥加密 / 私钥解密 • 速度慢,适合小数据量 • 公钥可公开,密钥分发易 • 密钥长度:2048-4096 bit • 用于签名、密钥交换 混合加密(Hybrid Encryption)—— 现实中最优解 ① 生成临时密钥 ② 公钥加密密钥 ③ 对称加密数据 ④ 私钥解密密钥 ⑤ 解密数据 典型应用:TLS 1.3 密钥交换(ECDHE)+ 数据加密(AES-GCM) 密钥管理比算法选择更重要 —— 密钥分层、定期轮换、硬件安全模块(HSM) 对称加密适用于高性能场景,非对称加密解决密钥分发难题 混合加密结合两者优势,是实际工程中的标准做法 选型建议:批量数据用 AES-GCM / SM4-GCM;数字签名用 ECDSA / SM2;密钥交换用 ECDH / SM2

这张图把三种加密方式的关系画得很清楚。左边是对称加密,右边是非对称加密,中间是混合加密的完整流程——这也是你在云加密 SDK 中实际会用到的模式。

总的来说,对称加密和非对称加密不是替代关系,而是互补关系。你在做云加密 SDK 选型时,核心就是搞清楚哪一步该用哪种加密,以及如何把它们组合起来。我自己的习惯是:能用 ECDH + AES-GCM 解决的方案,绝不硬套 RSA-OAEP。