AVR-AES

Biblioteka została stworzona w celu umożliwienia szyfrowania i deszyfrowania danych na 8-bitowych mikrokontrolerach Atmel AVR. Posiada w sobie symetryczny szyfr blokowy zgodny ze standardem AES. Szyfrowany blok, jak również klucz, ma długość 128-bitów.

Budowa

Biblioteka zawiera w sobie cztery różne implementacje algorytmu AES nazwane: SMALL, MINI, FANTASTIC, FURIOUS, FAST. Autorem całej implementacji SMALL i MINI jestem ja. Pozostałe pochodzą ze strony http://point-at-infinity.org/avraes/ i zostały przetłumaczone z assemblera (w wersji dla kompilatora Atmel'a) na język C ze wstawkami asemblerowymi. Oprócz tłumaczenia zostały wprowadzone jeszcze drobne zmiany w kodzie źródłowym.

Rezultaty

Bibliotekę można konfigurować w celu dostosowania do własnych potrzeb. Gdy potrzebna jest duża szybkość działania i dysponuje się dużymi zasobami (duży mikrokontroler), maksymalna teoretyczna prędkość szyfrowania może dojść do ok. 95KB/s przy 16MHz. W przeciwnym wypadku, gdy potrzeba małego kodu, bibliotekę można zmniejszyć aż do ok. 282 bajtów kodu programu kosztem spadku wydajności do ok. 1.9KB/s przy 16MHz. Całkowite zapotrzebowanie na pamięć RAM można zmniejszyć do 43 bajtów. Kilka przykładowych konfiguracji i ich szczegółowe cechy można zobaczyć na rysunku obok. Rezultaty otrzymano po kompilacji w kompilatorze AVR-GCC 4.6.2 dla mikrokontrolera ATmega128 przy stopniu optymalizacji "-Os".

Download

Użycie

W celu dołączenia biblioteki wystarczy dodać plik "aes.c" do aplikacji i dołączyć (include) plik nagłówkowy "aes.h" do odpowiednich plików źródłowych. Następnie należy zmienić konfigurację biblioteki przez edycję odpowiednich definicji w pliku "aes.h". Najważniejsze jest wybranie implementacji definicją "AES_IMPLEMENTATION", ponieważ od tego zależy jak wygląda API biblioteki.

Implementacja SMALL i FANTASTIC

void aesCipher(unsigned char* key, unsigned char* data);

Szyfruje dane zapisane w data przy pomocy klucza key. Oba parametry muszą mieć długość 16 bajtów (128 bitów). Blok szyfrowany jest w miejscu, czyli zaszyfrowane dane nadpisują dane wejściowe. Skutkiem ubocznym jest to, że klucz również zmienia się i po zakończeniu przyjmuje wartość zwaną dalej kluczem zmodyfikowanym. Można powrócić do wartości początkowej klucza wykorzystując aesKeyRewind lub zapamiętaną wcześniej wartość.

void aesInvCipher(unsigned char* patched, unsigned char* data);

Deszyfruje dane zapisane w data przy pomocy zmodyfikowanego klucza patched. Oba parametry muszą mieć długość 16 bajtów (128 bitów). Blok szyfrowany jest w miejscu, czyli odszyfrowane dane nadpisują dane wejściowe. Skutkiem ubocznym jest to, że klucz zmodyfikowany również zmienia się i po zakończeniu jest równy oryginalnemu kluczowi. Klucz oryginalny można przekształcić na zmodyfikowany funkcją aesKeyPatch.

void aesKeyPatch(unsigned char* key);

Konwertuje klucz podany w key z klucza oryginalnego na klucz zmodyfikowany (patched).

void aesKeyRewind(unsigned char* patched);

Konwertuje klucz podany w key z klucza zmodyfikowanego na klucz oryginalny.

Należy zaznaczyć, że klucz zmodyfikowany w implementacji SMALL ma inną postać niż w implementacji FANTASTIC.

Implementacja FURIOUS i FAST

void aesCipher(const unsigned char* expanded, unsigned char* data);

Szyfruje dane zapisane w data przy pomocy klucza poszerzonego expanded. Dane muszą mieć długość 16 bajtów (128 bitów), klucz poszerzony 176 bajtów. Blok szyfrowany jest w miejscu. Klucz poszerzony otrzymuje się wywołując funkcję aesKeyExpand.

void aesInvCipher(const unsigned char* expanded, unsigned char* data);
void aesInvCipher(const unsigned char* patched, unsigned char* data);

Deszyfruje dane zapisane w data przy pomocy klucza poszerzonego expanded (impl. FURIOUS) lub zmodyfikowanego klucza poszerzonego patched (impl. FAST). Dane muszą mieć długość 16 bajtów (128 bitów), klucz 176 bajtów. Blok szyfrowany jest w miejscu. Klucz poszerzony (expanded) otrzymuje się wywołując funkcję aesKeyExpand. Zmodyfikowany klucz poszerzony (patched) otrzymuje się wywołując funkcję aesKeyExpand, a następnie aesKeyPatch.

void aesKeyExpand(const unsigned char* key, unsigned char* expanded);

Poszerza 16-bajtowy klucz key i zapisuje rezultat w expanded (176 batów).

void aesKeyPatch(unsigned char* expanded);

Konwertuje klucz poszerzony na zmodyfikowany klucz poszerzony. Ta funkcja istnieje tylko w implementacji FAST.

Implementacja MINI

void aesCipher(const unsigned char* key, unsigned char* data);

Szyfruje dane zapisane w data przy pomocy klucza key. Oba parametry muszą mieć długość 16 bajtów (128 bitów). Blok szyfrowany jest w miejscu, czyli zaszyfrowane dane nadpisują dane wejściowe. Klucz pozostaje bez zmian. W tej implementacji istnieje funkcja szyfrująca tylko w jedną stronę, ale można uzyskać deszyfrowanie stosując odpowiedni tryb blokowy, np. Cipher feedback (CFB), Output feedback (OFB), Counter (CTR).

char aesTempBuffer[21];

Jest to tymczasowy bufor wykorzystywany przez aesCipher. Jego zawartość nie ma znaczenia dla użytkownika. Został udostępniony, ponieważ przy deficycie pamięci można go użyć w dowolnym celu, ale należy pamiętać, że po wywołaniu aesCipher jego zawartość zostanie zmieniona.

Konfiguracja

W pliku "aes.h" można zmienić konfigurację biblioteki używając do tego odpowiednich definicji.

AES_IMPLEMENTATION - Wybór implementacji: 0 - SMALL, 1 - FANTASTIC, 2 - FURIOUS, 3 - FAST, 4 - MINI.

AES_CIPHER, AES_INVCIPHER, AES_KEYREWIND, AES_KEYPATCH, AES_KEYEXPAND - Określa, czy dana funkcja zostanie dołączona do biblioteki. Należy wyłączyć wszystkie nie wykorzystane funkcje w celu minimalizacji kodu wynikowego. Nazwy definicji odpowiadają nazwom funkcji.

Pozostałe definicje dotyczą tylko implementacji SMALL i MINI.

AES_SHORTSBOX - Użyj małej tablicy zamiast SBOX. Tablica SBOX zajmuje 256 bajtów pamięci programu, można ją zmniejszyć kosztem spadku wydajności. Czas szyfrowania przestaje być stały przy zastosowaniu tej opcji.

AES_SHORTSBOXSIZE - Rozmiar zredukowanej tablicy, jeżeli jest ustawione AES_SHORTSBOX lub AES_SHORTINVSBOX. Poprawne wartości: 10, 12, 16, 20, ..., 4*N, ..., 248, 252, 256. Rozmiar kodu programu zmienia się proporcjonalnie przy zmianie tej wartości. Czas obliczeń zwiększa się przy zmniejszaniu rozmiaru tablicy.

Pozostałe definicje dotyczą tylko implementacji SMALL.

AES_SHORTINVSBOX - Użyj małej tablicy zamiast INVSBOX. Tablica INVSBOX zajmuje 256 bajtów pamięci programu, można ją zmniejszyć kosztem spadku wydajności. Jeżeli AES_SHORTSBOX też jest ustawione, to zmniejszona tablica nie będzie duplikowana. Czas szyfrowania przestaje być stały przy zastosowaniu tej opcji. Definicja ta nie ma znaczenia jeżeli AES_INVCIPHER == 0.

AES_FASTSHROWS - Zastosuj szybszą implementację transformacji AES ShiftRows i InvShiftRows.

AES_FASTMIXCOL - Zastosuj szybszą implementację transformacji AES MixColumns i InvMixColumns. Definicja ma znaczenie tylko, gdy AES_CIPHER != 0 && AES_INVCIPHER != 0.

© 2012 Dominik Kilian