对称加密与非对称加密:算法选型与场景对比
对称加密和非对称加密,说白了就是 KMS 的左右手。一个负责快,一个负责安全分发。我刚开始接触密钥管理时,觉得只要会用 AES 和 RSA 就万事大吉了,后来踩过不少坑——嗯,今天就把这些经验跟你聊聊。
对称加密:AES 为什么是默认选项
对称加密,加密和解密用同一把密钥。速度快,适合大数据量。但问题也明显:怎么把密钥安全送到对方手里?
在项目中,我几乎只用 AES。DES 早就被淘汰了,3DES 效率低,SM4 在国内合规场景才用。AES 支持 128、192、256 位密钥,我个人习惯直接上 AES-256——虽然慢一点,但在 KMS 场景下,密钥本身不是海量数据,安全冗余更重要。
重点:AES 有多个工作模式。ECB 模式不要用,因为它相同的明文会生成相同的密文,容易泄露模式。我用得最多的是 GCM 模式,自带认证标签,能防篡改。
再提一嘴密钥派生。你的 KMS 不会直接用主密钥去加密大量数据,而是先生成一个数据密钥(DEK),再用主密钥(KEK)去加密 DEK。这就是我常说的“密钥分层”——绕开对称加密的密钥分发难题。
非对称加密:RSA 与 ECC 的取舍
非对称加密用公钥加密、私钥解密,或私钥签名、公钥验签。它解决了密钥分发问题,但速度比对称加密慢几百倍。
目前在 KMS 里,RSA 和 ECC 是两大主力。RSA 大家很熟悉,密钥长度通常 2048 位或 4096 位。ECC(椭圆曲线加密)用更短的密钥达到相同安全强度,比如 256 位 ECC 和 3072 位 RSA 差不多。
我曾经在物联网项目中推过 ECC。设备端资源有限,RSA 2048 的签名验签太吃计算和存储,换成 ECC P-256 后,密钥体积小了 4 倍,运算时间降了 2/3。避坑指南:ECC 的曲线选择很关键,尽量用标准曲线(比如 NIST P-256、secp256k1),别自己造曲线。
算法选型对比表
| 特性 | AES (对称) | RSA (非对称) | ECC (非对称) |
|---|---|---|---|
| 密钥长度 | 128 / 256 位 | 2048 / 4096 位 | 256 / 384 位 |
| 运算速度 | 极快(硬件加速) | 慢(大数运算) | 中等(椭圆曲线运算) |
| 安全强度(等效) | AES-256 ≈ AES-256 | RSA-2048 ≈ AES-128 | ECC-256 ≈ AES-128 |
| 主要用途 | 批量数据加密 | 密钥封装、数字签名 | 密钥交换、数字签名 |
| 公钥/私钥 | 单一密钥 | 一对密钥 | 一对密钥 |
| 计算资源消耗 | 低 | 高(尤其解密/签名) | 中 |
| 典型应用场景 | 数据库字段加密、文件加密 | PKI、HTTPS 证书、数字签名 | 移动端/物联网认证、区块链 |
小建议:在 KMS 中,我一般用 AES-256-GCM 做数据加密,用 ECC P-256 做签名和密钥协商。只有在需要与老系统兼容时才保留 RSA 2048。别一上来就 RSA 4096,性能损耗不值得。
适用场景对比
你问我什么时候用对称、什么时候用非对称?其实它们不是二选一,而是配合使用。我见过不少刚入门的人,硬要用 RSA 加密整块大文件,结果性能崩了。
- 对称加密:适合加密体量较大的数据。比如:
- 数据库中的敏感字段(信用卡号、身份证)
- 云存储中的文件内容
- 实时通信的语音/视频流
- 非对称加密:适合小数据量、需要安全分发的场景。比如:
- 交换对称密钥(密钥封装)
- 数字签名(确保数据完整性和身份)
- 证书签发(PKI 体系)
实际上,KMS 最经典的模式就是“混合加密”:客户端用随机生成的 AES 密钥加密数据,然后用非对称加密(RSA 或 ECC)对 AES 密钥做封装。这样既发挥了对称加密的速度优势,又解决了密钥分发问题。
注意:不要用非对称加密去加密超过几百字节的数据。RSA 能加密的明文长度受密钥长度限制,比如 2048 位 RSA 一次最多只能加密 245 字节。超过的话,要么分段加密(极度不推荐),要么换思路——先对称加密,再封装密钥。
混合加密流程与算法关系
为了让你更直观地理解,我画了一张图。它展示了对称加密和非对称加密在 KMS 中的典型配合方式:
这张图里,发送方先生成一个临时 AES 密钥,用它对明文做对称加密得到密文;然后用接收方的公钥去加密这个 AES 密钥,得到“信封”。最后把密文和信封一起发给对方。接收方用自己的私钥解开信封拿到 AES 密钥,再用它解密得到明文。这么做,安全性由非对称加密保障,效率由对称加密兜底。
代码演示:Python 中的 AES + RSA 混合封装
下面是一小段 Python 代码,展示如何在 KMS 封装中实现混合加密。这段代码我经常在内部工具里复用:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
import os
# 1. 生成随机 AES-256 密钥
aes_key = os.urandom(32)
# 2. 用 AES-GCM 加密明文
iv = os.urandom(12)
cipher = Cipher(algorithms.AES(aes_key), modes.GCM(iv))
encryptor = cipher.encryptor()
ciphertext = encryptor.update(b"这是要加密的敏感数据") + encryptor.finalize()
tag = encryptor.tag # GCM 认证标签
# 3. 用接收方 RSA 公钥加密 AES 密钥(信封)
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
envelope = public_key.encrypt(
aes_key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
# 4. 模拟接收方:用私钥解信封,再用 AES 解密
recovered_key = private_key.decrypt(
envelope,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
cipher_dec = Cipher(algorithms.AES(recovered_key), modes.GCM(iv, tag))
decryptor = cipher_dec.decryptor()
plaintext = decryptor.update(ciphertext) + decryptor.finalize()
print("解密结果:", plaintext.decode())
经验之谈:注意 GCM 的 iv(又叫 nonce)我固定用 12 字节,这是推荐长度。别重复使用同一个 iv,否则认证标签失效。项目中我一般用计数器或 UUID 生成。
怎么样?对称加密和非对称加密其实不是对立关系,而是互补。选型时重点看数据量、性能要求和兼容性。我个人倾向:新项目起步就用 ECC + AES-GCM,需要对接旧系统再保留 RSA。避开 ECB,避开自己造轮子,KMS 调用时多用标准库——这些都是我从血泪教训中总结出来的。