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