AES 的 PKCS#7 填充:原理、示例与安全解填充

加密# AES# PKCS#7# 填充# CBC
作者 HSM Kit Editorial Team技术审阅 HSM Kit Security Review Team最后审阅: 2026年9月22日5 分钟阅读
现在需要计算吗?
使用我们免费的在线 AES 加密工具 工具。

AES 每次处理 16 字节分组,因此 CBC 模式需要一套可逆规则来处理长度不是 16 倍数的明文。PKCS#7 通过追加字节完成填充,每个填充字节的值都表示填充长度。规则本身很简单,但错误验证可能产生严重的填充预言机漏洞。

PKCS#7 填充规则

设分组大小为 B 字节、明文长度为 L,需要添加的字节数为:

N = B - (L mod B)

追加 N 个字节,每个字节的数值都为 N。AES 的 B 固定为 16,所以 N 的取值范围是 1–16。

示例:5 字节明文

ASCII 字符串 HELLO 长 5 字节,需要追加 11 个 0x0B

48 45 4C 4C 4F 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B

解密后,最后一个字节表示追加了 11 字节。删除前必须确认最后 11 个字节全部等于 0x0B

为什么整分组明文仍需填充

当明文长度已经是 16 的倍数时,PKCS#7 仍会添加完整填充分组:

10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10

如果不添加该分组,接收方无法判断末尾的 0x01 是真实数据还是填充。PKCS#7 要求每条消息都包含填充,从而避免歧义。

这也是常见长度误区:16 字节明文使用 AES-CBC + PKCS#7 后会形成两个密文分组,此外还需单独计算 IV 的长度。

有效与无效填充

对 AES 而言,以下结尾有效:

... 01
... 02 02
... 03 03 03
... 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10

以下结尾无效:

... 00             # 0 不是有效填充长度
... 02 03          # 字节与声明长度不一致
... 11 ...         # 17 超过 AES 的 16 字节分组

解码器必须拒绝无效填充。只读取最后一个值便直接裁剪,会导致数据损坏并降低安全性。

PKCS#5 与 PKCS#7 的区别

API 经常混用这两个名称,但原始定义不同:

  • PKCS#5 填充最初针对 8 字节分组;
  • PKCS#7/CMS 填充支持 1–255 字节分组;
  • AES 分组是 16 字节,因此准确名称是 PKCS#7 填充。

部分 Java Provider 对 AES 暴露 PKCS5Padding 名称,内部实际执行通用 PKCS#7 规则。互操作时应查阅 Provider 文档,而不是只看算法字符串。

哪些 AES 模式需要填充

模式是否需要 PKCS#7原因
CBC任意长度数据需要只处理完整分组
ECB任意长度数据需要只处理完整分组
CTR不需要输出字节流
GCM不需要基于计数器的认证模式
CFB / OFB不需要以类似流密码方式运行

如果密码库已经自动应用 PKCS#7,不要再手工填充。双重填充会导致解填充一次后仍残留一层填充数据。

填充预言机风险

填充不等于认证。在 CBC 中,修改一个密文分组会以可预测方式改变下一个解密明文分组。如果服务会泄露填充是否有效,攻击者就能通过大量请求逐字节恢复明文,而无需知道密钥。

泄露信号可能是直接或间接的:

  • 无效填充与无效 JSON 返回不同错误;
  • 使用不同 HTTP 状态码;
  • 响应时间存在可测差异;
  • 解密失败后的连接行为不同。

首选修复方案是改用 AES-GCM 等认证加密。必须兼容 CBC 时,应采用 Encrypt-then-MAC,对版本、IV 与密文计算认证码,并在解密前验证 MAC。两种模式的差异见 AES-GCM 与 AES-CBC 对比

安全解填充

应用代码通常应调用维护良好的密码库,而不是自己实现解填充。正确流程应当:

  1. 在 CBC 解密前完成密文认证;
  2. 确认解密结果长度非零且是分组大小的倍数;
  3. 读取最后一个填充长度,要求在 1–16 之间;
  4. 检查声明范围内每个填充字节;
  5. 对所有无效加密记录返回统一错误。

不要记录解密字节或详细填充失败原因。详细诊断适合隔离测试,不应出现在攻击者可观察的生产响应中。

互操作排查清单

两个系统的 AES-CBC 结果不一致时,依次确认:

  • 原始密钥字节与密钥长度完全相同;
  • 使用相同的 16 字节 IV;
  • 明文字符编码相同;
  • 都使用 PKCS#7,而不是零填充或不填充;
  • 密文编码都是 Hex 或都是 Base64;
  • IV 是单独传输还是统一前置;
  • 没有把认证标签或 HMAC 当作密文的一部分。

字符串字符数不等于字节数。包含中文等非 ASCII 字符的 UTF-8 文本会占用更多字节,因此填充长度也不同。

长度示例

明文字节数填充字节填充后长度
016 个 0x1016
115 个 0x0F16
151 个 0x0116
1616 个 0x1032
311 个 0x0132
3216 个 0x1048

可以使用 AES 加密工具配合测试数据比较明文、IV 与密文编码。新系统应优先选择不需要填充的认证加密模式。

标准与参考资料

技术内容依据所列公开标准与官方文档进行审阅。用于生产前,请同时核对已授权的标准文本和厂商文档。
相关工具
AES 加密工具
← 上一篇
AES IV 与 Nonce 重用:风险与防范
下一篇 →
Web Crypto AES-GCM:浏览器加密实现指南