CBC加密和解密过程

f215609f354300598724de6ef2aeb364

加密过程

CBC加密流程:

  1. 准备

    • 将明文按固定长度(通常是块大小,比如AES是128位)分块
    • 如果最后一块不足长度,需要填充(padding)
    • 选一个初始化向量(IV),它的长度跟分块大小相同。
  2. 加密每一块(第 i 块)

    • 第1步:用当前明文块 PiP_iPi 和前一块密文(或IV)做异或(XOR)

      • 第一个块是
        $$
        C_0=Ek(P0⊕IV)
        $$
    • 第2步:将异或后的结果送入加密算法(E_k)(比如AES)加密,得到当前块的密文 Ci。

    • 第3步:当前的密文块 CiC_iCi 会作为下一块明文的XOR对象。

  3. 循环处理每一块,直到全部加密完成。

解密过程

1
解密过程刚好相反,第一组密文在解密之后与初始向量IV异或得到第一组明文。第二组密文解密之后和第一组密文异或得到第二组明文。也就是说,解密一组明文需要本组和前一组的密文。

特点

加密算法的输入是上一个密文分组和下一个明文分组的异或

EXB模式和CBC模式

image-20250426204537824

CBC字节翻转攻击

CBC字节翻转攻击的核心原理是通过破坏一个比特的密文来篡改一个比特的明文。

erwerwerwerwe
$$
由题目得 A⊕B=C
$$
如果我们想要改变输出的明文C 那我们只需要改变秘钥A

令改变后的A为A’ C为C’,于是:

1
2
3
4
5
C'=C⊕C⊕C'
=A⊕B⊕C⊕C'
=B⊕A⊕C⊕C'
令A'=A⊕C⊕C'
-->C'=B⊕A'-->A'⊕B=C' 翻转成功啦!

所以把A改为A’=A⊕C⊕C’ 我们就可以实现这个字节翻转攻击

测试攻击模拟代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from Crypto.Cipher import AES
import uuid
import binascii

BS = AES.block_size # 分组长度
key = b'test' # 密钥
iv = uuid.uuid4().bytes # 随机初始向量
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() # Pkcs5Padding
data = b'1234567890abcdefabcdef1234567890' # 明文M


# 加密
def enc(data):
aes = AES.new(pad(key), AES.MODE_CBC, iv)
ciphertext = aes.encrypt(pad(data))
ciphertext = binascii.b2a_hex(ciphertext)
return ciphertext


# 解密
def dec(c):
c = binascii.a2b_hex(c)
aes = AES.new(pad(key), AES.MODE_CBC, iv)
data = aes.decrypt(c)
return data


# 测试CBC翻转
def CBC_test(c):
c = bytearray(binascii.a2b_hex(c))
c[0] = c[0] ^ ord('a') ^ ord('A') # c[0]为第一组的密文字符,a为第二组相应位置的明文字符,A是我们想要的明文字符 这一步就是在做 A'=A⊕C⊕C'
c = binascii.b2a_hex(c)
return c


print("ciphertext:", enc(data))
print("data:", dec(enc(data)))
print("CBC Attack:", dec(CBC_test(enc(data))))

输出结果

1
2
3
ciphertext: b'65518dfe77f7d677134f341c5b00c1674e7a87b231f852b63d35ee69dc60bcc7c5b7325b590c00d089b6ad312f21b043'
data: b'1234567890abcdefabcdef1234567890\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10'
CBC Attack: b'\xfe\xb4\x11n+\x1a\xb7\x90\x9c\x86TPvS\xd4\x9cAbcdef1234567890\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10'

可以看到第二组密文解密之后已经被我们更改成了A,而由于我们更改了第一组的密文,所以第一组解密的明文变成了乱码。如果我们想要更改第一组的明文,则需要修改初始向量IV的值。

于是达到修改明文的内容的目的:解密出来的内容就会把 'a' 改成 'A'

例题

bugku-login4

题解链接:https://cltheorem.github.io/2019/03/bugku-login/

总结

通过CBC字节翻转攻击,假如我们能够触发加解密过程,并且能够获得每次加密后的密文。那么我们就能够在不知道key的情况下,通过修改密文或IV,来控制输出明文为自己想要的内容,而且只能从最后一组开始修改,并且每改完一组,都需要重新获取一次解密后的数据,要根据解密后的数据来修改前一组密文的值。

参考文章

https://blog.csdn.net/XL115715453/article/details/102442024?spm=1001.2014.3001.5506

https://goodapple.top/archives/217

https://blog.csdn.net/XiongSiqi_blog/article/details/131925246