nocti1016头像

CTF学习/crypto/滑动攻击/相关密钥/不可能差分/AES缓存时序

滑动攻击/相关密钥/不可能差分/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)

工具:CryptoHack – Challenges

 

 

 

 

题目: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

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--