对称加密算法基础:AES 和 DES

对称加密,说白了就是加密和解密用同一把钥匙。你在网上看到的 HTTPS、文件加密、数据库字段加密,底层绝大多数都是它。今天咱们就把 AES 和 DES 这两个老大哥聊透。

DES:时代的眼泪,但值得了解

DES(Data Encryption Standard)诞生于上世纪 70 年代,IBM 搞出来的,后来被 NIST 采纳为标准。密钥长度 56 位,分组长度 64 位,用 Feistel 网络结构,16 轮迭代。

我在早期接触加密 SDK 的时候,还见过一些遗留系统用 DES。当时客户说「这个加密跑了好几年了,别动它」。嗯,我打开源码一看,硬编码的密钥,56 位,心里咯噔一下——这玩意儿用现代显卡暴力破解,几个小时就能跑出来。

避坑指南: 我曾在一次合规审计中,发现某个金融交易系统还在用 DES 对账。整改方案不是升级密钥,而是直接替换成 AES-256。为什么?因为 56 位密钥的有效强度只有 2^56,而 2017 年一台专用机就能在一天内遍历。

AES:当今的王者

AES(Advanced Encryption Standard)接过了 DES 的班。它也叫 Rijndael 算法,由比利时两位密码学家设计。密钥长度支持 128、192、256 位,分组长度固定 128 位。

AES 用的是 SPN(Substitution-Permutation Network)结构,不是 Feistel。所以加密和解密的流程不对称,实现上得更小心。我个人习惯用 OpenSSL 或者各语言自带的 AES 实现,绝不自己造轮子。

特性DES3DESAES-128AES-256
密钥长度56 位112 或 168 位128 位256 位
分组长度64 位64 位128 位128 位
轮数1616×31014
结构FeistelFeistelSPNSPN
安全等级已不推荐逐步弃用安全最高
常见场景遗留系统旧版支付Web、数据库金融、政务

几个关键概念,绕不开的坑

分组密码的工作模式

AES 和 DES 都是分组密码,一次加密一个固定长度的块。但你加密的数据长度不一定正好是 128/64 的整数倍,所以需要 填充。常用的有 PKCS7 填充。

填充之后还涉及模式:

  • ECB:简单粗暴,每个块独立加密。但相同的明文块会变成相同的密文块,有信息泄漏风险。我见过一个图像加密的例子,用 ECB 加密后,图片轮廓居然还依稀可见……
  • CBC:每个块跟上一个密文块异或后再加密。需要初始向量 IV。我个人项目中几乎只用 CBC 或 GCM。
  • GCM:CBC 的升级版,自带完整性校验。适合需要认证加密的场景,比如 HTTPS 的 TLS 1.3。
我的习惯: 除非有特殊的合规要求,否则一律用 AES-256-GCM。密钥和 IV 分开管理,IV 每次随机生成,随密文一起存储。GCM 自带认证标签,能防篡改,省去额外计算 MAC 的步骤。

密钥管理

算法再强,密钥丢了全白搭。我建议用硬件安全模块(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 / CBC PKCS7填充 / 随机IV 认证标签校验 SDK内部将对称加密与脱敏规则组合:先加密敏感字段,再应用脱敏模板

这张图展示的是我们在 SDK 中的典型链路。上层业务调用加密接口,SDK 内部先判断用哪个算法(比如对内存中的敏感数据用 AES-256-GCM),然后从密钥管理模块取密钥,最后把加密结果交给脱敏规则引擎,决定是否脱敏展示。你想想看,如果不分层,所有逻辑耦合在一起,要换个算法就得改业务代码——我吃过这种亏,那次重构差点把我的头发薅光。

我踩过的三个坑

  1. IV 重用:CBC 和 GCM 模式下,如果 IV 重复,加密强度直接归零。我在一个日志系统里见过有人用固定 IV,明文相似度高的地方密文也相似,被审计查出来了。
  2. 密钥变更:曾经有个项目,运维手抖把数据库密钥换了,第二天所有历史数据都解不开。幸好我们有备份密钥版本号,回退才恢复。从那以后我强制要求 SDK 支持密钥轮换和多版本。
  3. 填充攻击:CBC 模式如果解密时填充校验失败就返回错误,攻击者可以通过错误信息推断明文(Padding Oracle Attack)。我建议直接用 GCM,或者自己实现统一错误响应。

一句话总结: 对称加密里,AES-256-GCM 是目前最稳妥的选择。DES 和 3DES 该退休了,别犹豫。密钥管理和 IV 随机性比算法本身更值得关注。