CBC模式-字节翻转攻击

CBC模式的字节翻转攻击可以篡改原文的第一块分组的内容,在某些情况下我们就可以控制解密输出来的部分明文来达到我们的目的

前导知识

ECB模式:按照原先的加密算法不进行修改,直接进行加密解密

CBC模式:相对于原生的算法,CBC模式多了IV(IV:初始向量)进行异或操作,IV用于随机化加密的比特块,保证即使对相同明文多次加密,也可以得到不同的密文。

解密第一组时:

X[1]=k(Y[1]) Xor IV

对于X[i]的解密时,X[i] = k(Y[i]) Xor Y[i-1],k(Y[i])部分是无法控制的,假如修改Y[i]的值,是无法确定k(Y[i])的值,由于最后是异或操作,因此可以仅修改Y[i-1]的内容为Y’[i-1]来控制最后的明文的值,设解密后的内容为M[i]=k(Y[i]) Xor Y[i-1]。

将Y[i-1]的值设置为Y[i-1] Xor M[i]的值,新的Y[i-1]的值用Y’[i-1]表示。

那么X[i] = k(Y[i]) Xor Y’[i-1]=k(Y[i]) Xor Y[i-1] Xor M[i] = M[i] Xor M[i] = 0

这样就能将只修改Y[i-1]的内容来控制X[i]的值

而此时X[i-1]的值肯定就会出错了,设修改Y[i-1]的值,导致解密后X[i-1]的值为M[i-1],那么将Y[i-2]的值改为Y[i-2]=Y[i-2] Xor M[i-1] Xor 任意值,可以使得X[i-1]=任意值

这样循环往前,最后一组就是根据M[1]的值修改IV=IV Xor M[1] Xor 任意值,使得X[1]=任意值。

也就是说在解密时,只有第一块分组才会用到IV进行解密,其他部分不受影响,即使IV值不正确,也能确保除了第一块分组以为的其他分组是正确的。

简单来说就是我们可以控制原文的第一块分组的内容

利用条件

  1. 知道原始IV
  2. 知道原文
  3. 知道用恶意IV解密出的明文

举例-AES

下面就是演示如何篡改内容的。

#! /usr/bin/python3
# -*- coding: utf-8 -*-

from Crypto.Cipher import AES
import struct

def encrypt(plain_text, key, iv):

    aes_instance = AES.new(key, AES.MODE_CBC, iv)
    cipher = aes_instance.encrypt(plain_text)

    return cipher

def decrypt(cipher, key, iv):

    aes_instance = AES.new(key, AES.MODE_CBC, iv)
    plain_text = aes_instance.decrypt(cipher)

    return plain_text

iv = b'\x00' * 16
key = 'k'*16
plain_text = b'I like you!!!!!!' + b' very much!!!!!!'
print('Plain text: ', plain_text)

print('encrypt...')
cipher = encrypt(plain_text, key, iv)

hack_content = b'I very hate you!'
indirect_text = decrypt(cipher, key, hack_content)
print('indirect_text: ', indirect_text)

new_iv = b''
for i in range(len(iv)):
    temp = iv[i] ^ indirect_text[i]
    new_iv += struct.pack('B', temp)

print('decrypt: ', decrypt(cipher, key, new_iv))

运行结果:

ex@Ex:~/test$ ./aes_demo.py 
Plain text:  b'I like you!!!!!! very much!!!!!!'
encrypt...
indirect_text:  b'\x00\x00\x1a\x0c\x19\x1c\x00\x11\x0e\x01D\x01XNT\x00 very much!!!!!!'
decrypt:  b'I very hate you! very much!!!!!!'

举例-DES

#! /usr/bin/python3
# -*- coding: utf-8 -*-

from Crypto.Cipher import AES, DES
import struct

def encrypt(plain_text, key, iv):

    des_instance = DES.new(key, DES.MODE_CBC, iv)
    cipher = des_instance.encrypt(plain_text)

    return cipher

def decrypt(cipher, key, iv):

    des_instance = DES.new(key, DES.MODE_CBC, iv)
    plain_text = des_instance.decrypt(cipher)

    return plain_text

iv = b'\x00' * 8
key = 'k'*8
plain_text = b'like you' + b' so much'
print('Plain text: ', plain_text)

print('encrypt...')
cipher = encrypt(plain_text, key, iv)

hack_content = 'hate you'
indirect_text = decrypt(cipher, key, hack_content)
print('indirect_text: ', indirect_text)

new_iv = b''
for i in range(len(iv)):
    temp = iv[i] ^ indirect_text[i]
    new_iv += struct.pack('B', temp)

print('decrypt: ', decrypt(cipher, key, new_iv))

运行结果:

ex@Ex:~/test$ ./des_demo.py 
Plain text:  b'like you so much'
encrypt...
indirect_text:  b'\x04\x08\x1f\x00\x00\x00\x00\x00 so much'
decrypt:  b'hate you so much'

总结

只要用到了CBC模式进行加解密,就会存在这种漏洞。