В прошлой статье мы разобрали AES шифрование в режиме Single block, в этой статье мы продвинемся немного дальше и познакомимся с работой в режиме Multiple blocks — это интересный режим шифрования, когда вы не ограничены длиной сообщения в 128 бит, а можете шифровать сразу большие массивы данных.
Режим Multiple blocks
Режим Multiple blocks — это режим в котором работа происходит сразу с несколькими блоками по 128 бит, то есть мы можем шифровать значительные массивы данных и, соответственно, потом их расшифровывать. Длина сообщения (массива) должна быть кратна 16-и байтам.
Библиотека AESLib поддерживает работу в этом режиме с ключами 128 (16 uint8_t) или 256 бит (32 uint8_t). Ключ для шифрования данных и их расшифровки применяется один и тот же.
В библиотеке AESLib присутствуют две функции для шифрования данных в режиме Multiple blocks, они имеют одинаковое устройство, различие заключается только в длине ключа 128 или 256 бит. Кроме ключа на вход этой функции подаются массив данных и его длина.
void aes128_enc_multiple(const uint8_t* key, void* data, const uint16_t data_len);
void aes256_enc_multiple(const uint8_t* key, void* data, const uint16_t data_len);
Библиотека AESLib содержит также соответствующие функции для расшифровки ранее зашифрованных массивов. Устройство этих функций аналогично рассмотренным выше — им в качестве аргументов передаются ключ для расшифровки сообщения, массив данных и его длина.
void aes128_dec_multiple(const uint8_t* key, void* data, const uint16_t data_len);
void aes256_dec_multiple(const uint8_t* key, void* data, const uint16_t data_len);
Другими словами этот режим называется ECB (Electronic Codebook) «режим электронной кодовой книги» или «режимом простой замены». В предыдущих статьях этого цикла мы подробно разбирали достоинства и недостатки этого режима.
Рассмотрим теперь практические примеры AES шифрования в режиме Multiple blocks.
Шифрование в режиме Multiple blocks
Рассмотрим пример шифрования массива данных из 32 байт с использованием 128-битного ключа. Массив данных из 32 байт выбран исключительно для примера — длина этого массива могла бы быть любой, кратной 16-и байтам. В нашем случае массив (условно) состоит из двух блоков по 16 байт (128 бит).
/* AES Multiple 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,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}; const uint16_t len = 32; void setup() { Serial.begin(115200); Serial.println(F("AES Multiple block Encrypt test start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes128_enc_multiple(key, data, len); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 32; 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};
Далее задаём массив данных data (размером 256 бит). Тут значения байтов данных тоже выбраны произвольным образом
byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
и указываем длину нашего массива данных.
const uint16_t len = 32;
В начале работы скетча выводим на экран (для контроля) содержимое массива data.
Serial.print(F("Data: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println();
Шифруем данные по алгоритму AES, передавая функции aes128_enc_multiple массивы с данными и ключом шифрования, а также длину массива данных.
aes128_enc_multiple(key, data, len);
Далее выводим на экран результат шифрования.
Serial.print(F("Encrypt: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println();
И видим, что операция по шифрованию данных прошла успешно. Вот скриншот результата работы нашего скетча:
Шифрование с ключом 256 бит
Теперь немного модифицируем наш скетч для шифрования с ключом 256 бит. Здесь ключ становится длиннее (и более надёжным), а размер блока данных остаётся неизменным.
Код примера шифрования с ключом 256 бит:
/* AES Multiple 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,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}; const uint16_t len = 32; void setup() { Serial.begin(115200); Serial.println(F("AES Multiple block Encrypt 256 start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes256_enc_multiple(key, data, len); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 32; 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_multiple(key, data, len);
Результат работы по шифрованию (неизменного) блока данных
byte data[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
, разумеется, отличается от предыдущего, что можно увидеть на следующем скриншоте.
Расшифровка в режиме Multiple blocks
Теперь давайте разберём расшифровку в режиме Multiple blocks ранее зашифрованного массива данных. В этом примере мы будем работать с массивом данных размером 32 байта с использованием 128-битного ключа.
Код примера:
/* AES Multiple 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,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}; const uint16_t len = 32; void setup() { Serial.begin(115200); Serial.println(F("AES Multiple block Decrypt test start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes128_enc_multiple(key, data, len); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes128_dec_multiple(key, data, len); Serial.print(F("Decrypt: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); } void loop() { }
Здесь мы добавляем функцию расшифровки зашифрованных перед этим данных.
aes128_dec_multiple(key, data, len);
И выводим на экран результат расшифровки.
Serial.print(F("Decrypt: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println();
На скриншоте видно, что результат расшифровки полностью совпадает с исходными данными. Это значит, что наш скетч работает корректно с алгоритмом AES шифрования.
Расшифровка с ключом 256 бит
Модифицируем скетч расшифровки для работы с ключом 256 бит. Ключ становится длиннее, а размер массива данных остаётся неизменным — 32 байта.
Код примера расшифровки с ключом 256 бит:
/* AES Multiple 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,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}; const uint16_t len = 32; void setup() { Serial.begin(115200); Serial.println(F("AES Multiple block Decrypt 256 start...")); Serial.print(F("Data: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes256_enc_multiple(key, data, len); Serial.print(F("Encrypt: ")); for (byte i = 0; i < 32; i++) { Serial.print(data[i]); Serial.print(F(" ")); } Serial.println(); aes256_dec_multiple(key, data, len); Serial.print(F("Decrypt: ")); for (byte i = 0; i < 32; 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_multiple(key, data, len);
и функцию расшифровки тоже на 256-битную.
aes256_dec_multiple(key, data, len);
Результат работы по 256-битному AES шифрованию массива данных можно увидеть на следующем скриншоте.
Всё работает абсолютно корректно и так, как и ожидалось.
Заключение
На этом уроке мы освоили практическое шифрование данных по стандарту AES в режиме Multiple blocks. В следующих статьях мы продолжим знакомство с шифрованием на микроконтроллерах и разберём работу других режимах.
Ссылки по теме
AES: Работа в режиме Single block
AES: Работа в режиме Multiple blocks