/* * * MagmaEncryptor.h * * Библиотека для шифрования (с аутентификацией), построенная на основе * шифра "Магма" (в версии ГОСТ Р 34.12-2015). * * Состав: * реализация шифра (криптопримитив); * реализация шифрования в режиме счётчика (гаммирования); * реализация схемы аутентифиукации сообщений CMAC * (на базе шифра); * * Версия: 0.1beta от 11/12/2016 * Автор: Александр Венедюхин * Сайт: https://dxdt.ru/ * Условия использования: свободное распространение, использование * без ограничений. * Страница библиотеки: https://dxdt.ru/arduino-crypto/ * * Пример: * * --- * * MagmaEncryptor M; * uint32_t nonce; * uint16_t len; * byte MAC[8]; * byte plain_text[19]; * byte cipher_text[19]; * * nonce = 127; * len = 19; * * M.setKeys(c_key, MAC_key); * * M.lock(&nonce, plain_text, cipher_text, len, MAC); * * --- * * Логика работы достаточно подробно описана ниже, в комментариях внутри * исходного кода. * * "Магма" (известен также как ГОСТ 28147-89) - блочный симметричный шифр, * с разрядностью блока 64 бита и разрядностью ключа - 256 бит. * * С целью повышения быстродействия и получения более компактного кода * криптопримитив шифра для микроконтроллера "Ардуино" целиком реализован на * inline-ассемблере - функция DoCipher(). * * Библиотека обеспечивает шифрование/расшифрование сообщений с аутентификацией - * соответственно, функции (методы) lock() и unlock(). * * Для работы необходимо загрузить действующие ключи. _Обязательно_ * использование двух различных ключей: для шифрования и аутентификации. * * Для аутентификации применяется алгоритм CMAC (NIST SP 800-38B). В состав * сообщения, для вычисления кода аутентификации (имитовставки) включается * значение nonce. Это же значение nonce должно использоваться для генерации * ключевого потока. Nonce с данным ключом шифрования может быть использовано * только один раз. * * Предполагается, что узлы, обменивающиеся защищёнными данными, используют * синхронное значение nonce. Это значение может (но не должно) передаваться * вместе с сообщением, в открытом виде. * */ #ifndef MagmaEncryptor_h #define MagmaEncryptor_h #include "Arduino.h" class MagmaEncryptor{ private: const byte pi[64] = /* * * 64 байта подстановок: оригинальные подстановки Pi (используются таблицы из ГОСТ Р 34.12-2015) * объединены в байты, соответственно 4-битным блокам, к которым они применяются. Это экономит * память. Число 64 соответствует ограничениям команды ADIW ассемблера AVR. * */ { 0x6C,0x84,0x26,0x32,0x9A,0xA5,0x5B,0xC9,0x1E,0xE8,0x4D,0x77,0xB0,0xD3,0xF,0xF1, 0xCB,0x83,0x25,0x18,0xD2,0x4F,0xFA,0x6D,0x7E,0x1,0xA7,0x54,0x3C,0xE9,0x96,0xB0, 0x57,0xDF,0xF5,0x6A,0x98,0x21,0xC6,0xAD,0xB0,0x79,0x83,0x1E,0x4B,0x34,0xE2,0xC, 0x18,0x7E,0xE2,0xD5,0x6,0x59,0x81,0x3C,0x4F,0xF4,0xAB,0x60,0x9D,0xCA,0xB3,0x27 }; /* * Указатель, используемый для загрузки адреса массива подстановок. */ const byte *pi_ptr = pi; // Набор указателей и массивов ключей, используемых в реализации шифра. byte magma_round_keys[128]; // Массив для ключей раундов (шифрование). byte magma_MAC_round_keys[128]; // Массив для раундовых ключей, используемых MAC. byte magma_MAC_K1[8]; // Дополнительный ключ для CMAC (K1). byte magma_MAC_K2[8]; // Дополнительный ключ для CMAC (K2). byte KeysReady; // Флаг, обозначающий наличие раундовых ключей. // Внутренние функции. int DoCipher(byte *round_keys, byte *plain_text, byte *cipher_text, const byte *s_boxes); void ExpandKey(byte *source_key, byte *round_keys); void ExpandKeyDecrypt(byte *source_key, byte *round_keys); int MagmaEncrypt(uint32_t *nonce, byte *pt, byte *dst, uint16_t len); int MagmaDecrypt(uint32_t *nonce, byte *dst, byte *ct, uint16_t len); int MagmaMAC(uint32_t nonce, byte *text, uint16_t len, byte *MAC); public: MagmaEncryptor(); ~MagmaEncryptor(); int setKeys(byte *cipher_key, byte *MAC_key); int KDF(byte *source_key, byte *source_MAC_key, byte *base, int epoch); int lock(uint32_t *nonce, byte *plain_text, byte *cipher_text, uint16_t len, byte *MAC); int unlock(uint32_t *nonce, byte *plain_text, byte *cipher_text, uint16_t len, byte *MAC); /* * Для использования следует загрузить действующие ключи при помощи setKeys(), зашифрование * производится вызовом lock(), расшифрование, с проверкой MAC, - unlock(). * * KDF(), при необходимости, может быть использована для получения следующего набора * ключей из текущего. * */ }; #endif