web手从0学习密码的故事-2 加密模式
关于常见对称分组加密的加密方式以及对应的常见攻击手法
加密模式
ECB 模式
ECB(Electronic Codebook,电子密码本)模式是最基础、最简单的块密码加密模式。
加密流程:
- 将明文分成固定长度的块
- 每个明文块使用相同的密钥 独立加密
- 加密公式:
- 各分组之间完全独立、互不影响
- 最终密文为:

解密流程:
- 将密文分成等长的块
- 每个密文块使用相同的密钥 独立解密
- 解密公式:
- 各分组之间完全独立,可并行处理

ECB 模式特点:
- 简单直接:每个明文块独立加密,像查字典一样
- 确定性:相同密钥下,相同明文块总是产生相同密文块(最大缺陷)
- 可并行化:各块独立,可并行加密/解密
- 不适合加密长消息或含重复模式的数据(如图片)
ECB 块重排攻击
在块加密中ECB模式中每个块都是独立加密的。因此攻击者可以在未知密钥的情况下,对密文中的块进行重新排列,组合成合法的可解密的新密文。 例如,现在有一个cookie:
admin=0;username=test123
假设块字节大小是8字节,那么明文就能拆分成三块
admin=0;
username
=test123
那么现在我们需要把admin变成1使其越权 那么我们就可以通过构造用户名来得到admin=1的块,然后替换掉第一块即可,比如
admin=0;username=test123admin=1;
那么拆分成块得到
admin=0;
username
=test123
admin=1;
我们就得到了admin=1的密文,替换掉第一个密文即可越权成为admin
ECB 字节频率统计 / 已知明文攻击
ECB 模式最大的缺陷是确定性:相同的明文块在同一密钥下必定产生相同的密文块。攻击者可以利用这一特性进行统计或已知明文分析。
示例 —— 加密 Tux 图像:

假设原始企鹅图像包含大片相同颜色的背景。加密后:
原始位图(明文块): 加密后(密文块):
[黑][黑][黑][黑][轮廓] → [C1][C1][C1][C1][C5]
[黑][黑][黑][轮廓][轮廓] → [C1][C1][C5][C5][C5]
观察密文就能还原出企鹅轮廓,完全不需要密钥。
已知明文攻击示例 —— 网站 cookie 模板:
假设服务器对固定格式 user=XXX;role=user 进行 ECB 加密(块大小 8 字节):
明文: user=Alc;role=user
分块: user=Alc | ;role=us | er????
密文: abcdef01 | 12345678 | 9abcdef0
攻击者已知前两块的明文内容后,可以构造任意相同前缀的明文,再观察对应密文即可推断第三块内容。例如注册 user=Alc;role=admin 时第三块密文如果变为 fedcba98,即可推断该块对应 admin?? 的密文。
CBC 模式
CBC(Cipher Block Chaining,密码分组链接)模式通过引入”链接”机制解决了ECB的安全性问题。
加密流程:
- 使用初始化向量 启动加密过程
- 每个明文块先与前一个密文块异或,再进行加密
- 第一块:
- 后续块:
- 加密过程串行(必须等待前一块结果)

解密流程:
- 每个密文块先解密,再与前一个密文块异或
- 第一块:
- 后续块:
- 解密可并行(所有密文块已知)

CBC 模式特点:
- 安全性高:相同明文在不同位置生成不同密文
- IV 必须不可预测,但不需保密
- 加密串行,解密可并行
- 错误传播有限:单块密文损坏只影响相邻两块
CBC字节翻转
CBC字节翻转攻击利用了解密过程中异或的特性。由于:
攻击者可以通过修改 的特定字节来控制 的对应字节。

padding oracle
Padding Oracle 攻击能够在仅知道 padding 是否合法的情况下,完全解密任意密文。
攻击原理:
CBC 解密公式为:
假设我们想解密密文块 ,我们控制 (即”伪造前一块”)。Padding Oracle 会告诉我们:解密后 的填充是否合法(PKCS#7 padding)。
设 (即解密中间值,与密钥相关但固定)。
我们有:
单字节恢复过程(恢复 的最后一个字节):
合法的 PKCS#7 padding 在最后字节为 \x01,或最后两字节为 \x02\x02,等等。
我们想让 的最后一个字节变成 \x01:
通过暴力枚举 (256 种可能),当 Padding Oracle 返回”合法”时,我们就获得了 :
知道了 后,将 的最后一个字节恢复为原值即可得到原明文最后一个字节。
恢复倒数第二个字节:
让 的最后两个字节为 \x02\x02:
- 倒数第二字节:
- 最后一字节:(已知)
依此类推,可在 次尝试内恢复整个块。
完整攻击示例(伪代码):
def padding_oracle_attack(oracle, ciphertext_block, orig_prev):
intermediate = [0] * 16
plaintext = [0] * 16
for byte_pos in range(15, -1, -1):
padding = 16 - byte_pos
# 构造伪造前一块,让已恢复的字节产生正确 padding
forged_prev = [0] * 16
for i in range(byte_pos + 1, 16):
forged_prev[i] = intermediate[i] ^ padding
# 暴力枚举当前字节
for guess in range(256):
forged_prev[byte_pos] = guess
if oracle(bytes(forged_prev) + ciphertext_block):
intermediate[byte_pos] = guess ^ padding
plaintext[byte_pos] = intermediate[byte_pos] ^ orig_prev[byte_pos]
break
return bytes(plaintext)
CFB 模式
CFB(Cipher Feedback,密文反馈)模式将分组密码转换为自同步的流密码。
加密流程:
- 使用初始化向量 填充反馈寄存器 (长度 位)
- 从寄存器取最左 位送入加密算法
- 从加密输出取最左 位与明文 异或,得到密文
- 将 反馈到寄存器右端(左移 位后填充)
- 生成新的反馈寄存器

解密流程:
- 同样使用加密算法 (而非解密算法)
- 用寄存器加密结果的前 位与密文 异或得到
- 用 反馈更新寄存器

CFB 模式特点:
- 流密码特性:不需要填充,可处理任意长度数据
- 自同步:丢失若干密文位后会自动恢复
- 错误传播:错误位会停留在寄存器中影响后续块
- 加密和解密都使用加密算法
CFB IV 重用攻击
CFB 模式将分组密码转换为流密码,密文为 。如果 IV 重复使用,且密钥相同,攻击者就能恢复明文。
攻击原理:
CFB 的密钥流生成器为:
如果两次加密使用了相同的密钥 和相同的 ,那么前 位(参数)的密钥流完全相同。即:
- 第一次加密:( 为密钥流)
- 第二次加密:
虽然后续块的密钥流会因为 的不同而分叉,但只要反馈位 小于分组大小 ,就能构造 IV 碰撞场景。
示例 —— CFB-8 攻击():
假设 CFB-8 用 64 位分组、8 位反馈:
加密消息1:Hello World! → 密文 C1[0..10]
加密消息2:Goodbye!!! → 密文 C2[0..10]
如果 IV1 == IV2,则:O1[0..7] 相等
因此:C1[0] ⊕ P1[0] == C2[0] ⊕ P2[0]
⇒ P1 ⊕ P2 == C1 ⊕ C2
只要知道其中一个明文(比如常见的 HTTP 响应头 HTTP/1.1),就能恢复另一个明文。
针对 CFB-1 的攻击(极端情况):
如果 ,那么每次只加密 1 位,反馈 1 位。如果 IV 复用,每条消息的第一位都使用相同的密钥流位,多条消息的密文首位异或即可恢复明文首位异或。
OFB 模式
OFB(Output Feedback,输出反馈)模式将分组密码转换为同步流密码。
加密流程:
- 使用初始化向量 启动
- 对 加密,取输出前 位作为密钥流
- 关键:将 的完整 位输出反馈到下一轮输入
- 反馈链与明文/密文无关

解密流程:
- 与加密流程结构完全相同
- 仅将底部的 和 互换
- 中间仍使用加密算法

OFB 模式特点:
- 同步流密码:密钥流可预先计算
- 无错误传播:密文位错误只影响对应明文位
- IV 必须唯一(nonce),否则严重的安全问题
- 加解密结构相同
OFB nonce 重用 / 密钥流重用攻击
OFB 模式本质上是同步流密码,加密公式为 ,其中 是仅由密钥 和 决定的密钥流。如果 IV(nonce)被重用,密钥流完全相同。
攻击原理:
如果两个不同消息使用相同的 加密:
- 消息 A:
- 消息 B:
则:
攻击者只要知道其中一个明文,就能立刻恢复另一个明文。即使两者都不知道,密文异或也暴露了两段明文的异或关系,统计攻击可以恢复出明文内容。
经典案例 —— WEP 协议破解:
WEP(无线加密协议)使用 RC4 流密码,但 IV 只有 24 位。当流量较大时:
- 24 位 IV 空间有限(约 1677 万)
- 同一个 IV 重复使用会导致密钥流重用
- 这正是 WEP 容易被破解的根本原因(虽然还有弱密钥等其他问题)
现代 WPA3 改用 SAE 协议从根本上解决了这一问题。
示例 —— 两段密文异或恢复明文:
假设 IV 重用,加密两段 HTTP 响应:
密文A: 1a2b3c4d5e6f7081...
密文B: 0f5e4a2c7d8b9012...
已知密文A对应: "HTTP/1.1 200"
密文B对应未知内容
由 ,前 12 字节为:
"HTTP/1.1 200" ⊕ 密文A ⊕ 密文B = 密文B对应的明文前12字节
CTR 模式
CTR(Counter,计数器)模式是现代加密中最常用的模式之一。
加密流程:
- 使用一系列计数器值 (通常由 nonce + 计数序列构成)
- 每个计数器值独立加密:
- 密文:
- 计数器值必须唯一

解密流程:
- 与加密流程完全对称
- 同样使用加密算法
- 处理不满整块时:取 的前 位与密文异或

CTR 模式特点:
- 完全并行:各分组独立计算,效率最高
- 随机访问:可直接解密任意块
- 无填充:可处理任意长度数据
- 计数器唯一性是安全的关键
- 加解密结构完全相同
- 当前推荐使用的加密模式(如 AES-CTR)
CTR nonce 重用攻击
CTR 模式的加密公式为 ,其中 。如果 nonce 重用(即不同消息使用相同的计数器初始值),攻击方式与 OFB nonce 重用完全一致。
攻击原理:
如果两次加密使用了相同的 :
- 消息 A:
- 消息 B:
则每块对应的密钥流 完全相同:
示例 —— 已知明文恢复:
设 AES-256-CTR 加密两个 16 字节块的消息:
nonce = 0x00000000000000000000000000000001
T1 = 0x00000000000000000000000000000001
T2 = 0x00000000000000000000000000000002
密钥流: S1 = AES_K(T1), S2 = AES_K(T2)
消息A明文: "GET /admin HTTP" (16字节)
消息B明文: "GET /public HTTP" (16字节)
密文A[0]: 0x9a4b3c2d1e5f7081...
密文B[0]: 0x7c8d9e0f1a2b3c4d...
由密文异或得到:
C^A[0] ⊕ C^B[0] = "GET /admin" ⊕ "GET /public" = 0xe6c6a222043f4c2c...
若已知密文A对应明文”GET /admin “,则立即恢复密文B的明文:
P^B[0] = C^B[0] ⊕ C^A[0] ⊕ P^A[0]
Bit-flipping 攻击(与 CBC 类似):
CTR 模式没有 IV,也没有链接,但密文 = 明文 ⊕ 密钥流。攻击者直接修改密文 的某个字节,新明文对应字节会变化:
这种”密文可控则明文可控”的特性使得 CTR 模式也需要 MAC 保护。
多消息密钥流恢复:
如果攻击者收集了大量使用相同 nonce 加密的消息,可以构造多组 等式。如果某个消息明文完全已知(例如硬编码的固定响应),就能恢复所有其他消息的明文。
CTR 计数器碰撞 / 比特翻转
计数器碰撞攻击:
CTR 模式的核心安全性在于计数器值的唯一性。如果两个不同的明文块使用了相同的计数器值 ,那么它们会被相同的密钥流加密,攻击方式与 nonce 重用一致。
碰撞场景示例:
假设 nonce 是 32 位,计数器是 32 位:
nonce = 0x00000001, counter = 0x00000001 → T = 0x0000000100000001
nonce = 0x00000000, counter = 0x00000001 → T = 0x0000000000000001
不同 nonce + counter 不应该碰撞,但如果实现错误(如拼接顺序错误、位数截断),就可能发生碰撞。
整数溢出碰撞:
32 位计数器空间只有约 42 亿。如果加密了超过 个块(约 64 GB 数据),计数器必然回绕,密钥流就会重复。
WEP 中 24 位 IV 空间更小,几小时内就会碰撞。
比特翻转(Bit-flipping)攻击:
CTR 模式同样可以被比特翻转攻击:
攻击者无需知道密钥,只需修改密文对应位即可控制明文对应位。
示例 —— 构造 admin 用户:
假设加密格式:role=guest;username=test
明文块[0]: role=guest → 密文块[0]: 0xa1b2c3...
密钥流 S0: = 明文 ⊕ 密文
S0[0..3] = "role" ⊕ 0xa1b2c3... = 密钥流前缀
如果想改成 role=admin:
新密文块[0] = 新明文 ⊕ S0 = "role=admin" ⊕ S0
但 CTR 模式下,攻击者只要知道原密文和想改成的明文,就可算出需要的密文修改值:
密文' = 密文 ⊕ 原明文 ⊕ 新明文 = 密文 ⊕ "guest" ⊕ "admin"
无需关心密钥流!
为什么 CTR 模式仍然安全:
- 计数器唯一 → 密钥流唯一 → 流密码语义安全
- 加密算法是 PRF(伪随机函数)
- 攻击者不能获得密钥流明文对
CTR vs CBC 比对:
- CBC:修改 影响 ,修改 影响 和
- CTR:修改 精确影响 ,错误传播最小
两者都需要 MAC 保护才能防止篡改。