AES-CBC 是什么
CBC(Cipher Block Chaining,密码分组链接)是 NIST SP 800-38A 定义的经典分组模式:每块明文先与上一块密文异或,再交给 AES 加密,第一块异或的对象是 IV。它需要随机且不可预测的 IV,也需要把不足一整块的数据补齐(通常用 PKCS#7 填充)。CBC 本身不提供完整性,安全用法必须额外加 HMAC;TLS 1.3 已彻底移除 CBC 套件。
基本信息
| 标准 | NIST SP 800-38A |
|---|---|
| IV | 16 字节,随机且不可预测,每消息唯一 |
| 填充 | PKCS#7(1-16 字节,整块时补满一整块) |
| 完整性 | 无,需另加 HMAC 或改用 AEAD |
| 加密并行性 | 加密不可并行(链式依赖),解密可并行 |
| 篡改影响 | 改一块密文会破坏该块及其后一块的明文 |
| TLS 现状 | TLS 1.3 已移除;TLS 1.2 中应禁用 |
典型使用场景
- 兼容老文件格式与老接口:很多历史格式固定使用 AES-CBC,迁移期必须能读写
- 已有的自研加密工具与脚本:openssl enc 的默认 CBC 用法在存量运维脚本里很常见
- 遗留协议对接:部分行业设备只实现 CBC,需要按对端能力做兼容
- 教学与协议分析:CBC 是理解填充、IV 与链接结构的典型模式
- 需要逐块解密的历史存储:CBC 解密可并行,适合随机读取已分块存储的老数据
OpenSSL 加解密
OpenSSL 加解密
# 口令派生密钥:salt 与 iter 必须随文件保存,否则日后无法解密
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -salt -in plain.txt -out data.enc
# 解密:模式、迭代次数与派生方式要完全一致
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -in data.enc -out plain.txt
# 显式指定密钥与 IV(均十六进制,IV 为 16 字节)便于与程序对接
openssl enc -aes-256-cbc -K 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff -iv 000102030405060708090a0b0c0d0e0f -in plain.txt -out data2.enc
# 查看默认填充行为与隐式 IV 的存储方式(前 16 字节通常就是随机盐或 IV)
xxd -l 32 data.enc
# 生成随机 IV 并保存,CBC 的 IV 不需要保密但不能预测
openssl rand -hex 16CBC 与相邻模式对照
| 维度 | CBC | CTR/GCM |
|---|---|---|
| 是否需填充 | 需要 PKCS#7 | 不需要(流式) |
| IV/nonce 要求 | 随机且不可预测 | 同一密钥下唯一,可结构化 |
| 完整性 | 无,需加密后追加 MAC | GCM 自带认证;CTR 无 |
| 加密并行 | 不可并行 | 可并行 |
| 随机读取 | 只能从块边界定位 | 可任意偏移定位 |
| 典型误用 | 固定 IV 退化为确定性加密 | nonce 重用泄漏密钥流 |
CBC 无认证:密文被篡改会影响后续明文。若服务端对「填充错误」与「消息认证失败」给出不同错误码、不同页面甚至不同响应耗时,就构成填充预言(padding oracle),攻击者可用它逐字节推断明文。TLS 1.2 时代还出现过针对 CBC 的时序攻击(Lucky13 类),根治手段是改用 AEAD。
自研 AES 的坑点对应写法
自研 AES 的坑点对应写法
# 正确做法(Encrypt-then-MAC):先加密,再对 IV+密文计算 MAC
# MAC 覆盖 IV 是必须的,否则攻击者可篡改 IV 影响首个明文块
ct = AES_CBC_encrypt(key_enc, iv, pad(plain))
tag = HMAC_SHA256(key_mac, iv || ct)
store(version, iv, ct, tag)
# 错误做法:先 MAC 后加密(MAC-then-Encrypt),或 MAC 不覆盖 IV,都会留下攻击面
# 解密后必须常量时间比较 tag,并在标签失败时统一返回同一个错误
IV 不需要保密,但必须不可预测:常见的错误是把计数器或时间戳直接当 IV。CBC 的正确来源是密码学安全随机数(openssl rand、os.urandom),并与密文一起存储在文件头或数据库字段里。
新系统若必须加密文件且只能用命令行工具,优先选择支持 AEAD 的方式;如果对象是老格式或老对端,CBC 可以保留,但要确保 IV 独立随机、密文与标签一起校验,并在应用层统一错误响应。