Ćwiczenie numer 10 jest naturalną kontynuacją ćwiczenia numer 7 z zestawu 1 (https://koltys.info/blog/2020/05/25/cryptopals-zestaw-1-cwiczenie-7/ ). Jedyne co musimy zrobić do dodanie do kodu, który już stworzyliśmy nowego trybu – CBC. Przy okazji omawiania trybu ECB wspomniałem, że ma on bardzo poważną wadę, którą zaprezentowałem przy pomocy obrazka. Chodziło o to, że każdy blok danych który się powtarza na wejściu powoduje, że w danych wyjściowych występują bloki, które się powtarzają.
Tryb CBC pozwala nam sprawić, że nawet jeżeli jakieś bloki się powtarzają na wejściu to na wyjściu otrzymamy różne wartości. W celu uzyskania takiej właściwości wartość wynikowa jest teraz zależna nie tylko od danych wyjściowych, ale również od wartości poprzedniego zaszyfrowanego bloku danych.
Powyższy rysunek opisuje jak działa szyfrowanie danych w trybie CBC. Pierwszy blok danych jest traktowany trochę inaczej, ponieważ nie mamy z czym go XORować i dlatego potrzebujemy wektora inicjującego (https://pl.wikipedia.org/wiki/Wektor_inicjuj%C4%85cy) – na rysunku jest on oznaczony jako IV (Initialization Vector).
Mając przed oczami te dwa obrazki i kod z ćwiczenia 7. możemy w prosty sposób rozwiązać to zadanie:
def encode_cbc(self, data, key, iv):
result = []
data_chunks = self.get_blocks(data)
key_expanded = self.key_expansion(key)
for data_chunk in data_chunks:
iv = self.encode_block(bytearray(bytes_xor(data_chunk, iv)), key_expanded)
result += iv
return bytearray(result)
def decode_cbc(self, data, key, iv):
result = []
data_chunks = self.get_blocks(data)
key_expanded = self.key_expansion(key)
for data_chunk in data_chunks:
next_iv = list(data_chunk)
result += bytes_xor(self.decode_block(data_chunk, key_expanded), iv)
iv = next_iv
return bytearray(result).decode('ascii')
To na co trzeba zwrócić uwagę to moment w którym dane mają zostać XORowane przed przekazaniem ich do algorytmu AES.
Kod jak zwykle jest dostępny tutaj: https://gitlab.com/akoltys/cryptopals .