Режим гаммирования в блочном алгоритме шифрования

Гост 34.13

Режим гаммирования, в отличие от режима простой замены, позволяет шифровать сообщения произвольной длины без применения операции дополнения (паддинга). При этом исходное сообщение может быть разбито на блоки с размером меньшим размера одного блока используемого алгоритма блочного шифрования или равным ему.

В статье мы поговорим о том, как реализуется режим гаммирования, и попробуем написать все необходимые для его реализации функции.

Блочные алгоритмы шифрования ГОСТ 34.13

Для начал вот несколько ссылкок, про то, как применять блочные криптоалгоритмы «Кузнечик» и «Магма» для шифрования сообщений, размер которых превышает размер одного блока (для «Кузнечика» он составляет 16 байт, а для «Магмы» — 8 байт) с использованием режима простой замены (ECB, от английского Electronic Codebook). Этот режим описан в ГОСТ 34.13—2015 «Информационная технология. Криптографическая защита информации. Режимы работы блочных шифров». Этот нормативный документ, помимо режима простой замены, определяет еще несколько способов применения блочных шифров, а именно:

  • режим гаммирования (CTR, от английского Counter);
  • режим гаммирования с обратной связью по выходу (OFB, от английского Output Feedback);
  • режим простой замены с зацеплением (CBC, от английского Cipher Block Chaining);
  • режим гаммирования с обратной связью по шифртексту (CFB, от английского Cipher Feedback);
  • режим выработки имитовставки (MAC, от английского Message Authentication Code).

Что ж, давайте разберемся, как работает гаммирование и как его применять на практике.

Общие принципы реализации режима гаммирования

В настоящее время ГОСТ 34.12—2015 и ГОСТ 34.13—2015 обрели статус межгосударственных (в рамках нескольких государств СНГ) и получили наименования соответственно ГОСТ 34.12—2018 и ГОСТ 34.13—2018. Оба стандарта введены в действие в качестве национальных стандартов Российской Федерации с 1 июня 2019 года.

Гамма шифра

Гаммирование — это наложение (или снятие при расшифровке сообщений) на открытое (или зашифрованное) сообщение так называемой криптографической гаммы. Криптографическая гамма — это последовательность элементов данных, которая вырабатывается с помощью определенного алгоритма. Наложение (или снятие) гаммы на блок сообщения в рассматриваемом нами стандарте реализуется с помощью операции побитного сложения по модулю 2 (XOR). То есть при шифровании сообщений каждый блок открытого сообщения ксорится с блоком криптографической гаммы, длина которого должна соответствовать длине блоков открытого сообщения. При этом, если размер блока исходного текста меньше, чем размер блока гаммы, блок гаммы обрезается до размера блока исходного текста (выполняется процедура усечения гаммы).

Принцип реализации режима гаммирования при зашифровывании сообщения
Принцип реализации режима гаммирования при зашифровывании сообщения

Для дешифровки закрытого сообщения необходимо произвести обратную операцию. То есть каждый блок зашифрованного сообщения ксорится с блоком гаммы, и на выходе мы имеем требуемое расшифрованное сообщение.

Принцип реализации режима гаммирования при расшифровывании сообщения
Принцип реализации режима гаммирования при расшифровывании сообщения

В большинстве случаев размер блока исходного текста принимается равным размеру блока используемого алгоритма блочного шифрования (напомню, это 16 байт при использовании алгоритма «Кузнечик» или 4 байт при использовании «Магмы»), поэтому процедура усечения блока гаммы может понадобиться только для последнего блока исходного текста, в случае, когда общая длина сообщения не кратна размеру одного блока и последний блок получается неполный.

Усечение блока гаммы при несовпадении размеров блока исходного сообщения и блока гаммы
Усечение блока гаммы при несовпадении размеров блока исходного сообщения и блока гаммы

Чтобы обеспечить высокую стойкость шифрования, блоки гаммы должны отличаться друг от друга, а также иметь случайный (или псевдослучайный) характер. В данном примере блоки различаются благодаря так называемому инициализирующему вектору, значение которого меняется от блока к блоку. Псевдослучайность блоков гаммы при этом реализуется путем шифрования этого вектора с использованием выбранного алгоритма (мы используем «Магму»).

Инициализирующий вектор

Значение этого вектора формируется из так называемой синхропосылки, которая представляет собой число определенной длины. Для режима гаммирования длина этого числа должна быть равна половине размера одного блока используемого алгоритма блочного шифрования. Само значение синхропосылки для режима гаммирования должно быть уникальным для каждого цикла шифрования, проведенного с использованием одинаковых ключей, при этом требований к конфиденциальности синхропосылки не предъявляется (то есть ее можно передавать в открытом виде вместе с зашифрованным сообщением).

РЕКОМЕНДУЕМ:
Поиск энтропии на микросхеме для повышения стойкости шифра

В режиме гаммирования инициализирующий вектор формируется дополнением нулями синхропосылки до размера одного блока используемого алгоритма блочного шифрования. В случае «Магмы» длина синхропосылки равна четырем байтам, длина инициализирующего вектора — восьми. Вторая часть инициализирующего вектора (заполненная нулями) будет использоваться в качестве того самого счетчика (Counter), который и лег в основу англоязычного сокращения CTR.

Выработка инициализирующего вектора в режиме гаммирования с алгоритмом блочного шифрования «Магма»
Выработка инициализирующего вектора в режиме гаммирования с алгоритмом блочного шифрования «Магма»

Очередной блок гаммы шифра получается благодаря шифрованию значения счетчика (его начальное значение равно инициализирующему вектору) с помощью выбранного алгоритма блочного шифрования, при этом после выработки очередного блока гаммы значение счетчика увеличивается на единицу.

Выработка гаммы шифра
Выработка гаммы шифра

Зашифровываем и расшифровываем

В целом процесс шифрования выглядит следующим образом.

Зашифровывание в режиме гаммирования
Зашифровывание в режиме гаммирования

На рисунке показаны в том числе и операции усечения гаммы шифра (обозначены буквами T с индексом n). Как я уже говорил, эта операция в большинстве случаев не применяется (когда размеры блоков исходного текста и блоков гаммы шифра совпадают). Операция усечения гаммы шифра может понадобиться для последнего блока (на рисунке обозначена буквой T с индексом s), в случае, когда длина исходного сообщения не кратна размеру блока гаммы шифра.

Дешифровка полностью повторяет процесс шифрования за исключением того, что на вход подают зашифрованный текст, а на выходе получают расшифрованный, который совпадает с исходным.

Дешифровка в режиме гаммирования
Дешифровка в режиме гаммирования

Пишем необходимые функции

Поскольку процессы шифрования и дешифровки в режиме гаммирования идентичны, определим одну общую функцию для шифрования и расшифровки строки и одну общую функцию для аналогичной работы с файлом.

Ксорим блоки гаммы и текста

Для начала определим функцию сложения блоков по модулю 2.

Здесь все просто и можно, я думаю, обойтись без пояснений.

Шифруем строку

Здесь GOST\_Magma\_Expand\_Key — это функция развертывания ключей для алгоритма «Магма», а GOST\_Magma\_Encrypt — функция шифрования блока алгоритмом «Магма» из нашей статьи о «Магме». Если для шифрования в режиме гаммирования захочешь использовать «Кузнечик», то эти две функции необходимо заменить на соответствующие функции «Кузнечика» ( GOST\_Kuz\_Expand\_Key и GOST\_Kuz\_Encrypt из статьи про «Кузнечик»).

На вход функции подаются:

  • текущее значение инициализирующего вектора (ctr);
  • открытое сообщение (in\_buf);
  • указатель на буфер для зашифрованного сообщения (out\_buf);
  • ключ шифрования (key);
  • длина шифруемого сообщения (size).

Шифруем файл целиком

Здесь то же самое. Шифруем и расшифровываем файл одной функцией.

Здесь на вход функции подаем:

  • файл-источник, содержимое которого необходимо зашифровать (src);
  • файл, куда будет записано зашифрованное содержимое файла-источника (in\_buf);
  • значение синхропосылки (init\_vect);
  • ключ шифрования (key);
  • размер шифруемого файла (size).

Поскольку размер файла, который нужно зашифровать, может быть большим, его считывание производится не целиком за один раз, а по частям, и константа BUFF\_SIZE как раз и определяет размер буфера, куда будет считана очередная часть.

Увеличиваем значение счетчика на единицу

В функции шифрования строки CTR\_Crypt значение счетчика для выработки очередного блока гаммы шифра увеличивают вызовом функции inc\_ctr. Ее опишем следующим образом:

Если внимательно посмотреть, то можно увидеть знакомые строчки из функции сложения по модулю n (в данном случае n соответствует размеру блока). С помощью этих строчек к текущему значению счетчика прибавляется массив, по размеру равный одному блоку, в последний байт которого записана единица.

Удаляем ключи из памяти

То место в памяти, где лежат итерационные ключи шифрования, после их использования необходимо очистить. Для этого напишем простую функцию:

В нашем случае функция предназначена для работы с «Магмой». Для «Кузнечика», я думаю, ты сможешь написать такую же функцию сам, если понадобится.

Ссылки

Заключение

Теперь вы знаете, как применять блочные алгоритмы шифрования для работы с сообщениями произвольной длины с использованием режима гаммирования. Это позволяет избежать основного недостатка режима прямой замены (если шифруемое сообщение содержит в себе одинаковые или повторяющиеся блоки, то на выходе мы тоже получим зашифрованные одинаковые или повторяющиеся блоки).

РЕКОМЕНДУЕМ:
Что такое и как работает IPsec

В этой статье режим гаммирования рассмотрен применительно к алгоритму «Магма», но если понадобится «Кузнечик», то нет проблем — все необходимые функции мы уже написали.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий