AES на МК

Иногда возникает задача передать определённую информацию, но сделать это так, чтобы доступ к ней не смог получить тот, для кого она не предназначена, казалось бы, это невозможно, но выход есть. Шифрование — процесс преобразование информации в нечитаемый вид, применяется издревле в целях сделать информацию бесполезной без ключа.

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

Проект для IAR STM8L

Оставить комментарий