Иногда возникает задача передать определённую информацию, но сделать это так, чтобы доступ к ней не смог получить тот, для кого она не предназначена, казалось бы, это невозможно, но выход есть. Шифрование — процесс преобразование информации в нечитаемый вид, применяется издревле в целях сделать информацию бесполезной без ключа.
AES
Алгоритм AES — алгоритм блочного шифрования, второе имя Rijndael имеет размер блока 128 бит или 16 байт, длинна ключа 128 или 192 или 256 бит. Блоки данных на выходе имеют такую же длину как и на входе.
Вот именно этот алгоритм шифрования я и предлагаю использовать в нашем канале связи или любых других данных. Не изобретая велосипед, я воспользуюсь готовой реализацией для AVR. Из платформенных зависимостей у этой библиотеки всего ничего. Про назначение фалов этой библиотеки можно почитать там же. Скачиваем библиотеку, на всякий случай я прикрепил фал с исходной библиотекой к статье.
Портировать я буду на STM8L. При необходимости вы можете изучить использование и работу библиотеки не имея ни отладочной платы ни программатора, проект в архиве настроен на симулирование железа.
Для тестов я выбрал длину ключа 128 бит. Добавим в наш чистый проект все сишные файлы библиотеки кроме
aes192_enc.c
aes192_dec.c
aes256_enc.c
aes256_dec.c
эти файлы нужны при длине ключа 256 или 192.
По задумке авторов в файле gf256mul.s содержится функция на ассемблере, которая позволяет экономить ресурсы контролера, желающие портировать на ассемблер целевой платформы могут это сделать, я же воспользуюсь сишной версией этой функции.
Второе что сделать, это устранить зависимость АВРовского доступа к константантам во флеш памяти:
Находим и удаляем(или коментируем) все строки
1 | #include avr/pgmspace.h; |
Заменяем все
1 | #include <stdint.h> |
на
1 | #include "stm8l15x.h" |
эта замена зависит от платформы, на которую вы переносите библиотеку
Находим и убираем все квалификаторы PROGMEM.
Затем ищем (проще искать попытавшись построить проект, и просто выбирая ошибки компилятора) все вызовы функции pgm_read_byte и модифицируем доступ к переменной, вызов
1 | pgm_read_byte(aes_invsbox+state->s[i]); |
меняется на
1 | aes_invsbox[(state->s[i])]; |
вызов
1 | pgm_read_byte(aes_sbox+state->s[i]); |
меняется на
1 | aes_sbox[(state->s[i])]; |
а блок
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | if(i!=next_nk){ if(nk==8 && i%8==4){ tmp.v8[0] = pgm_read_byte(aes_sbox+tmp.v8[0]); tmp.v8[1] = pgm_read_byte(aes_sbox+tmp.v8[1]); tmp.v8[2] = pgm_read_byte(aes_sbox+tmp.v8[2]); tmp.v8[3] = pgm_read_byte(aes_sbox+tmp.v8[3]); } } else { next_nk += nk; aes_rotword(&(tmp.v32)); tmp.v8[0] = pgm_read_byte(aes_sbox+tmp.v8[0]); tmp.v8[1] = pgm_read_byte(aes_sbox+tmp.v8[1]); tmp.v8[2] = pgm_read_byte(aes_sbox+tmp.v8[2]); tmp.v8[3] = pgm_read_byte(aes_sbox+tmp.v8[3]); tmp.v8[0] ^= pgm_read_byte(rc_tab+rc); rc++; } |
Надо заменить на
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | if(i!=next_nk){ if(nk==8 && i%8==4){ tmp.v8[0] = aes_sbox[(tmp.v8[0])]; tmp.v8[1] = aes_sbox[(tmp.v8[1])]; tmp.v8[2] = aes_sbox[(tmp.v8[2])]; tmp.v8[3] = aes_sbox[(tmp.v8[3])]; } } else { next_nk += nk; aes_rotword(&(tmp.v32)); tmp.v8[0] = aes_sbox[(tmp.v8[0])]; tmp.v8[1] = aes_sbox[(tmp.v8[1])]; tmp.v8[2] = aes_sbox[(tmp.v8[2])]; tmp.v8[3] = aes_sbox[(tmp.v8[3])]; tmp.v8[0] ^= rc_tab[rc]; rc++; } |
На данный момент проект должен нормально компилироватся, однако будут вылазить Warning[Pa050]: non-native end of line sequence detected мне не известен способ быстрого исправления подобных ошибок, поэтому я просто подавлю их в настройках проекта.
Использование шифрования
Для теста создадим переменную testArray, заполним её данными
После шифрования содержимое выглядит совсем не так, как хотелось бы злоумышленнику 🙂
Но тот, кто имеет ключ легко может восстановить нормальный вид
Тестирование производительности
Для тестирования я взял железо основанное на STM8L152C6T6, интервалы измерял ногодрыганием. Вот что получилось.
Оптимизация кода | ||||||
None | Low | Medium | High Speed | High Size | High balanced | |
Время шифрования | 107.9ms | 107.5ms | 60.4ms | 50ms | 59.2ms | 57.5ms |
Время дешифрования | 138.9ms | 138.3ms | 89.8ms | 78ms | 90.1ms | 86.6ms |
Во всех случаях тактовая частота была 1MHz, размер тестового пакета составил 16 байт.
Часть библиотеки AVR Cripto Lib, ответственная за AES