W tym ćwiczeniu zapoznajemy się z szyfrowaniem AES w nowym trybie – CTR. Jest to tryb licznikowy i polega na tym, że zamiast szyfrować dane, szyfrowana jest wartość licznika a wynik szyfrowania jest XORowany z danymi, które chcemy zabezpieczyć. Przy każdym kolejnym bloku danych, licznik jest zwiększany. Początkowa wartość licznika nazywana jest NONCE, ponieważ powinna być użyta tylko raz. Każda kolejna wiadomość powinna być szyfrowany z inną wartością NONCE.
W tym zadaniu rozbudowałem wcześniej stworzoną klasę CustomAES o wsparcie dla nowego trybu. Moja implementacja wygląda następująco:
def encode_ctr(self, data, key, iv):
if iv != None and type(iv) != c_uint64:
return None
if iv != None:
self.M_ENONCE = iv
self.M_ECNTR = c_uint64(0)
self.M_NONCE = self.M_ENONCE
self.M_CNTR = self.M_ECNTR
result = []
data_chunks = self.get_blocks(data)
key_expanded = self.key_expansion(key)
for data_chunk in data_chunks:
tmpCtr = bytearray(self.M_NONCE) + bytearray(self.M_CNTR)
tmpResultChunk = self.encode_block(tmpCtr, key_expanded)
result += bytearray(bytes_xor(tmpResultChunk, data_chunk))
self.M_CNTR.value += 1
if self.M_CNTR.value == 0:
self.M_NONCE.value += 1
self.M_ENONCE = self.M_NONCE
self.M_ECNTR = self.M_CNTR
return bytearray(result)
def decode_ctr(self, data, key, iv):
if iv != None and type(iv) != c_uint64:
return None
if iv != None:
self.M_DNONCE = iv
self.M_DCNTR = c_uint64(0)
self.M_NONCE = self.M_DNONCE
self.M_CNTR = self.M_DCNTR
result = []
data_chunks = self.get_blocks(data)
key_expanded = self.key_expansion(key)
for data_chunk in data_chunks:
tmpCtr = bytearray(self.M_NONCE) + bytearray(self.M_CNTR)
tmpResultChunk = self.encode_block(tmpCtr, key_expanded)
result += bytearray(bytes_xor(tmpResultChunk, data_chunk))
self.M_CNTR.value += 1
if self.M_CNTR.value == 0:
self.M_NONCE.value += 1
self.M_DNONCE = self.M_NONCE
self.M_DCNTR = self.M_CNTR
return bytearray(result)
Właściwie ciężko coś więcej dodać, więc ten wpis będzie wyjątkowo krótki. Cały kod do znalezienia na: https://gitlab.com/akoltys/cryptopals .