对称加密算法基础:AES 和 DES
对称加密,说白了就是加密和解密用同一把钥匙。你在网上看到的 HTTPS、文件加密、数据库字段加密,底层绝大多数都是它。今天咱们就把 AES 和 DES 这两个老大哥聊透。
DES:时代的眼泪,但值得了解
DES(Data Encryption Standard)诞生于上世纪 70 年代,IBM 搞出来的,后来被 NIST 采纳为标准。密钥长度 56 位,分组长度 64 位,用 Feistel 网络结构,16 轮迭代。
我在早期接触加密 SDK 的时候,还见过一些遗留系统用 DES。当时客户说「这个加密跑了好几年了,别动它」。嗯,我打开源码一看,硬编码的密钥,56 位,心里咯噔一下——这玩意儿用现代显卡暴力破解,几个小时就能跑出来。
AES:当今的王者
AES(Advanced Encryption Standard)接过了 DES 的班。它也叫 Rijndael 算法,由比利时两位密码学家设计。密钥长度支持 128、192、256 位,分组长度固定 128 位。
AES 用的是 SPN(Substitution-Permutation Network)结构,不是 Feistel。所以加密和解密的流程不对称,实现上得更小心。我个人习惯用 OpenSSL 或者各语言自带的 AES 实现,绝不自己造轮子。
| 特性 | DES | 3DES | AES-128 | AES-256 |
|---|---|---|---|---|
| 密钥长度 | 56 位 | 112 或 168 位 | 128 位 | 256 位 |
| 分组长度 | 64 位 | 64 位 | 128 位 | 128 位 |
| 轮数 | 16 | 16×3 | 10 | 14 |
| 结构 | Feistel | Feistel | SPN | SPN |
| 安全等级 | 已不推荐 | 逐步弃用 | 安全 | 最高 |
| 常见场景 | 遗留系统 | 旧版支付 | Web、数据库 | 金融、政务 |
几个关键概念,绕不开的坑
分组密码的工作模式
AES 和 DES 都是分组密码,一次加密一个固定长度的块。但你加密的数据长度不一定正好是 128/64 的整数倍,所以需要 填充。常用的有 PKCS7 填充。
填充之后还涉及模式:
- ECB:简单粗暴,每个块独立加密。但相同的明文块会变成相同的密文块,有信息泄漏风险。我见过一个图像加密的例子,用 ECB 加密后,图片轮廓居然还依稀可见……
- CBC:每个块跟上一个密文块异或后再加密。需要初始向量 IV。我个人项目中几乎只用 CBC 或 GCM。
- GCM:CBC 的升级版,自带完整性校验。适合需要认证加密的场景,比如 HTTPS 的 TLS 1.3。
密钥管理
算法再强,密钥丢了全白搭。我建议用硬件安全模块(HSM)或密钥管理服务(KMS),不要硬编码密钥。你想想看,如果密钥写在代码里被 push 到 GitHub……那画面太美不敢看。
性能对比
现代 CPU 都有 AES 指令集(AES-NI),硬件加速后 AES-128 的速度可以超过 1 GB/s。DES 没有硬件加速,慢得多。所以别再纠结「DES 更快」这种老观念了。
实战:AES-256-GCM 代码示例
// 伪代码,实际语言取决于你的 SDK
function encryptAesGcm(plaintext, key) {
iv = randomBytes(12); // GCM 推荐 12 字节 IV
cipher = new AESGCM(key, iv);
ciphertext, tag = cipher.encrypt(plaintext, aad);
return iv + ciphertext + tag; // 一起返回
}
function decryptAesGcm(cipherBlob, key) {
iv = cipherBlob[0:12];
ciphertext = cipherBlob[12:-16];
tag = cipherBlob[-16:];
cipher = new AESGCM(key, iv);
return cipher.decrypt(ciphertext, aad, tag);
}
注意 aad(附加认证数据)可以传空,也可以传像用户 ID 之类的上下文。解密时如果 tag 校验失败,立刻抛异常,别返回任何数据——这能防住很多 oracle 攻击。
对称加密在 SDK 中的定位
这张图展示的是我们在 SDK 中的典型链路。上层业务调用加密接口,SDK 内部先判断用哪个算法(比如对内存中的敏感数据用 AES-256-GCM),然后从密钥管理模块取密钥,最后把加密结果交给脱敏规则引擎,决定是否脱敏展示。你想想看,如果不分层,所有逻辑耦合在一起,要换个算法就得改业务代码——我吃过这种亏,那次重构差点把我的头发薅光。
我踩过的三个坑
- IV 重用:CBC 和 GCM 模式下,如果 IV 重复,加密强度直接归零。我在一个日志系统里见过有人用固定 IV,明文相似度高的地方密文也相似,被审计查出来了。
- 密钥变更:曾经有个项目,运维手抖把数据库密钥换了,第二天所有历史数据都解不开。幸好我们有备份密钥版本号,回退才恢复。从那以后我强制要求 SDK 支持密钥轮换和多版本。
- 填充攻击:CBC 模式如果解密时填充校验失败就返回错误,攻击者可以通过错误信息推断明文(Padding Oracle Attack)。我建议直接用 GCM,或者自己实现统一错误响应。
一句话总结: 对称加密里,AES-256-GCM 是目前最稳妥的选择。DES 和 3DES 该退休了,别犹豫。密钥管理和 IV 随机性比算法本身更值得关注。