Skip to content

vselenaya/Kuznechik

Repository files navigation

Реализация блочного шифра <<Кузнечик>>

Данный проект представляет собой реализацию российского блочного шифра <<Кузнечик>>, утверждённого в ГОСТ Р 34.12-2015.

Данный проект чётко следует документации шифра, описанной в стандарте (ГОСТе) и реализует функции согласно ей. Блочный шифр вообще - это функция, осуществляющая отображение блоков (битовых строк фиксированной длины) в перестановку на этом множестве блоков. Блочный шифр параметризуется ключом. <<Кузнечик>> работает с блоками длины 128 бит и ключом длины 256 бит.

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

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

Код проекта снабжён большим количеством комментариев, в которых подробно описывается, что и как делается, в том числе описана оптимизация шифрования.

Струтктура проекта и кода

  • В файле kuznechik.c реализованы функции, необходимые для работы блочного шифра - всё, что было описано в стандарте.

  • В файле test_correct.c находится код для тестирования функций блочного шифра. Все примеры, на которых производится тестирование, тоже взяты из стандарта.

  • В файле test_speed.c находится код для измерения скорости работы функций шифрования (обычной, написанной по стандарту и оптимизированной).

  • В файле main.c производится лишь запуск тестов. При необходимости его можно поменять, обеспечив требуемую функциональность.

Вообще для использования кода (то есть для шифрования и дешифрования блоков) необходимо перед шифрованием и дешифрованием сделать следующее:

  1. Сначала запустить функцию compute_consts(), которая посчитает необходимы константы для работы алгоритма.
  2. Затем запустить функцию expand_key(master_key), куда в качестве параметра передаётся мастер-ключ - основной ключ блочного шифра (из него потом генерирутся другие ключи внутри алгоритма) длины 256 бит (это и есть основной секрет, который нельзя разглашать для работы шифрования) - то есть фактически массив из 256 бит данных.
  3. Предыдущих двух функций достаточно для обычной работы шифра, но если нужно воспользоваться функцией быстрого шифрования, то перед этим нужно запустить функцию compute_values_L(), которая посчитает еще значения.
  4. Для шифрования используется функция kuznechik_encrypt(), для дешифрования - функция kuznechik_decrypt(). В каждую из них передаются указатели на память, откуда считать блок, и куда записать результат (шифрования или дешифрования).

Для лучшего понимания, стоит обратить внимание на код в test_correct.c, где все эти функции запускаются (Сами функции из kuznechik.c).

Некоторые детали реализации

Сам блок, который занимает 128 бит, хранится в виде массива из 16 элементов. Каждый элемент типа uint8_t и занимает ровно 1 байт. Таким образом, блок в коде представляется массивом из 16 байтов.

Для считывания примеров, записанных в документации в виде шестандцатиричных строк вида ffeeddccbbaa99881122334455667700, используется функция hexstring_to_array() из файла test_correct.c. Для тех, кто не знает, как это работает: такая строка кодирует 128 бит данных, а именно каждый символ строки - шестнадцатиричная цифра, каждые две цифры образуют двузначное шестнадцатиричное число, а оно принимает значения от 0 до 255. То есть две шестнадцатиричные цифры кодируют один байт. Таким образом, данная строка - это 16 байт = 128 бит. Нужно обратить внимание, что в российских стандартах примеры пишутся со старшего байта: то есть в приведённом примере строка имеет старший байт = ff (= 255) и младший байт, равный 00 (= 0).

Оптимизация шифрования заключается в том, чтобы, воспользовавшись линейностью одного из отображений внутри блочного шифра, сделать предподсчёт: посчитать это линейное преобразование на блоках, где только один байт не равен 0. Так как байт принимает значения от 0 до 255, а всего байтов в блоке 16, то получается небольшая матрица заранее посчитанных значений. А далее, при применении, можно просто брать уже посчитанные значения из таблицы, и складывать их (пользуясь линейностью), получая результат преобразования на вем входе.

Запуск кода

В проекте есть Makefile, который запускается командой make (из той же папки, где находится весь проект) и автоматически компилирует все исходные файлы.

После сброки (компиляции) проекта появляется исполняемый файл main, запустив который ./main, должно вывестись такое сообщение:

Начинается тестирование корректности кода...
--> Тестирование преобразований S, R, L завершено
--> Тестирование ключей завершено
--> Тесты шифрования завершены
--> Тесты ускоренного шифрования завершены
Тестирование корректности окончено. Если не было выведено сообщений об ошибках, значит тесты пройдены верно!

Начинаем тестирование скорости...
Обычное шифрование:
--> Зашифровано 10000 блоков за 1.53 секунд
--> Скорость шифрования ~ 0.83 Мбит в секунду
Тест ускоренного шифрования:
--> Зашифровано 1000000 блоков за 1.18 секунд
--> Скорость шифрования ~ 108.02 Мбит в секунду

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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published