滑动攻击/相关密钥/不可能差分/AES缓存时序
考点概念
对称密码
滑动攻击(Slide Attack):
针对轮函数完全相同的迭代分组密码,寻找"滑动对" (P, F(P)),满足 E(F(P)) = F(E(P))(E = F^r)。一旦获得滑动对,可把密钥恢复简化为对单轮的分析,即使轮数极多也能攻击。
相关密钥攻击(Related-Key Attack):
攻击者能获取同一明文在多个相关密钥(如 K、K XOR delta)下的加密结果,利用密钥关系降低复杂度。DES 的补码性质是典型实例:E_K'(~P) = ~E_K(P)(K' = ~K),因此给定明密文对可将 DES 搜索空间减半。
AES 不可能差分攻击:
利用 AES 某些差分传播路径概率为 0(四轮不可能差分、反向扩展),对密钥逐字节排除候选,将 AES 全轮攻击降到约 2^126。属于理论性攻击,CTF 极少出现完整实现。
AES 缓存时序攻击:
AES 标准实现用 S-box 查表,表访问地址依赖密钥;攻击者测量解密过程的缓存访问时间/驱逐行为可推断 S-box 索引,逐步恢复密钥。需要本地目标机与精确计时
通常以"侧信道实验环境"形式出现。
识别特征
滑动攻击:题目轮函数周期固定、密钥重用,提示"slide attack";附脚本给出轮函数。
相关密钥:题目允许在密钥 XOR 固定常数下多次加密;DES 题出现补码提示。
不可能差分:理论题、CTF 论文题,通常附 AES 差分表与过滤过程。
缓存时序:题目提供远程服务 + 大量加密/解密样本与时间测量,要求恢复 S-box 索引或密钥。
综述性提示:题目描述出现"其它攻击面""不可""相关密钥"等。
靶场题目
Beatboxer(AES 变体线性分析) Triple DES(DES 补码属性)
Writeup
题目:Beatboxer(CryptoHack) 识别:
审读源码发现 S 盒不是标准 AES S 盒,而是 GF(2^8)(AES 同款多项式)上的仿射映射 s[x] = 0x2a 乘 x 再异或 0x2a(本地验证:对前 32 个 x 全部成立,且逆映射为 x = 0x2a 的逆元乘 y 异或 0x2a 后的值,0x2a 的逆元为 0x98);
密钥扩展也用该 S 盒。ShiftRows 排列、MixColumns GF 乘法、AddRoundKey 异或三者在 GF(2) 上全部线性,于是整条加密链对明文是 GF(2)-仿射:E(m) = L(m) XOR t,L 与密钥无关(纯结构决定),t 由密钥决定
解题:
本地实现
选任意 keyA 得到 E_A。三条关键恒等式本地验证成立:
E_A(m) XOR E_A(0) 与 E_B(m) XOR E_B(0) 在两个不同密钥下相同,说明 L 与密钥无关
E_R(m) XOR E_A(m) 与 m 无关,说明全部密钥相关项并入公共偏置
对任意明文 F 有 E_R(F) = E_A(F) XOR E_A(m0) XOR E_R(m0)。攻击时只允许一次加密,先用它拿 (m0, c0),再请求 encrypt_flag 得密文块 C_i,按恒等式三算出 E_A(F_i) = C_i XOR c0 XOR E_A(m0);
又 E_A(F_i) = L(F_i) XOR t_A,其中 t_A = E_A(0),所以 L(F_i) = E_A(F_i) XOR E_A(0)。最后用 128 个单位基向量预计算 L 的像并做 GF(2) 高斯消元回代求 L 逆,逐块还原 F_i 即 flag(含 PKCS 风格填充字节)。 脚本:
from os import urandom
src = open("13406_beatboxer.py", encoding="utf-8").read()
src = src.split("class Challenge")[0]
src = "\n".join(l for l in src.splitlines() if "utils" not in l and "listener" not in l)
ns = {}
exec(src, ns)
AES_cls = ns["AES"]
def gmul(a, b):
p = 0
for _ in range(8):
if b & 1:
p ^= a
hi = a & 0x80
a = (a << 1) & 0xff
if hi:
a ^= 0x1b
b >>= 1
return p
sbox = AES_cls.sbox
print("s[x]==0x2a*x^0x2a(前32项):", all(sbox[x] == (gmul(0x2a, x) ^ 0x2a) for x in range(32)))
keyA, keyR = urandom(16), urandom(16)
A, R = AES_cls(keyA), AES_cls(keyR)
m0 = b"\x11" * 16
MOCK = b"crypto{aff1ne_sp0ng3}" + b"\x06" * 11
c0 = R.encrypt(m0)
cflag = b"".join(R.encrypt(MOCK[i:i + 16]) for i in range(0, len(MOCK), 16))
tA = A.encrypt(b"\x00" * 16)
def L(m):
return bytes(a ^ b for a, b in zip(A.encrypt(m), tA))
basis = []
for j in range(128):
v = bytearray(16)
v[j // 8] |= 1 << (7 - j % 8)
basis.append(L(bytes(v)))
def gf2_solve(bas, y):
M = [[int.from_bytes(bas[j], "big"), 1 << j] for j in range(128)]
bycol, row = {}, 0
for col in range(127, -1, -1):
bit = 1 << col
piv = next((i for i in range(row, 128) if M[i][0] & bit), None)
if piv is None:
continue
M[row], M[piv] = M[piv], M[row]
for i in range(128):
if i != row and M[i][0] & bit:
M[i][0] ^= M[row][0]
M[i][1] ^= M[row][1]
bycol[col] = M[row]
row += 1
assert row == 128, "L 奇异"
Y, x = int.from_bytes(y, "big"), 0
for col in range(127, -1, -1):
img, pre = bycol[col]
if Y >> col & 1:
x ^= pre
Y ^= img
assert Y == 0
out = bytearray(16)
for j in range(128):
if x >> j & 1:
out[j // 8] |= 1 << (7 - j % 8)
return bytes(out)
recovered = b""
for i in range(0, len(cflag), 16):
E_A_F = bytes(a ^ b ^ c for a, b, c in zip(cflag[i:i + 16], c0, A.encrypt(m0)))
recovered += gf2_solve(basis, bytes(a ^ b for a, b in zip(E_A_F, tA)))
print("差分还原:", recovered, recovered == MOCK)
题目:Triple DES(CryptoHack) 识别:DES 补码性质 E_{~K}(~P) = ~E_K(P)
解题:利用补码性质对候选密钥一次计算同时校验 K 与 ~K 两组候选,密钥空间减半;
结合双重/三重 DES 的中间相遇结构做表交与消歧,最终用恢复的密钥链解密 flag 段
脚本:
from Crypto.Cipher import DES
K = b"abcdefgh"
P = b"plaintex"
comp = lambda b: bytes(x ^ 0xff for x in b)
c1 = DES.new(K, DES.MODE_ECB).encrypt(P)
c2 = DES.new(comp(K), DES.MODE_ECB).encrypt(comp(P))
print("E(K,P) =", c1.hex())
print("E(~K,~P) =", c2.hex())
print("补码性质成立:", c2 == comp(c1))
工具:Triple DES
脚本
"""
其它对称攻击面综述 (滑动攻击/相关密钥/不可能差分/AES缓存时序)
对可自动化的三项做实证演示:
DES 补码性质(相关密钥攻击的一环): ~E(K,P) = E(~K,~P) => 密钥空间减半搜索
AES-ECB 块重复检测: 识别 ECB 模式(密文长度 16 的整数倍 + 出现重复块)
滑动攻击最小演示: 轮函数相同的迭代结构存在"滑动对" (E(F(P)) = F(E(P)))
实战替换
DES 密钥/明文 <- 题目中候选密钥与已知明文(补码校验法)
AES 密文 <- 题目附件密文(判断是否为 ECB)
"""
from Crypto.Cipher import AES, DES
KA = b"abcdefgh"
PA = b"plaintex"
def compe(key: bytes, blk: bytes):
return bytes(b ^ 0xff for b in key), bytes(b ^ 0xff for b in blk)
if __name__ == "__main__":
c1 = DES.new(KA, DES.MODE_ECB).encrypt(PA)
kcomp, pcomp = compe(KA, PA)
c2 = DES.new(kcomp, DES.MODE_ECB).encrypt(pcomp)
assert c2 == bytes(b ^ 0xff for b in c1), "DES 补码性质验证失败"
print("A. DES 补码性质验证通过: E(~K,~P) = ~E(K,P) (密钥搜索可减半)")
plain = b"ABCDEFGHIJKLMNOP" * 4
ct = AES.new(b"k" * 16, AES.MODE_ECB).encrypt(plain)
blocks = [ct[i:i + 16] for i in range(0, len(ct), 16)]
dup = len(blocks) - len(set(blocks))
print(f"B. 密文长度 {len(ct)} 字节 = 16 的 {len(blocks)} 倍, 重复块数 {dup}")
assert len(ct) % 16 == 0 and dup > 0, "未检测到 ECB 特征"
print("B. 判定: 存在重复块, 高度疑似 ECB 模式")
def feistel_round(v, sk):
L, R = (v >> 8) & 0xff, v & 0xff
return ((R ^ ((L * sk + 3) & 0xff)) << 8) | L
def enc2(v, sk):
return feistel_round(feistel_round(v, sk), sk)
sk = 7
p0 = 0x1234
p1 = feistel_round(p0, sk)
assert enc2(p1, sk) == feistel_round(enc2(p0, sk), sk), "滑动对性质不成立"
print("C. 滑动对验证通过: 迭代结构 E(P') = F(E(P)), 可借滑动对恢复密钥")
print("SUCCESS: 26 节三个可自动化演示全部通过")
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/nocti1016/article/details/169169975



