AES 加密详解:对称加密的工业标准
什么是 AES?
AES(Advanced Encryption Standard,高级加密标准)是目前全球使用最广泛的对称加密算法。说白了,就是加密和解密用同一把钥匙。
你每天上网时,HTTPS 连接里的数据加密、WiFi 的 WPA2/WPA3、文件加密工具(如 VeraCrypt 和 BitLocker),乃至你手机的全盘加密,大概率都在用 AES。
把 AES 放进历史坐标里来看——它的前身是 DES(数据加密标准),DES 出生于 1977 年,搞了 20 多年后,56 位的密钥长度在当时的计算能力面前已经撑不住了。1997 年,NIST(美国国家标准与技术研究院)发起了 AES 算法征集,最终来自比利时的 Rijndael 算法胜出,2002 年正式成为标准。
值得一提的是,Rijndael 的两位设计者——Joan Daemen 和 Vincent Rijmen,他们把算法设计得非常优雅:硬件上高效、软件上灵活,而且能抵抗当时已知的所有攻击方法。说实话,一个 1998 年设计的算法到现在还能扛住攻击,说明它是真的扎实。
AES 的工作原理
AES 属于分组密码(Block Cipher),它不是对数据流按位加密,而是把数据切成固定大小的块——每个块正好 128 位(16 字节),然后对每一块独立加密。
加密轮数
AES 有三种密钥长度,对应的加密轮数也不同:
| 密钥长度 | 轮数 | 常见称呼 |
|---|---|---|
| 128 位(16 字节) | 10 轮 | AES-128 |
| 192 位(24 字节) | 12 轮 | AES-192 |
| 256 位(32 字节) | 14 轮 | AES-256 |
轮数越多安全性越高,但性能也越低。一般来说 AES-128 已经足够安全(2^128 的暴力搜索空间在可预见的未来都不现实),AES-256 主要用于合规要求或特别敏感的场景。
上面那张表只说了轮数,下面这张图把整个过程从头到尾串起来——从分块、初始轮密钥加、N 轮变换、密钥扩展,一直到密文拼接输出:
每轮做了些什么?
每一轮加密包含四个操作(第 10 轮省略 MixColumns):
- SubBytes:用 S-Box 做字节替换,这是 AES 的核心非线性变换。简单说就是把每个字节映射到另一个字节,让明文和密文之间的关系极度混乱
- ShiftRows:按行循环移位。第 0 行不动,第 1 行左移 1 个字节,第 2 行左移 2 个字节,第 3 行左移 3 个字节
- MixColumns:对列做矩阵乘法(在有限域 GF(2^8) 上运算),进一步打散
- AddRoundKey:把当前状态和轮密钥做 XOR(异或)
四步加起来的目的只有一个:让明文和密文的统计关系完全消失。攻击者哪怕知道加密算法,也没法从密文推断出密钥或明文。
我把这个过程想象成是一个多层搅拌机——SubBytes 是把食材打散,ShiftRows 和 MixColumns 是横向和纵向搅拌,AddRoundKey 是加入新的调料。每多搅拌一轮,原始食材的痕迹就更少一分。
用状态矩阵的视角看这一轮,会更直观。下面这张图里,我用蓝色方块跟踪 4 个字节,看它们在四步操作里怎么被搬来搬去:
密钥扩展
加密用的每一轮密钥都不一样,但都来源于你输入的那把主密钥。AES 通过密钥扩展算法,从一把 128/192/256 位的种子密钥生成所有轮密钥。这个扩展算法是单向的——即使你知道某几轮的密钥也推不出原始密钥。
分组模式:不止是加密算法
AES 只定义了对一个 128 位块的加密方法,真实的数据远比 16 个字节长。怎么把 AES 用在长数据上?这就要靠分组密码模式(Mode of Operation)了。
ECB(电子密码本模式)
直接把数据切成 128 位块,每块独立用 AES 加密。同一个明文块永远产生同一个密文块。
如果你用 ECB 加密一张图片,像素模式会在密文里原样浮现出来——多年前那个”Linux 企鹅 ECB 加密后还能看清轮廓”的实验至今还在教科书里被引用。说白了,ECB 对大多数实际场景来说几乎等于没加密。我们工具里虽然支持 ECB 模式,但那更多是为了让你验证某种历史遗留系统,不是推荐你用它。
原因看这张图就明白了:
CBC(密码块链接模式)
CBC 改进了一个关键点:每个块的加密结果会影响下一个块。在加密当前块之前,先把前一个块的密文和当前块的明文做 XOR。第一个块没有前一个密文怎么办?用一个叫 IV(初始化向量)的随机数顶替。
这样,哪怕两个块明文完全一样,只要位置不同,密文就不同。
但 CBC 有一个致命问题:它没有内置完整性校验,可以被 padding oracle 攻击。换句话说,别人可以篡改你的 CBC 密文,而你解密时毫无察觉。
GCM(伽罗瓦计数器模式)
我个人推荐的生产级选择。GCM 内部用 CTR(计数器)模式做加密,同时利用 GHASH 算法计算认证标签,提供认证加密(AEAD,Authenticated Encryption with Associated Data)。
翻译成人话:GCM 不仅能保证机密性,还能检测密文是否被篡改。如果有人动了你的密文哪怕一个字节,认证标签就对不上了,你能立刻知道数据被改过。
这也是为什么 TLS 1.3 强制使用 AEAD 模式——光加密不够,还得验证完整性。
核心特性
| 特性 | 说明 |
|---|---|
| 类型 | 对称分组密码 |
| 分组大小 | 128 位(固定) |
| 密钥长度 | 128 / 192 / 256 位 |
| 安全性 | 无已知的有效密钥恢复攻击(旁路攻击除外) |
| 性能 | 现代 CPU 大多有硬件 AES-NI 指令集加速 |
| 标准化 | FIPS PUB 197、ISO/IEC 18033-3 |
特别说一句 AES-NI。Intel 和 AMD 从 2010 年前后开始在 CPU 里集成了专门的 AES 硬件指令。开了 AES-NI 之后,AES 加密吞吐量能提升好几倍,甚至几十倍。你在服务器上跑加密操作的时候,其实大部分时间开销不在加密本身,在网络或 I/O 上。
实际应用场景
1. TLS/HTTPS
TLS 1.3 把对称加密算法选项精简到了只剩 AEAD 模式。AES-GCM 和 AES-CCM 是其中最常见的两种。你访问任何一个 HTTPS 网页,浏览器和服务器握手时会协商使用哪种对称加密,AES-GCM 往往是首选。
2. 全盘加密
BitLocker(Windows)、FileVault(macOS)、LUKS/dm-crypt(Linux)都用到了 AES。这个场景里,加密和I/O 要同时进行,AES-NI 硬件加速就特别关键。
3. 数据库字段加密
像身份证号、银行卡号这类敏感字段,很多合规要求里要求”静态加密”。应用层先 AES-GCM 加密再存库,即使数据库泄露了,数据也是密文状态。
不过说实话,密钥管理才是这个场景里最难的部分——密钥放配置文件里有泄露风险,放密钥管理服务里又增加运维负担。很多人实现字段加密时,把密钥和密文存在同一个数据库里,这跟没加密没什么两样。
4. 无线安全
WPA2 用 AES-CCMP(CCM 模式),WPA3 强制使用 AES。你连 WiFi 输入密码之后的所有通信,都是由 AES 在硬件层面保护的。
5. AWS S3 服务端加密
S3 的 SSE-S3 模式在写入数据之前自动用 AES-256 加密。对用户完全透明——你照常读写,加密发生在存储层。
常见误区
误区一:AES-256 一定比 AES-128 更安全
对暴力搜索来说,是的。但 AES-256 的密钥扩展更复杂,在某些微架构攻击场景下反而可能更弱(比如相关密钥攻击)。对于绝大多数应用来说 AES-128 绰绰有余,AES-256 更多是为了满足严格的合规标准。
误区二:选对算法就行了,模式不重要
一个选了 ECB 模式的 AES-256 加密,安全性不如选了 CBC 模式的 AES-128。算法和模式要一起考虑。我之前审一个外包项目的代码,发现他们用 AES-256-ECB 来加密用户密码——密钥倒是够强,但 ECB 的问题让攻击者可以重放和替换密文块。
误区三:AES 加密后不需要完整性校验
CBC 和 ECB 模式下,攻击者可以修改密文而不被发现。你的解密程序会”成功”解出点什么——只不过已经被篡改过了。这就是为什么密码学里的共识是:加密一定要配认证。要么用 GCM/CCM,要么在加密模式之外套一个 HMAC。
AES vs DES vs ChaCha20
| AES | DES | ChaCha20 | |
|---|---|---|---|
| 类型 | 分组密码 | 分组密码 | 流密码 |
| 密钥长度 | 128/192/256 位 | 56 位 | 256 位 |
| 分组大小 | 128 位 | 64 位 | 无(流密码) |
| 安全强度 | 高 | 低(可暴力破解) | 高 |
| 硬件加速 | AES-NI | 无 | 无 |
| 主要场景 | TLS、全盘加密、数据库加密 | 遗留系统 | 移动端、TLS 备用 |
ChaCha20 是 Google 在移动设备上推的替代方案。因为很多移动 CPU 没有 AES-NI 指令集,跑 AES 比较吃力,而 ChaCha20 是专门为软件实现优化设计的,性能反而更好。
常见问题
Q: AES 密钥到底要多长才够?
128 位对于 99% 的应用场景已经够了。2^128 次尝试,就算用地球上所有计算力并行,也要耗尽宇宙的寿命。选 256 位更多是商业合规需求(比如 FIPS 140-2 某些级别要求 AES-256),而非实际安全需要。
Q: 初始化向量 IV 可以重用吗?
对于 CBC 模式,IV 可以公开但不能预测、不能重用。对于 GCM 模式,IV(也叫 nonce)绝对不可以重用——一旦重用,攻击者可以直接恢复认证密钥。如果有任何概率发生 nonce 重复(比如用随机 nonce 又高频调用),建议用 AES-GCM-SIV 这类抗 nonce 重用的变体。
Q: 自己实现 AES 安全吗?
千万别。算法虽然公开,但实现中的旁路攻击(时序攻击、缓存攻击、功耗分析)防不胜防。用经过审计的库(OpenSSL、libsodium、Web Crypto API),不要自己写 AES 实现,除非你的目的就是学习和研究。
Q: 密码学里说的”语义安全”是什么意思?
简单讲:同一个明文加密两次,得到的密文要不一样,否则攻击者就能通过比较密文推断明文。CBC 和 GCM 模式的随机 IV 就保证了这一点,ECB 不满足语义安全就是因为同一个明文块永远出同一个密文块。
Q: 为什么 Web Crypto API 中 AES-CBC 不推荐了?
Chrome 从某个版本起对 SubtleCrypto.encrypt 使用 AES-CBC 时打出了控制台警告。原因是 CBC 没有内置认证,容易出 padding oracle 漏洞。现在推荐用 AES-GCM 或者 AES-CTR + HMAC 的组合(Encrypt-then-MAC)。工具的加密工具也保留了 CBC 模式,但建议优先选 GCM。