Python填充Oracle破坏脚本似乎未定义



我打算写一个非常简单的脚本,只解密一个字节的文本根据这个公式P′2[K] = Pn[K] ⊕ Cn-1[K] ⊕ C′[K]oracle是一个简单的函数,它解密然后检查最后一个字节是否等于填充CCD_。p'2[k]只有0x15(填充大小(

def decrypt(cipher):
dec = aes_context.decryptor()
text = dec.update(cipher)
if text[-1] == 0x15:
return True, "Padding Match"
else:
return False, "No Match"

但这种行为似乎没有定义。循环是从0->255(尝试解密一个块的次数(

number = 0x01
index = 0
while index < 255:
try_this_block = 0x0.to_bytes(7, "big") + number.to_bytes(1, "big")
mod_ciphertext = try_this_block + c1
state, error_text = decrypt(mod_ciphertext)
if state:
byte = try_this_block[-1] ^ 0x15 ^ c1[-1]
text_back += byte.to_bytes(1, "big")
break
else:
number += 1
index += 1

被加密的消息只有8个字节的字符串+8个字节的填充,每次都用相同的密钥和IV解密。其中c1,c2对应于m1,m2 的密文

m1 = b"khaled G"
m2 = 0x00.to_bytes(7, "big") + 0x015.to_bytes(1, "big")

完整的源代码在这里:

from cryptography.hazmat.primitives.ciphers import algorithms, modes, Cipher
from cryptography.hazmat.backends import default_backend
import os
m1 = b"khaled G"
m2 = 0x00.to_bytes(7, "big") + 0x015.to_bytes(1, "big")
aes_context = Cipher(algorithms.AES(os.urandom(16)), modes.CBC(os.urandom(16)), default_backend())
enc = aes_context.encryptor()
c1 = enc.update(m1)
c2 = enc.update(m2)
c1, c2 = c2[0:8], c2[8:]
def decrypt(cipher):
dec = aes_context.decryptor()
text = dec.update(cipher)
if text[-1] == 0x15:
return True, "Padding Match"
else:
return False, "No Match"
text_back = b""
number = 0x01
index = 0
while index < 255:
try_this_block = 0x0.to_bytes(7, "big") + number.to_bytes(1, "big")
mod_ciphertext = try_this_block + c1
state, error_text = decrypt(mod_ciphertext)
if state:
byte = try_this_block[-1] ^ 0x15 ^ c1[-1]
text_back += byte.to_bytes(1, "big")
break
else:
number += 1
index += 1
print("text is {}".format(text_back))

我认为代码中有两个问题:

  • 首先,AES用于生成长度为一个块或16个字节的密文。然后,这一个16字节的密文块被分割成两个8字节的块,这两个块被视为两个单独的密文块,用于填充预言机攻击。然而,这在关系P2 = C1 xor (C1' xor P2')的上下文中是不允许的,因为假定的两个块之间的关系不存在,参见例如这里。在这一点上,我不想排除有一种算法适用于你的情况的可能性,但它将是不同的
    这个问题可以通过使用与算法大小相等的块大小来解决。例如,对于8字节的块大小,可以使用TripleDES。或者,当使用AES时,必须使用16字节的块大小。在前一种情况下,密钥和IV大小必须进行调整,而且c1, c2 = c2[0:8], c2[8:]行现在已经过时:

    aes_context = Cipher(algorithms.TripleDES(os.urandom(24)), modes.CBC(os.urandom(8)), default_backend())
    ...
    c1 = enc.update(m1)
    c2 = enc.update(m2)
    #c1, c2 = c2[0:8], c2[8:]
    ...
    
  • 其次,解密不考虑IV。如果要解密第一个块(c1(,则前面的测试块不是对应于c1(如当前代码中所示(,而是对应于c0,这就是IV。为了解决这个问题,需要进行以下更改:

    iv = os.urandom(8)
    aes_context = Cipher(algorithms.TripleDES(os.urandom(24)), modes.CBC(iv), default_backend())
    ...
    c1 = enc.update(m1)
    c2 = enc.update(m2)
    #c1, c2 = c2[0:8], c2[8:]
    ...
    byte = try_this_block[-1] ^ 0x15 ^ iv[-1]
    

    通过这些改变,获得了预期的结果(G(。

当使用AES和16字节的块大小时,必须相应地对数据进行额外修改。

  • 例如,以下变化也提供了预期结果(G(:

    m1 = b"khaled Gkhaled G"
    m2 = 0x00.to_bytes(15, "big") + 0x015.to_bytes(1, "big")
    ...
    iv = os.urandom(16)
    aes_context = Cipher(algorithms.AES(os.urandom(16)), modes.CBC(iv), default_backend())
    ...
    c1 = enc.update(m1)
    c2 = enc.update(m2)
    #c1, c2 = c2[0:8], c2[8:]
    ...
    try_this_block = 0x0.to_bytes(15, "big") + number.to_bytes(1, "big")
    ...
    byte = try_this_block[-1] ^ 0x15 ^ iv[-1]
    

编辑:

  • 如果算法/块大小(AES,16字节(和测试数据而不是要更改,则测试数据将仅形成一个明文块(由m1m2组成(,而不是两个。在这种情况下,返回0x15作为结果,因为填充字节现在是块的最后一个字节。关于必要的代码更改,应该注意的是,当只加密一个明文块时,只生成一个密文块(c1(:

    iv = os.urandom(16)                                                                     
    aes_context = Cipher(algorithms.AES(os.urandom(16)), modes.CBC(iv), default_backend())  
    ...
    c1 = enc.update(m1)  # empty
    c1 += enc.update(m2) # provides full block
    #c1, c2 = c2[0:8], c2[8:]
    ...
    try_this_block = 0x0.to_bytes(15, "big") + number.to_bytes(1, "big")
    ...
    byte = try_this_block[-1] ^ 0x15 ^ iv[-1]
    

    这将返回结果0x15

相关内容

  • 没有找到相关文章

最新更新