D
开发工具箱

AES 加密详解:对称加密的工业标准

加密解密 2026年6月15日 约 1 分钟阅读

什么是 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 轮变换、密钥扩展,一直到密文拼接输出:

AES-128:10 轮 AES-192:12 轮 AES-256:14 轮 明文(任意长度) P₁ P₂ P₃ Pₙ 每个块固定 128 位(16 字节) 最后一块不足则按 PKCS#7 填充 主密钥 K128 / 192 / 256 位 密钥扩展 Key Expansion单向派生,推不回主密钥 每一轮使用不同的轮密钥, 全部由主密钥单向派生 明文块 P(128 位) ⊕ K₀(初始轮密钥加) 状态矩阵 State 16 字节按列填入 每轮都在这 16 个字节上 反复做替换与置换 K₀ Round 1 SubBytes ShiftRows MixColumns ⊕ K₁ K₁ Round 2 SubBytes ShiftRows MixColumns ⊕ K₂ K₂ (Round 3 ~ Round 9,结构完全相同) Round 10(最后轮) SubBytes ShiftRows ⊕ K₁₀ 最后一轮省略 MixColumns K₁₀ 密文块 C(128 位) C₁ C₂ C₃ Cₙ 密文
图 1:AES 完整加密流程。明文按 128 位切块,每块先与初始轮密钥异或,再经过 N 轮变换(SubBytes → ShiftRows → MixColumns → ⊕ 轮密钥,最后一轮省略 MixColumns);每一轮的轮密钥都来自主密钥的单向扩展。点上面的「播放」可以看一步步的演示。

每轮做了些什么?

每一轮加密包含四个操作(第 10 轮省略 MixColumns):

  1. SubBytes:用 S-Box 做字节替换,这是 AES 的核心非线性变换。简单说就是把每个字节映射到另一个字节,让明文和密文之间的关系极度混乱
  2. ShiftRows:按行循环移位。第 0 行不动,第 1 行左移 1 个字节,第 2 行左移 2 个字节,第 3 行左移 3 个字节
  3. MixColumns:对列做矩阵乘法(在有限域 GF(2^8) 上运算),进一步打散
  4. AddRoundKey:把当前状态和轮密钥做 XOR(异或)

四步加起来的目的只有一个:让明文和密文的统计关系完全消失。攻击者哪怕知道加密算法,也没法从密文推断出密钥或明文。

我把这个过程想象成是一个多层搅拌机——SubBytes 是把食材打散,ShiftRows 和 MixColumns 是横向和纵向搅拌,AddRoundKey 是加入新的调料。每多搅拌一轮,原始食材的痕迹就更少一分。

用状态矩阵的视角看这一轮,会更直观。下面这张图里,我用蓝色方块跟踪 4 个字节,看它们在四步操作里怎么被搬来搬去:

输入状态16 字节明文块 SubBytes字节替换 替换后位置不变值全变 ShiftRows行移位 移位后第 n 行左移 n MixColumns列混合 混合后每列 4 字节混合 AddRoundKey⊕ 轮密钥 本轮输出整块 ⊕ 轮密钥 Kᵢ 轮密钥 Kᵢ 进入下一轮
图 2:一轮加密的四个步骤。128 位明文排成 4×4 的状态矩阵,依次做字节替换(位置不动、值全变)、行移位(第 n 行循环左移 n 字节)、列混合(每列在 GF(2⁸) 上做矩阵乘),最后与本轮轮密钥逐位异或,输出即下一轮的输入。点上面的「播放」可以看四个字节是怎么被一步步搬动的。

密钥扩展

加密用的每一轮密钥都不一样,但都来源于你输入的那把主密钥。AES 通过密钥扩展算法,从一把 128/192/256 位的种子密钥生成所有轮密钥。这个扩展算法是单向的——即使你知道某几轮的密钥也推不出原始密钥。

分组模式:不止是加密算法

AES 只定义了对一个 128 位块的加密方法,真实的数据远比 16 个字节长。怎么把 AES 用在长数据上?这就要靠分组密码模式(Mode of Operation)了。

ECB(电子密码本模式)

直接把数据切成 128 位块,每块独立用 AES 加密。同一个明文块永远产生同一个密文块。

如果你用 ECB 加密一张图片,像素模式会在密文里原样浮现出来——多年前那个”Linux 企鹅 ECB 加密后还能看清轮廓”的实验至今还在教科书里被引用。说白了,ECB 对大多数实际场景来说几乎等于没加密。我们工具里虽然支持 ECB 模式,但那更多是为了让你验证某种历史遗留系统,不是推荐你用它。

原因看这张图就明白了:

P₁ 与 P₃ 的明文完全相同 明文块 P₁内容:AAAAAAAA 明文块 P₂内容:BBBBBBBB 明文块 P₃内容:AAAAAAAA AES 加密密钥 K(同一把) AES 加密密钥 K(同一把) AES 加密密钥 K(同一把) 密文块 C₁7f3a9c…(与 C₃ 相同) 密文块 C₂b21e40… 密文块 C₃7f3a9c…(与 C₁ 相同) → 密文块也完全相同:明文的重复结构被完整保留下来 原图 ECB 后 图案结构完整保留 只是换了个颜色
图 3:ECB 模式。每个块用同一把密钥独立加密、互不影响,于是相同的明文块必然得到相同的密文块。右边就是教科书里那个著名的实验:整张图用 ECB 加密后,颜色变了,企鹅的轮廓却依然清晰可见。点上面的「播放」可以看这个过程。

CBC(密码块链接模式)

CBC 改进了一个关键点:每个块的加密结果会影响下一个块。在加密当前块之前,先把前一个块的密文和当前块的明文做 XOR。第一个块没有前一个密文怎么办?用一个叫 IV(初始化向量)的随机数顶替。

这样,哪怕两个块明文完全一样,只要位置不同,密文就不同。

(a)CBC 加密 (b)CBC 解密 IV 随机、不可预测 无需保密但不能重用 明文块 P₁ AES 加密密钥 K 密文块 C₁ 明文块 P₂ AES 加密密钥 K 密文块 C₂ 上一块密文 明文块 P₃ AES 加密密钥 K 密文块 C₃ 密文块 C₁ 密文块 C₂ 密文块 C₃ AES 解密密钥 K AES 解密密钥 K AES 解密密钥 K IV 明文块 P₁ 明文块 P₂ 明文块 P₃ 上一块密文 同一个 IV ⚠ 只保证机密性:密文可被篡改而你毫无察觉,建议改用 GCM 或补一层 HMAC
图 4:CBC 模式。加密时每块先与上一个密文块(第一块用 IV)异或再走 AES,所以加密必须串行、无法并行;解密时密文块是已知的,可以并行计算,代价是一个块损坏会波及相邻两个块。注意它只保证机密性,没有任何完整性校验。点上面的「播放」可以看链条是怎么一节节搭起来的。

但 CBC 有一个致命问题:它没有内置完整性校验,可以被 padding oracle 攻击。换句话说,别人可以篡改你的 CBC 密文,而你解密时毫无察觉。

GCM(伽罗瓦计数器模式)

我个人推荐的生产级选择。GCM 内部用 CTR(计数器)模式做加密,同时利用 GHASH 算法计算认证标签,提供认证加密(AEAD,Authenticated Encryption with Associated Data)。

翻译成人话:GCM 不仅能保证机密性,还能检测密文是否被篡改。如果有人动了你的密文哪怕一个字节,认证标签就对不上了,你能立刻知道数据被改过。

这也是为什么 TLS 1.3 强制使用 AEAD 模式——光加密不够,还得验证完整性。

Nonce / IV12 字节,绝对不可重用 密钥 K所有块共用同一把 CTRᵢ = Nonce ‖ 32 位计数器(每块 +1) CTR₁ CTR₂ CTR₃ AES 加密 K AES 加密 K AES 加密 K 各块互不依赖,可并行计算 S₁ S₂ S₃ 密钥流 P₁ P₂ P₃ 明文块 C₁ C₂ C₃ 密文块 H = AES(K, 0¹²⁸)GHASH 子密钥 AAD 附加数据可选,只认证不加密 GHASH(H):AAD ‖ C₁ ‖ C₂ ‖ C₃ ‖ 长度在 GF(2¹²⁸) 上做带密钥的认证计算 ⊕ S₀ S₀ = 计数器 0 的密钥流 认证标签 Tag 解密时先验 Tag, 不匹配直接拒绝解密
图 5:GCM 模式。计数器块经 AES 加密产生密钥流,与明文块异或得到密文——各块互不依赖,可以并行;同时用 GHASH 把 AAD、所有密文块和长度一起算出认证标签。密文被改动一个字节,标签就对不上,解密方立刻能发现。点上面的「播放」可以看加密与认证两条线是怎么同时跑的。

核心特性

特性说明
类型对称分组密码
分组大小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

AESDESChaCha20
类型分组密码分组密码流密码
密钥长度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。