logo
+7 (495) 997-37-74
Москва, ул.Международная, 15

AES: Работа в режиме Multiple blocks

В прошлой статье мы разобрали 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: Стандарт шифрования AES

AES: Библиотека AESLib

AES: Работа в режиме Single block

AES: Работа в режиме Multiple blocks