Python db2 oracle破解脚本好像没有定义?
Python Padding Oracle breaking script seems to be undefined?
我正在尝试编写一个非常简单的脚本,它只需要解密一个字节的文本
根据这个公式 P′2[K] = Pn[K] ⊕ Cn-1[K] ⊕ C′[K]
oracle 是一个简单的函数,它解密然后检查最后一个字节是否等于填充 0x15
。 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 字节的块,这两个块被视为 2 个单独的密文块,用于填充 oracle 攻击。然而,这在关系 P2 = C1 xor (C1' xor P2')
的上下文中是不允许的,因为两个块之间的假定关系不存在,参见例如here。在这一点上,我不想排除存在适用于您的情况的算法的可能性,但它会是不同的。
该问题可以通过使用与算法大小相等的块大小来解决。例如。对于 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]
编辑:
如果algorithm/blocksize(AES,16字节)和测试数据不改变,那么测试数据将只形成一个明文块(由m1
和m2
组成)而不是两个。在这种情况下,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]
这 returns 作为结果 0x15
。
我正在尝试编写一个非常简单的脚本,它只需要解密一个字节的文本
根据这个公式 P′2[K] = Pn[K] ⊕ Cn-1[K] ⊕ C′[K]
oracle 是一个简单的函数,它解密然后检查最后一个字节是否等于填充 0x15
。 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 字节的块,这两个块被视为 2 个单独的密文块,用于填充 oracle 攻击。然而,这在关系
P2 = C1 xor (C1' xor P2')
的上下文中是不允许的,因为两个块之间的假定关系不存在,参见例如here。在这一点上,我不想排除存在适用于您的情况的算法的可能性,但它会是不同的。
该问题可以通过使用与算法大小相等的块大小来解决。例如。对于 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]
编辑:
如果algorithm/blocksize(AES,16字节)和测试数据不改变,那么测试数据将只形成一个明文块(由
m1
和m2
组成)而不是两个。在这种情况下,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]
这 returns 作为结果
0x15
。