2. 密钥类型与算法
刚接触密钥管理时,我总觉得算法选型是件挺简单的事——随便挑个流行的就行。结果第一个项目就踩了坑。后来才明白,不同类型的密钥和算法有各自的适用场景,选错了代价可不小。这一章我们就来掰开揉碎讲清楚。
2.1 对称密钥
对称密钥,说白了就是加密和解密用同一把钥匙。就像你家的门锁,一把钥匙既能锁门也能开门。优点是速度快,适合处理大量数据。缺点嘛,密钥分发是个大问题——你怎么安全地把这把钥匙交给对方?
我工作中最常用的对称算法是 AES(高级加密标准)。AES 支持 128、192、256 位密钥,目前推荐至少用 256 位。还有 SM4,国密标准,国内项目经常碰到。以下是常见对称算法的对比:
| 算法 | 密钥长度 | 分组大小 | 安全强度 | 典型场景 |
|---|---|---|---|---|
| AES | 128/192/256 | 128 | 高 | 文件加密、TLS |
| SM4 | 128 | 128 | 高(国密) | 政务、金融 |
| 3DES | 112/168 | 64 | 低(已弃用) | 遗留系统 |
| ChaCha20 | 256 | 流式 | 高 | 移动端、性能受限设备 |
代码示例:用 Python 的 cryptography 库实现 AES-256-GCM 加密:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os
key = os.urandom(32)
iv = os.urandom(12)
cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend())
encryptor = cipher.encryptor()
plaintext = b"这是需要加密的日志内容"
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
# 记录 IV 和密钥用于后续解密——注意 IV 不要硬编码
print("密文:", ciphertext.hex())
print("IV:", iv.hex())
2.2 非对称密钥
非对称密钥,又叫公钥密码体制。每对密钥包含公钥和私钥,公钥可以公开,私钥必须保密。加密用公钥,解密用私钥;签名用私钥,验签用公钥。正好解决了对称密钥的分发难题。
你想想看,两个人想安全通信,不需要提前共享秘密了——各自公布公钥,用对方公钥加密即可。代价是速度慢,通常只用来加密对称密钥或者做数字签名。
| 算法 | 密钥长度推荐 | 安全强度 | 特点 |
|---|---|---|---|
| RSA | 2048/4096 | 高 | 通用、广泛支持 |
| ECC(P-256) | 256 | 高 | 密钥短、性能好 |
| SM2 | 256 | 高(国密) | 国内合规需求 |
| DSA | 2048 | 中 | 仅签名、逐渐淘汰 |
我个人习惯,如果项目没有强制国密要求,优先选 ECDSA(P-256)做签名,RSA 做加密。ECC 的密钥只有 256 位,强度却跟 3072 位 RSA 相当,传输和存储都省。注意,Java 的 ECDSA 实现里有些库的随机数生成有坑——用 SP 800-90A 的 DRBG 别自己瞎造随机数。
from cryptography.hazmat.primitives.asymmetric import rsa, ec, padding
from cryptography.hazmat.primitives import serialization, hashes
# 生成 RSA 密钥对
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
# 导出 PEM 格式
pem_private = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
print(pem_private.decode())
2.3 哈希算法
哈希算法不是加密,它是单向函数——输入任意数据,输出固定长度摘要。你无法从摘要反推出原文。主要用途:数据完整性校验、密码存储、数字签名中的消息摘要。
为什么需要它?你想想,如果直接对几百 MB 的文件做非对称签名,性能扛不住。先哈希成 32 字节摘要,再签名,就快多了。
常用哈希函数:
| 算法 | 输出长度 | 安全状态 | 应用场景 |
|---|---|---|---|
| SHA-256 | 256 位 | 安全 | 通用、TLS、区块链 |
| SHA-3 | 224/256/384/512 | 安全 | 新一代标准 |
| SM3 | 256 位 | 安全(国密) | 国内合规 |
| MD5 | 128 位 | 不安全 | 仅用于非安全场景 |
import hashlib
data = b"这是日志行内容"
sha256_hash = hashlib.sha256(data).hexdigest()
print("SHA-256 摘要:", sha256_hash)
2.4 数字签名
数字签名结合了哈希和非对称加密。先对消息用哈希算法生成摘要,再用私钥对摘要加密(即签名)。其他人用公钥解密摘要,并与自己计算的消息摘要对比——匹配则签名有效。
它保证了三点:
- 认证——消息确实来自声称的发送方
- 完整性——消息未被篡改
- 不可否认性——发送方不能抵赖
常见的签名算法:RSA-PSS、ECDSA、SM2(签名模式)、Ed25519。我最近偏好 Ed25519,密钥短、速度快、实现更安全(没有 P-256 里那些随机数陷阱)。
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
# 使用 ECDSA P-256 签名
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()
message = b"这是一条合规日志"
signature = private_key.sign(
message,
ec.ECDSA(hashes.SHA256())
)
# 验签
try:
public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
print("签名验证通过!")
except Exception as e:
print("签名验证失败:", e)
2.5 四种技术的关系
最后用一张图梳理它们在整个密钥体系中的位置和作用:
简单总结:对称加密快,用来保护内容;非对称加密慢,用来安全交换密钥或做身份认证;哈希算法为签名提供摘要;数字签名则是两者的融合,实现认证、完整、不可否认。选型时,结合合规要求、性能、安全等级去权衡就好。我个人建议,只要没有遗留系统拖累,一律用 AES-256-GCM + ECDSA(P-256)+ SHA-256 这套组合,既安全又高效。