From 168223cd873dddbebdaf1b8e2379b96005090fcb Mon Sep 17 00:00:00 2001 From: Nikita Romanov <nsromanov_1@edu.hse.ru> Date: Sat, 14 Dec 2024 19:50:07 +0300 Subject: [PATCH] ADD: belt block cipher and tests from STB --- CMakeLists.txt | 1 + examples/tests/test-belt-dec.c | 78 +++++++++++++ examples/tests/test-belt-enc.c | 80 +++++++++++++ source/ak_belt.c | 207 +++++++++++++++++++++++++++++++++ source/ak_oid.c | 11 ++ source/libakrypt.h | 2 + 6 files changed, 379 insertions(+) create mode 100644 examples/tests/test-belt-dec.c create mode 100644 examples/tests/test-belt-enc.c create mode 100644 source/ak_belt.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aee7e98..58c74902 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ set( AKRYPT_SOURCES source/ak_blom.c source/ak_kdf.c source/ak_encrypt.c + source/ak_belt.c ) # -------------------------------------------------------------------------------------------------- # diff --git a/examples/tests/test-belt-dec.c b/examples/tests/test-belt-dec.c new file mode 100644 index 00000000..05ea04bd --- /dev/null +++ b/examples/tests/test-belt-dec.c @@ -0,0 +1,78 @@ +/* --------------------------------------------------------------------------------- */ +/* Контрольный пример расшифрования РѕРґРЅРѕРіРѕ блока РёР· стандарта (STB 34.101.31-2020) */ +/* --------------------------------------------------------------------------------- */ +#include <stdio.h> +#include <libakrypt.h> + + int main( void ) +{ + /* РєРѕРґ ошибки, возвращаемый функциями библиотеки */ + int error = ak_error_ok; + /* статус выполнения программы */ + int exitstatus = EXIT_FAILURE; + + /* РІС…РѕРґРЅРѕР№ блок (уже зашифрован)*/ + ak_uint8 indec[16] = + { + 0xE1,0x2B,0xDC,0x1A, + 0xE2,0x82,0x57,0xEC, + 0x70,0x3F,0xCC,0xF0, + 0x95,0xEE,0x8D,0xF1 + }; + + /* расшифрованный блок */ + ak_uint8 out[16] = {0}; + + /* константное значение ключа */ + ak_uint8 keydec[32] = + { + 0x92,0xBD,0x9B,0x1C, + 0xE5,0xD1,0x41,0x01, + 0x54,0x45,0xFB,0xC9, + 0x5E,0x4D,0x0E,0xF2, + 0x68,0x20,0x80,0xAA, + 0x22,0x7D,0x64,0x2F, + 0x26,0x87,0xF9,0x34, + 0x90,0x40,0x55,0x11 + }; + + /* инициализируем библиотеку */ + if( ak_libakrypt_create( NULL ) != ak_true ) { + ak_libakrypt_destroy(); + return EXIT_FAILURE; + } + + /* контекст алгоритма блочного шифрования */ + struct bckey ctx; + + /* выполняем последовательный вызов РґРІСѓС… функций: + создаем ключ алгоритма Belt Рё присваиваем ему константное значение */ + ak_bckey_create_belt( &ctx ); + ak_bckey_set_key( &ctx, keydec, 32 ); + + size_t i; + + // расшифровываем РІ режиме простой замены РѕРґРёРЅ блок + if(( ak_bckey_decrypt_ecb( &ctx, indec, out, 16 )) + != ak_error_ok ) goto exlab; + + printf("Decryption:\n"); + printf("m: "); + for (i = 0; i < 16; ++i) { printf("%02X ", indec[i]); } + printf("\nk: "); + for (i = 0; i < 32; ++i) { printf("%02X ", keydec[i]); } + printf("\nc: "); + for (i = 0; i < 16; ++i) { printf("%02X ", out[i]); } + printf("\n"); + + printf("Expected:\n"); + printf("c: 0D C5 30 06 00 CA B8 40 B3 84 48 E5 E9 93 F4 21\n"); + + /* после использования необходимо удалить контекст секретного ключа */ + exlab: ak_bckey_destroy( &ctx ); + + /* завершаем работу */ + if( error == ak_error_ok ) exitstatus = EXIT_SUCCESS; + ak_libakrypt_destroy(); + return exitstatus; +} diff --git a/examples/tests/test-belt-enc.c b/examples/tests/test-belt-enc.c new file mode 100644 index 00000000..6e5eddf0 --- /dev/null +++ b/examples/tests/test-belt-enc.c @@ -0,0 +1,80 @@ +/* --------------------------------------------------------------------------------- */ +/* Контрольный пример зашифрования РѕРґРЅРѕРіРѕ блока РёР· стандарта (STB 34.101.31-2020) */ +/* --------------------------------------------------------------------------------- */ +#include <stdio.h> +#include <libakrypt.h> + + int main( void ) +{ + /* РєРѕРґ ошибки, возвращаемый функциями библиотеки */ + int error = ak_error_ok; + /* статус выполнения программы */ + int exitstatus = EXIT_FAILURE; + + /* РІС…РѕРґРЅРѕР№ блок */ + ak_uint8 inenc[16] = + { + 0xB1,0x94,0xBA,0xC8, + 0x0A,0x08,0xF5,0x3B, + 0x36,0x6D,0x00,0x8E, + 0x58,0x4A,0x5D,0xE4, + }; + + /* выходной блок после зашифрования */ + ak_uint8 outenc[16] = {0}; + + /* расшифрованный блок */ + ak_uint8 outdec[16] = {0}; + + /* константное значение ключа */ + ak_uint8 key[32] = { + 0xE9,0xDE,0xE7,0x2C, + 0x8F,0x0C,0x0F,0xA6, + 0x2D,0xDB,0x49,0xF4, + 0x6F,0x73,0x96,0x47, + 0x06,0x07,0x53,0x16, + 0xED,0x24,0x7A,0x37, + 0x39,0xCB,0xA3,0x83, + 0x03,0xA9,0x8B,0xF6, + }; + + /* инициализируем библиотеку */ + if( ak_libakrypt_create( NULL ) != ak_true ) { + ak_libakrypt_destroy(); + return EXIT_FAILURE; + } + + /* контекст алгоритма блочного шифрования */ + struct bckey ctx; + + /* выполняем последовательный вызов РґРІСѓС… функций: + создаем ключ алгоритма Belt Рё присваиваем ему константное значение */ + ak_bckey_create_belt( &ctx ); + ak_bckey_set_key( &ctx, key, 32 ); + + size_t i; + + // зашифровываем РІ режиме простой замены РѕРґРёРЅ блок + if(( ak_bckey_encrypt_ecb( &ctx, inenc, outenc, 16 )) + != ak_error_ok ) goto exlab; + + printf("Encryption:\n"); + printf("m: "); + for (i = 0; i < 16; ++i) { printf("%02X ", inenc[i]); } + printf("\nk: "); + for (i = 0; i < 32; ++i) { printf("%02X ", key[i]); } + printf("\nc: "); + for (i = 0; i < 16; ++i) { printf("%02X ", outenc[i]); } + printf("\n"); + + printf("Expected:\n"); + printf("c: 69 CC A1 C9 35 57 C9 E3 D6 6B C3 E0 FA 88 FA 6E\n"); + + /* после использования необходимо удалить контекст секретного ключа */ + exlab: ak_bckey_destroy( &ctx ); + + /* завершаем работу */ + if( error == ak_error_ok ) exitstatus = EXIT_SUCCESS; + ak_libakrypt_destroy(); + return exitstatus; +} diff --git a/source/ak_belt.c b/source/ak_belt.c new file mode 100644 index 00000000..f58c942a --- /dev/null +++ b/source/ak_belt.c @@ -0,0 +1,207 @@ +/* ----------------------------------------------------------------------------------------------- */ +/* */ +/* Реализация зашифрования Рё расшифрования РѕРґРЅРѕРіРѕ блока шифром */ +/* РёР· Белорусского стандарта STB 34.101.31-2020 */ +/* */ +/* ----------------------------------------------------------------------------------------------- */ +#include <libakrypt-internal.h> + +#define ROTL32(x, r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define HU1(x,H) ((ak_uint32) ((H)[ (((x) >> 24) & 0xff) ]) << 24 ) +#define HU2(x,H) ((ak_uint32) ((H)[ (((x) >> 16) & 0xff) ]) << 16 ) +#define HU3(x,H) ((ak_uint32) ((H)[ (((x) >> 8) & 0xff) ]) << 8 ) +#define HU4(x,H) ((ak_uint32) ((H)[ (((x) >> 0) & 0xff) ]) << 0 ) +#define G(x,H,r) ROTL32(HU4((x),(H)) | HU3((x),(H)) | HU2((x),(H)) | HU1((x),(H)),(r)) +#define SWAP(x,y,tmp) (tmp) = (x); (x) = (y); (y) = (tmp); + + static ak_uint32 load32(const void *in) +{ + const ak_uint8 *p = (const ak_uint8 *)in; + return ((ak_uint32)p[0] << 0) | + ((ak_uint32)p[1] << 8) | + ((ak_uint32)p[2] << 16) | + ((ak_uint32)p[3] << 24); +} + + static void store32(void *out, const ak_uint32 v) +{ + ak_uint8 *p = (ak_uint8 *)out; + p[0] = (ak_uint8)(v >> 0); + p[1] = (ak_uint8)(v >> 8); + p[2] = (ak_uint8)(v >> 16); + p[3] = (ak_uint8)(v >> 24); +} + + static const ak_uint8 H[256] = +{ + 0xB1, 0x94, 0xBA, 0xC8, 0x0A, 0x08, 0xF5, 0x3B, 0x36, 0x6D, 0x00, 0x8E, 0x58, 0x4A, 0x5D, 0xE4, + 0x85, 0x04, 0xFA, 0x9D, 0x1B, 0xB6, 0xC7, 0xAC, 0x25, 0x2E, 0x72, 0xC2, 0x02, 0xFD, 0xCE, 0x0D, + 0x5B, 0xE3, 0xD6, 0x12, 0x17, 0xB9, 0x61, 0x81, 0xFE, 0x67, 0x86, 0xAD, 0x71, 0x6B, 0x89, 0x0B, + 0x5C, 0xB0, 0xC0, 0xFF, 0x33, 0xC3, 0x56, 0xB8, 0x35, 0xC4, 0x05, 0xAE, 0xD8, 0xE0, 0x7F, 0x99, + 0xE1, 0x2B, 0xDC, 0x1A, 0xE2, 0x82, 0x57, 0xEC, 0x70, 0x3F, 0xCC, 0xF0, 0x95, 0xEE, 0x8D, 0xF1, + 0xC1, 0xAB, 0x76, 0x38, 0x9F, 0xE6, 0x78, 0xCA, 0xF7, 0xC6, 0xF8, 0x60, 0xD5, 0xBB, 0x9C, 0x4F, + 0xF3, 0x3C, 0x65, 0x7B, 0x63, 0x7C, 0x30, 0x6A, 0xDD, 0x4E, 0xA7, 0x79, 0x9E, 0xB2, 0x3D, 0x31, + 0x3E, 0x98, 0xB5, 0x6E, 0x27, 0xD3, 0xBC, 0xCF, 0x59, 0x1E, 0x18, 0x1F, 0x4C, 0x5A, 0xB7, 0x93, + 0xE9, 0xDE, 0xE7, 0x2C, 0x8F, 0x0C, 0x0F, 0xA6, 0x2D, 0xDB, 0x49, 0xF4, 0x6F, 0x73, 0x96, 0x47, + 0x06, 0x07, 0x53, 0x16, 0xED, 0x24, 0x7A, 0x37, 0x39, 0xCB, 0xA3, 0x83, 0x03, 0xA9, 0x8B, 0xF6, + 0x92, 0xBD, 0x9B, 0x1C, 0xE5, 0xD1, 0x41, 0x01, 0x54, 0x45, 0xFB, 0xC9, 0x5E, 0x4D, 0x0E, 0xF2, + 0x68, 0x20, 0x80, 0xAA, 0x22, 0x7D, 0x64, 0x2F, 0x26, 0x87, 0xF9, 0x34, 0x90, 0x40, 0x55, 0x11, + 0xBE, 0x32, 0x97, 0x13, 0x43, 0xFC, 0x9A, 0x48, 0xA0, 0x2A, 0x88, 0x5F, 0x19, 0x4B, 0x09, 0xA1, + 0x7E, 0xCD, 0xA4, 0xD0, 0x15, 0x44, 0xAF, 0x8C, 0xA5, 0x84, 0x50, 0xBF, 0x66, 0xD2, 0xE8, 0x8A, + 0xA2, 0xD7, 0x46, 0x52, 0x42, 0xA8, 0xDF, 0xB3, 0x69, 0x74, 0xC5, 0x51, 0xEB, 0x23, 0x29, 0x21, + 0xD4, 0xEF, 0xD9, 0xB4, 0x3A, 0x62, 0x28, 0x75, 0x91, 0x14, 0x10, 0xEA, 0x77, 0x6C, 0xDA, 0x1D +}; + + static const size_t KeyIndex[8][7] = +{ + { 0, 1, 2, 3, 4, 5, 6 }, + { 7, 0, 1, 2, 3, 4, 5 }, + { 6, 7, 0, 1, 2, 3, 4 }, + { 5, 6, 7, 0, 1, 2, 3 }, + { 4, 5, 6, 7, 0, 1, 2 }, + { 3, 4, 5, 6, 7, 0, 1 }, + { 2, 3, 4, 5, 6, 7, 0 }, + { 1, 2, 3, 4, 5, 6, 7 } +}; + +/* ----------------------------------------------------------------------------------------------- */ +/*! \brief Функция зашифрования РѕРґРЅРѕРіРѕ блока информации алгоритмом блочного шифрования + * Belt (STB 34.101.31-2020). + + @param skey Контекст секретного ключа. + @param input Блок РІС…РѕРґРЅРѕР№ информации (открытый текст). + @param output Блок выходной информации (шифртекст). */ +/* ----------------------------------------------------------------------------------------------- */ + static void ak_belt_encrypt( ak_skey skey, ak_pointer input, ak_pointer output ) +{ + // Преобразование входных Рё выходных указателей РІ массивы данных + const ak_uint8 *in = (const ak_uint8 *)input; + ak_uint8 *out = (ak_uint8 *)output; + + ak_uint32 a = load32(in + 0); + ak_uint32 b = load32(in + 4); + ak_uint32 c = load32(in + 8); + ak_uint32 d = load32(in + 12); + ak_uint32 e; + size_t i; + ak_uint32 tmp; + ak_uint32 key[8] = {0}; + ak_uint32 msk[8] = {0}; + + for (i = 0; i < 8; ++i) + { + key[i] = load32(skey->key + (4*i)); + msk[i] = load32(skey->key + skey->key_size + (4*i)); + } + + for (i = 0; i < 8; ++i) + { + b ^= G((a + (key[KeyIndex[i][0]] ^ msk[KeyIndex[i][0]])),H,5); + c ^= G((d + (key[KeyIndex[i][1]] ^ msk[KeyIndex[i][1]])),H,21); + a -= G((b + (key[KeyIndex[i][2]] ^ msk[KeyIndex[i][2]])),H,13); + e = (G((b + c + (key[KeyIndex[i][3]] ^ msk[KeyIndex[i][3]])),H,21) ^ (ak_uint32)(i + 1)); + b += e; + c -= e; + d += G((c + (key[KeyIndex[i][4]] ^ msk[KeyIndex[i][4]])),H,13); + b ^= G((a + (key[KeyIndex[i][5]] ^ msk[KeyIndex[i][5]])),H,21); + c ^= G((d + (key[KeyIndex[i][6]] ^ msk[KeyIndex[i][6]])),H,5); + SWAP(a, b, tmp); + SWAP(c, d, tmp); + SWAP(b, c, tmp); + } + store32(out + 0, b); + store32(out + 4, d); + store32(out + 8, a); + store32(out + 12, c); +} + +/* ----------------------------------------------------------------------------------------------- */ + /*! \brief Функция расшифрования РѕРґРЅРѕРіРѕ блока информации алгоритмом Belt (STB 34.101.31-2020). + + @param skey Контекст секретного ключа. + @param input Блок РІС…РѕРґРЅРѕР№ информации (шифртекст). + @param output Блок выходной информации (открытый текст). */ +/* ----------------------------------------------------------------------------------------------- */ + static void ak_belt_decrypt( ak_skey skey, ak_pointer input, ak_pointer output ) +{ + // Преобразование входных Рё выходных указателей РІ массивы данных + const ak_uint8 *in = (const ak_uint8 *)input; + ak_uint8 *out = (ak_uint8 *)output; + + ak_uint32 a = load32(in + 0); + ak_uint32 b = load32(in + 4); + ak_uint32 c = load32(in + 8); + ak_uint32 d = load32(in + 12); + ak_uint32 e; + size_t i; + ak_uint32 tmp; + ak_uint32 key[8] = {0}; + ak_uint32 msk[8] = {0}; + + for (i = 0; i < 8; ++i) + { + key[i] = load32(skey->key + (4*i)); + msk[i] = load32(skey->key + skey->key_size + (4*i)); + } + + for (i = 0; i < 8; ++i) + { + b ^= G((a + (key[KeyIndex[7 - i][6]] ^ msk[KeyIndex[7 - i][6]])), H, 5); + c ^= G((d + (key[KeyIndex[7 - i][5]] ^ msk[KeyIndex[7 - i][5]])), H, 21); + a -= G((b + (key[KeyIndex[7 - i][4]] ^ msk[KeyIndex[7 - i][4]])), H, 13); + e = (G((b + c + (key[KeyIndex[7 - i][3]] ^ msk[KeyIndex[7 - i][3]])), H, 21) ^ (ak_uint32)(7 - i + 1)); + b += e; + c -= e; + d += G((c + (key[KeyIndex[7 - i][2]] ^ msk[KeyIndex[7 - i][2]])), H, 13); + b ^= G((a + (key[KeyIndex[7 - i][1]] ^ msk[KeyIndex[7 - i][1]])), H, 21); + c ^= G((d + (key[KeyIndex[7 - i][0]] ^ msk[KeyIndex[7 - i][0]])), H, 5); + SWAP(a, b, tmp); + SWAP(c, d, tmp); + SWAP(a, d, tmp); + } + store32(out + 0, c); + store32(out + 4, a); + store32(out + 8, d); + store32(out + 12, b); +} + +/* ----------------------------------------------------------------------------------------------- */ +/*! Функция инициализирует контекст ключа алгоритма блочного шифрования Belt (STB 34.101.31-2020). + После инициализации устанавливаются обработчики (функции класса). Однако само значение + ключу РЅРµ присваивается - поле `bkey->key` остается неопределенным. + + @param bkey Контекст секретного ключа алгоритма блочного шифрования. + + @return Функция возвращает РєРѕРґ ошибки. Р’ случаее успеха возвращается \ref ak_error_ok. */ +/* ----------------------------------------------------------------------------------------------- */ + int ak_bckey_create_belt( ak_bckey bkey ) +{ + int error = ak_error_ok; + + if( bkey == NULL ) return ak_error_message( ak_error_null_pointer, __func__, + "using null pointer to block cipher key context" ); + + /* создаем ключ алгоритма шифрования Рё определяем его методы */ + if(( error = ak_bckey_create( bkey, 32, 16 )) != ak_error_ok ) + return ak_error_message( error, __func__, "wrong initalization of block cipher key context" ); + + /* устанавливаем OID алгоритма шифрования */ + if(( bkey->key.oid = ak_oid_find_by_name( "belt" )) == NULL ) { + error = ak_error_get_value(); + ak_error_message( error, __func__, "wrong search of predefined belt block cipher OID" ); + ak_bckey_destroy( bkey ); + return error; + } + + /* устанавливаем методы наложения маски Рё подсчёта контрольной СЃСѓРјРјС‹ */ + bkey->key.set_mask = ak_skey_set_mask_xor; + bkey->key.unmask = ak_skey_unmask_xor; + bkey->key.set_icode = ak_skey_set_icode_xor; + bkey->key.check_icode = ak_skey_check_icode_xor; + + /* устанавливам методы зашифрования Рё расшифрования */ + bkey->encrypt = ak_belt_encrypt; + bkey->decrypt = ak_belt_decrypt; + + return error; +} diff --git a/source/ak_oid.c b/source/ak_oid.c index 9411cd81..b3c1c148 100644 --- a/source/ak_oid.c +++ b/source/ak_oid.c @@ -82,6 +82,8 @@ static const char *asn1_magma_i[] = { "1.2.643.7.1.1.5.1", NULL }; static const char *asn1_kuznechik_n[] = { "kuznechik", "kuznyechik", "grasshopper", NULL }; static const char *asn1_kuznechik_i[] = { "1.2.643.7.1.1.5.2", NULL }; + static const char *asn1_belt_n[] = { "belt", NULL }; + static const char *asn1_belt_i[] = { "1.2.112.0.2.0.34.101.31.81", NULL }; static const char *asn1_ctr_magma_n[] = { "ctr-magma", NULL }; static const char *asn1_ctr_magma_i[] = { "1.2.643.2.52.1.5.1.1", NULL }; @@ -509,6 +511,12 @@ ( ak_function_create_object *) ak_verifykey_create_streebog512, \ ( ak_function_destroy_object *) ak_verifykey_destroy, \ NULL, NULL, NULL } + #define ak_object_bckey_belt { sizeof( struct bckey ), \ + ( ak_function_create_object *) ak_bckey_create_belt, \ + ( ak_function_destroy_object *) ak_bckey_destroy, \ + ( ak_function_set_key_object *)ak_bckey_set_key, \ + ( ak_function_set_key_random_object *)ak_bckey_set_key_random, \ + ( ak_function_set_key_from_password_object *)ak_bckey_set_key_from_password } /* ----------------------------------------------------------------------------------------------- */ /*! Константные значения OID библиотеки */ @@ -580,6 +588,9 @@ static struct oid libakrypt_oids[] = { block_cipher, algorithm, asn1_kuznechik_i, asn1_kuznechik_n, NULL, { ak_object_bckey_kuznechik, ak_object_undefined, NULL, NULL }}, + { block_cipher, algorithm, asn1_belt_i, asn1_belt_n, NULL, + { ak_object_bckey_belt, ak_object_undefined, NULL, NULL }}, + /* базовые режимы блочного шифрования */ { block_cipher, encrypt_mode, asn1_ctr_magma_i, asn1_ctr_magma_n, NULL, { ak_object_bckey_magma, ak_object_undefined, ( ak_function_run_object *) ak_bckey_ctr, diff --git a/source/libakrypt.h b/source/libakrypt.h index 9bcbf756..ec6d3a61 100644 --- a/source/libakrypt.h +++ b/source/libakrypt.h @@ -734,6 +734,8 @@ extern "C" { /*! \brief Присвоение ключу алгоритма блочного шифрования значения, выработанного РёР· пароля. */ dll_export int ak_bckey_set_key_from_password( ak_bckey , const ak_pointer , const size_t , const ak_pointer , const size_t ); + /*! \brief Рнициализация секретного ключа алгоритма блочного шифрования Belt. */ + dll_export int ak_bckey_create_belt( ak_bckey ); /* ----------------------------------------------------------------------------------------------- */ /*! \brief Функция вырабатывает пару ключей алгоритма блочного шифрования РёР· заданного -- GitLab