Understand AES best practices, block padding, and modes

了解 AES 最佳实践、区块填充与模式

前言

AES(Advanced Encryption Standard)是最广泛使用的对称加密,HTTPS/TLS、Wi-Fi(WPA2/3)、全硬盘加密(BitLocker、FileVault)、ZIP/7z 压缩加密、消息应用(Signal、WhatsApp)都依赖它。通过理解 AES 如何运作有助于了解现代安全加密如何实践。

了解加密与 AES

为什么用 AES

所谓「对称加密算法」意味着对明文资料(PlainText)通过密钥(Key)进行运算生成密文(Cipher),也能反向操作。考虑到可行性,AES 是目前在「安全性、性能与硬件支持」之间取得最佳平衡的对称加密标准之一。

完美加密的配方

举例最简单经典的加密像是一次性密码本 (One-Time Pad, OTP),在电脑中任何资料可以视为一串 0 与 1,而通过与明文同长度、真随机、只使用一次的情况下与明文进行 XOR 运算,即使攻击者拥有无限的计算能力,也无法从密文推导出明文。

要达成完善保密性🔗条件非常严苛(如 OTP 几乎无法在实践中使用),Claude Shannon 提出的概念让我们能在「理论安全」与「实践可行」之间取得平衡:

  • 混淆(Confusion):隐藏密钥与密文之间的关系,使攻击者难以推导密钥
  • 扩散(Diffusion):让明文的每个位元影响到密文的多个位元,避免局部模式被保留

AES 运作原理

AES 是一种区块加密算法,固定一次处理 128 bit 的资料,而密钥有 128 / 192 / 256 bit 的大小。

  • 每次处理固定长度资料(128 bits = 16 bytes)
  • 使用同一把 Key 做加密与解密
  • 通过多轮转换让资料变得难以还原

AES 会把 16 bytes 的资料视为一个 4x4 矩阵:

[ a0 a4 a8 a12 ]
[ a1 a5 a9 a13 ]
[ a2 a6 a10 a14 ]
[ a3 a7 a11 a15 ]
  • SubBytes(位元替换)
  • ShiftRows(列位移)
  • MixColumns(栏混合)
  • AddRoundKey(加上密钥)

AES 运作模式

AES 本身只负责「加密一个区块」,但实际资料通常很长,因此需要「运作模式」来处理大量的区块加密:

ECB(Electronic Codebook,电码本模式)

每个区块独立加密,相同的明文区块产生相同的密文区块。这是最大的安全缺陷-加密图片时能直接看出原图的轮廓。实际开发不要使用。

CBC(Cipher Block Chaining,密码块连结模式)

每块明文先与上一块密文做 XOR,然后加密。第一块用随机产生的 IV(初始向量)代替。相同的明文 + 不同 IV → 完全不同的密文。缺点是必须串列加密,不能并行,是过去最常见的对称加密模式之一。

CTR(Counter,计数器模式)

把区块密码变成流密码:加密一个递增的计数器(Nonce + 计数),产生密钥流,再与明文 XOR。每块可以独立计算,支持完全并行,也不需要填充。注意:同一个 Nonce 绝对不能用两次。

GCM(Galois/Counter Mode)

在 CTR 基础上加了 GHASH 认证算法,可以产生一个 Auth Tag(认证标签)。解密时验证 Auth Tag,可以检测资料是否被篡改。同时提供加密和完整性认证,目前最推荐的模式,HTTPS/TLS 广泛使用。

CFB / OFB

两者也是将块密码变成流密码的变种,CFB 仰赖前一密文块(类似CBC),OFB 独立于密文,比较适合对实时性要求高的场景。

PKCS7 填充

缺几个 byte,就填几个值为「缺少数量」的 byte

区块加密有固定的大小,而 PKCS7 Padding 是一种区块加密的填充方式,用来让明文长度对齐区块大小。支持的区块大小:1 ~ 255 bytes 皆可,最常见搭配:AES(16 bytes 区块)

区块大小 = 8 bytes,明文 = HELLO(5 bytes)
原始: H E L L O
缺少: 3 bytes
填充后:H E L L O 03 03 03
再一个例子,明文 = HELLO123(刚好 8 bytes):
即使刚好对齐,也要加一个完整区块,否则解密时无法判断结尾:
H E L L O 1 2 3 | 08 08 08 08 08 08 08 08
缺 1 byte → 填 01
缺 2 bytes → 填 02 02
缺 5 bytes → 填 05 05 05 05 05
缺 16 bytes→ 填 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10

解密後如何去除 Padding?

读最后一个 byte 的值 → 去掉那么多个 byte

length := len(plaintext)
unpadding := int(plaintext[length-1])
plaintext = plaintext[:(length - unpadding)]

常见漏洞:Padding Oracle Attack🔗

如果系统在解密失败时回传不同的错误讯息,攻击者可以利用这个差异逐步还原明文,这就是 Padding Oracle Attack。

  • 使用 AES-GCM(不需要 padding 的 AEAD 模式)
  • 错误讯息不泄露 padding 是否正确

初始向量 IV

IV / Nonce 需「不可重复(unique)」,某些模式(如 CBC)还要求随机性

初始向量🔗(Initialization Vector,IV)是在加密过程中引入的一段随机资料,用来确保相同的明文在每次加密后产生不同的密文。

  1. 模式泄漏:为了避免攻击者观察特定密文块反复出现进而推断出对应的原文内容(Fixed IV Penguin)
  2. 重复使用:当相同的 IV 搭配相同的密钥被重复使用于加密,会造成 Many-Time Pad 问题

通常会以明文形式附加在加密资料的前端,因为解密端需要同一个 IV 才能还原第一块资料。

总结

正确的算法 + 正确使用 = 真正安全
  • 使用成熟的实践(标准函数库、成熟套件)
  • IV 可以公开但务必随机(至少密码学安全的伪随机数)
  • 密钥透过环境变量提供
  • 新专案优先用 AES-256-GCM;需要相容旧系统时用 AES-128-CBC + PKCS7;永远不要用 ECB。

延伸閱讀