14. Déchiffrement ECB octet par octet (complexe)

14. Déchiffrement ECB octet par octet (complexe)

Byte-at-a-time ECB decryption (Harder)

Take your oracle function from #12. Now generate a random count of random bytes and prepend this string to every plaintext. You are now doing:
AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key)
Same goal: decrypt the target-bytes.

Stop and think for a second.
What's harder than challenge #12 about doing this? How would you overcome that obstacle? The hint is: you're using all the tools you already have; no crazy math is required.

Think "STIMULUS" and "RESPONSE".

Ce problème est dans la continuité du 11ème et 12ème. Le but ici est d'arriver à détecter la longueur du préfixe, puis de déchiffrer le texte "secret".

On peut reprendre en l'adaptant légèrement la fonction de chiffrement utilisée pour l'exercice 12:

import os
import random
from cryptopals import ecb_encrypt, ecb_decrypt, padding

secret_text = b64decode("Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK")
random_key = os.urandom(16)
random_prepend = os.urandom(random.randint(5, 20))


store_method = ""
def custom_ecb_encrypt(text):
    text = random_prepend+text+secret_text
    return ecb_encrypt(text, random_key)

Trouver la longueur du préfixe

Pour trouver la longueur du préfixe on peut coder une fonction qui va détecter la longueur de chaîne de caractères que l'on doit fournir à la fonction de chiffrement pour que le 1er bloc reste le même (signifiant que les 16 premiers caractères sont occupés, donc que le premier bloc est constitué uniquement du préfixe + de notre texte):

previous_block = b"\x00"*16
preprend_size = 0
for i in range(0, 100):
    base_cipher_text = custom_ecb_encrypt(b"\x00"*i)
    if(preprend_size == 0 and previous_block == base_cipher_text[0:16]):
        preprend_size = (16-i)+1
        break
    else:
        previous_block = base_cipher_text[0:16]

Déchiffrement octet à octet

En prenant en compte le préfixe, on peut également adapter notre solution du problème 12 pour le cas présent :

base_cipher_text = custom_ecb_encrypt(b"")

for block in range(1, len(base_cipher_text) // 16):
    for i in range(0,16):
        base_block = b"\x00"*(32-preprend_size-i-1)
        cipher_text = custom_ecb_encrypt(base_block)
        for c in range(0,256):
            if(cipher_text[block*16:(block+1)*16] == custom_ecb_encrypt(base_block+recovered_text+bytes([c]))[block*16:(block+1)*16]):
                print(chr(c))
                recovered_text += bytes([c])
                break
print(recovered_text.decode())

En exécutant ce script on obtient :

Rollin' in my 5.0
With my rag-top down so my hair can blow
The girlies on standby waving just to say hi
Did you stop? No, I just drove by