pythonpython-3.xsecurityencryptionpadding-oracle-attack

Python Padding Oracle breaking script seems to be undefined?


I am tying to write a very simple script that will Just decrypt one byte of text according to this formula P′2[K] = Pn[K] ⊕ Cn-1[K] ⊕ C′[K] the oracle is a simple function that decrypt then check last byte to be equal to padding 0x15. with p'2[k] is just 0x15(padding size)

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

but the behavior seems Undefined . The loop is a simple loop from 0-> 255(number of tries to decrypt one block)

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

The message That gets encrypted is just 8 bytes string + 8 bytes padding and gets decrypted with same key and IV each time. with c1, c2 correspond to ciphertext of m1, m2

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

WHOLE SOURCE CODE IS HERE:

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))

Solution

  • I think there are two problems in the code:

    When using AES and a block size of 16 bytes, the data must additionally be modified accordingly.

    Edit: