Продолжаем знакомство с AES шифрованием и специализированной библиотекой AESLib и в этой статье подробно разберём работу по шифрованию данных и их расшифровке в т. н. режиме «Single block».
Режим Single block
Режим Single block — это самый простой режим работы по AES шифрования. В этом режиме работа происходит с одиночными (single) блоками по 128 бит, то есть мы можем шифровать отдельные блоки (массивы) по 16 байт и, соответственно, потом их расшифровывать.
Библиотека AESLib поддерживает работу в этом режиме с ключами 128 (16 uint8_t) или 256 бит (32 uint8_t). Ключ для шифрования данных и их расшифровки применяется один и тот же.
В библиотеке AESLib присутствуют две функции для шифрования данных в режиме Single block, они имеют одинаковое устройство, различие заключается только в длине ключа 128 или 256 бит (длина самих шифруемых данных в обоих случаях одинакова — 16 байт).
void aes128_enc_single(const uint8_t* key, void* data);
void aes256_enc_single(const uint8_t* key, void* data);
Библиотека AESLib содержит также соответствующие функции для расшифровки ранее зашифрованных блоков. Устройство этих функций аналогично рассмотренным выше — им в качестве аргументов передаются блок данных и ключ для расшифровки сообщения.
void aes128_dec_single(const uint8_t* key, void* data);
void aes256_dec_single(const uint8_t* key, void* data);
Режим шифрования Single block может использоваться для работы с небольшими объёмами данных, например, его удобно использовать для защиты передаваемых по проводным и беспроводным сетям пакетов. Если ваше сообщение меньше 16-и байт, то его можно дополнить нулями до длины 128 бит (а после расшифровки провести соответствующую операцию по удалению лишних данных).
Рассмотрим теперь пример по AES шифрованию в режиме Single block.
Шифрование в режиме Single block
Обратимся к примеру из нашей предыдущей статьи и подробно разберём AES шифрование блока данных в режиме Single block.
Рассмотрим пример шифрования одиночного блока данных 16 байт (128 бит) с использованием 128-битного ключа.
/* AES Single block Encrypt test */ #include <AESLib.h> uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; void setup() { Serial.begin(115200); Serial.println(F("AES Single block Encrypt test start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes128_enc_single(key, data); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); } void loop() { }
Здесь мы вначале подключаем библиотеку AESLib.
#include <AESLib.h>
Затем задаём 16-байтовый ключ шифрования (значение ключа было выбрано произвольно).
uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
Далее задаём блок данных (размером 128 бит). Тут значения байтов данных тоже выбраны произвольным образом.
byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
Выводим на экран (для контроля) содержимое массива data.
Serial.print(F("Data: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println();
Шифруем данные по алгоритму AES, передавая функции aes128_enc_single() массивы с данными и ключом шифрования.
aes128_enc_single(key, data);
Далее выводим на экран результат шифрования.
Serial.print(F("Encrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println();
И видим, что операция по шифрованию данных прошла успешно. Вот скриншот результата работы нашего скетча:
Шифрование с ключом 256 бит
Теперь немного модифицируем наш скетч для шифрования с ключом 256 бит. Здесь ключ становится длиннее (и более надёжным), а размер блока данных остаётся неизменным — 128 бит (обратите внимание: длина ключа в два раза больше длины шифруемых данных).
Код примера шифрования с ключом 256 бит:
/* AES Single block Encrypt 256 */ #include <AESLib.h> uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; void setup() { Serial.begin(115200); Serial.println(F("AES Single block Encrypt 256 start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes256_enc_single(key, data); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); } void loop() { }
Здесь мы меняем 16-байтовый ключ шифрования
uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
на 32-байтовый (256 бит)
uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
и заменяем функцию библиотеки на соответствующую.
aes256_enc_single(key, data);
Результат работы по шифрованию (неизменного) блока данных
byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
, разумеется, отличается от предыдущего, что можно увидеть на следующем скриншоте.
Расшифровка в режиме Single block
Теперь давайте разберём расшифровку в режиме Single block ранее зашифрованных блоков данных. В этом примере мы будем работать с одиночными блоками данных по 16 байт (128 бит) с использованием 128-битного ключа.
Код примера:
/* AES Single block Decrypt test */ #include <AESLib.h> uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; void setup() { Serial.begin(115200); Serial.println(F("AES Single block Decrypt test start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes128_enc_single(key, data); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes128_dec_single(key, data); Serial.print(F("Decrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); } void loop() { }
Здесь мы добавляем функцию расшифровки зашифрованных перед этим данных.
aes128_dec_single(key, data);
И выводим на экран результат расшифровки.
Serial.print(F("Decrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println();
На скриншоте видно, что результат расшифровки полностью совпадает с исходными данными. Это значит, что наш скетч работает корректно с алгоритмом AES шифрования.
Расшифровка с ключом 256 бит
Модифицируем скетч расшифровки для работы с ключом 256 бит. Ключ становится длиннее, а размер блока данных остаётся неизменным — 128 бит.
Код примера расшифровки с ключом 256 бит:
/* AES Single block Decrypt 256 */ #include <AESLib.h> uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; void setup() { Serial.begin(115200); Serial.println(F("AES Single block Decrypt 256 start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes256_enc_single(key, data); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes256_dec_single(key, data); Serial.print(F("Decrypt: ")); for (byte i = 0; i < 16; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); } void loop() { }
Здесь мы меняем 16-байтовый ключ шифрования (128 бит) на 32-байтовый (256 бит)
uint8_t key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
Заменяем функцию шифрования на соответствующую
aes256_enc_single(key, data);
и функцию расшифровки тоже на 256-битную.
aes256_dec_single(key, data);
Результат работы по 256-битному AES шифрованию блока данных можно увидеть на следующем скриншоте.
Как вы видите, всё работает абсолютно корректно и ожидаемо.
Заключение
Сегодня вы освоили практическое шифрование данных по стандарту AES, правда только в самом простом варианте работы в режиме Single block, но в следующих статьях мы продолжим знакомство с этой увлекательной темой и рассмотрим AES шифрование и в других, более продвинутых режимах.
Ссылки по теме
AES: Работа в режиме Single block