Cryptopals zestaw 1 ćwiczenie 8

przez | 27 maja 2020
Używam AESa, więc nikt nie wie co zawierają moje pliki.

Załączony powyżej obrazek to chyba najpopularniejszy sposób na pokazanie słabości trybu ECB. Wspomniałem o tym przy poprzednim ćwiczeniu, dziś trochę rozwinę temat. Najczęściej na prezentacjach wykorzystuje się obrazki ponieważ wtedy każdy może „naocznie” zaobserwować, że z naszymi zaszyfrowanymi danymi jest coś nie tak. Poniżej znajduje się oryginalny obraz:

Sekretny obrazek o którym nikt nie powinien się dowiedzieć.

Na początek wspomnę tylko, że zrobiłem pewne uproszczenie, żeby łatwiej się nam to oglądało, ale może zacznijmy od początku. Najpierw stworzyłem powyższy obrazek i zapisałem go w formacie BMP. W tym formacie dane są nieskompresowane i w związku z tym idealnie nadaje się do tej prezentacji. Żeby stworzyć nowy „zaszyfrowany” użyłem takiego skryptu:

from Crypto.Cipher import AES

ciph = AES.new("SecretPassword12", AES.MODE_ECB)
plain = b''
with open(r"aes_ecb_plain.bmp", "rb") as f:
   plain = f.read()

plain_data = plain[54:]
ciphered_data = ciph.encrypt(plain_data)
with open(r"aes_ecb_ciphered.bmp", "wb") as f:
   f.write(plain[:54])
   f.write(ciphered_data)
  1. Otwieramy niezaszyfrowany plik.
  2. Odczytujemy zawartość pliku.
  3. Szyfrujemy dane.
  4. Zapisujemy dane do nowego pliku.

Widać tu, że nie szyfruję wszystkich danych i pomijam pierwsze 54 bajty. Jest to nagłówek formatu BMP, gdyby został zaszyfrowany nie moglibyśmy w tak łatwy sposób podejrzeć zawartości pliku. To jest to uproszczenie o którym wspominałem. Gdybyśmy mieli do czynienia z plikiem który ma zaszyfrowany również nagłówek, moglibyśmy spróbować go nadpisać nagłówkiem z innego niezaszyfrowanego pliku.

Dlaczego to jest ważne? Ponieważ jeżeli udało by się nam wykryć, że dane są zaszyfrowane AES w trybie ECB, będziemy wiedzieli jakich technik użyć do odszyfrowania tych danych (tych technik nauczymy się w kolejnych ćwiczeniach).

Właściwość trybu ECB która nam w tym pomoże jest fakt, że każdy taki sam blok danych po zaszyfrowaniu zwraca takie sam blok danych na wyjściu. Przykładowo jeżeli szyfrujemy jakieś dane wśród których przynajmniej dwukrotnie powtarza się ciąg „0123456789abcdef” to po zaszyfrowaniu również będziemy mogli znaleźć ciąg o jakiejś innej wartości który będzie się powtarzał tyle samo razy i występował w tych samych miejscach. Na obrazku jest to bardzo dobrze widoczne ponieważ składa się on z białego tła i czarnego napisu – są to ciągi białych i czarnych pikseli dlatego takich powtarzających się bloków jest bardzo dużo i widać to nawet gołym okiem bez otwierania obrazka w hex edytorze (np. https://mh-nexus.de/en/hxd/). Oczywiście możemy stworzyć prostą funkcję która sprawdzi za nas, czy wśród danych są jakieś bloki, które się powtarzają:

def canBeAesECB(inputData):
    chunks = [inputData[idx:idx+16] for idx in range(0, len(inputData), 16)]
    tmp = {}
    for chunk in chunks:
        tmp[chunk] = 1
    return len(tmp) != len(chunks)

Na początku rozbijamy dane wejściowe na 16-bajtowe bloki. Następnie iterujemy po wszystkich blokach i dodajemy je do słownika. W słowniku może być tylko jeden klucz o danej wartości, w związku z tym jeżeli jakieś blok się powtarza to długość słownika będzie krótsza niż ilość wszystkich bloków. Na końcu porównujemy długość słownika z długością listy bloków i wiemy czy wystąpiły jakieś powtórzenia.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *