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 流式 高 移动端、性能受限设备
小技巧: 对称加密一定要搭配 GCM / CCM 等认证加密模式,不要直接用 ECB。我在项目中曾图省事用了 ECB,结果密文里能看出明文轮廓……后来被审计点名整改。

代码示例:用 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())
警告: 对称密钥不能硬编码在代码里!我曾经接手过一个项目,密钥直接写在配置文件中,git 仓库还没做 .gitignore……结果整个部门被安全团队约谈。

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())
密钥长度建议: 现在 RSA 至少要 2048 位,4096 位更稳妥但性能折半。ECC 推荐 P-256(secp256r1),P-384 用于更高安全等级。

2.3 哈希算法

哈希算法不是加密,它是单向函数——输入任意数据,输出固定长度摘要。你无法从摘要反推出原文。主要用途:数据完整性校验、密码存储、数字签名中的消息摘要。

为什么需要它?你想想,如果直接对几百 MB 的文件做非对称签名,性能扛不住。先哈希成 32 字节摘要,再签名,就快多了。

常用哈希函数:

算法 输出长度 安全状态 应用场景
SHA-256 256 位 安全 通用、TLS、区块链
SHA-3 224/256/384/512 安全 新一代标准
SM3 256 位 安全(国密) 国内合规
MD5 128 位 不安全 仅用于非安全场景
避坑: 千万不要在安全场景用 MD5 或 SHA-1。我曾经做过一个日志完整性校验系统,刚开始用的 SHA-1,后来同事提醒 SHA-1 已有碰撞攻击实践……吓得我连夜改成了 SHA-256。
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 里那些随机数陷阱)。

经验: 签名验签要注意 编码一致性。有一次我签名时用了 PEM 格式,验签时却用 DER 解析,折腾了半天才发现。建议团队统一用 DER(二进制)或统一用 PEM。
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 / SM4 / ChaCha20 非对称密钥 RSA / ECC / SM2 哈希算法 SHA-256 / SM3 数字签名 RSA-PSS / ECDSA / SM2签名 / Ed25519 加密对称密钥 提供摘要 私钥签名 · 公钥验签 摘要输入 应用流程示例: ① 对称加密日志数据 → ② 非对称加密对称密钥 → ③ 哈希摘要 + 签名 → ④ 发送方不可否认

简单总结:对称加密快,用来保护内容;非对称加密慢,用来安全交换密钥或做身份认证;哈希算法为签名提供摘要;数字签名则是两者的融合,实现认证、完整、不可否认。选型时,结合合规要求、性能、安全等级去权衡就好。我个人建议,只要没有遗留系统拖累,一律用 AES-256-GCM + ECDSA(P-256)+ SHA-256 这套组合,既安全又高效。