├── README.md ├── kuznechik.pro ├── main.c ├── test.h ├── gost_3412_2015_calc.h ├── gost_3412_2015_const.h └── gost_3412_2015_calc.c /README.md: -------------------------------------------------------------------------------- 1 | # kuznechik 2 | Реализация алгоритма шифрования "Кузнечик" по ГОСТ 34.12 - 2015. Статья в журнале "Хакер": https://xakep.ru/2017/02/02/working-with-grasshopper/. 3 | -------------------------------------------------------------------------------- /kuznechik.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += console 3 | CONFIG -= app_bundle 4 | CONFIG -= qt 5 | 6 | SOURCES += \ 7 | gost_3412_2015_calc.c \ 8 | main.c 9 | 10 | HEADERS += \ 11 | gost_3412_2015_calc.h \ 12 | gost_3412_2015_const.h \ 13 | test.h 14 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "gost_3412_2015_calc.h" 2 | #include "test.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | vect gipher_blk; 7 | GOST_Kuz_Expand_Key(test_key); 8 | 9 | GOST_Kuz_Encrypt(encrypt_test_string, gipher_blk); 10 | 11 | GOST_Kuz_Decrypt(decrypt_test_string, gipher_blk); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_H 2 | #define TEST_H 3 | 4 | static const unsigned char test_key[32] = { 5 | 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 6 | 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, 7 | 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 8 | 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88 9 | }; 10 | 11 | static const unsigned char encrypt_test_string[16] = { 12 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 13 | 0x00, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 14 | 15 | }; 16 | 17 | static const unsigned char decrypt_test_string[16] = { 18 | 0xcd, 0xed, 0xd4, 0xb9, 0x42, 0x8d, 0x46, 0x5a, 19 | 0x30, 0x24, 0xbc, 0xbe, 0x90, 0x9d, 0x67, 0x7f 20 | }; 21 | 22 | #endif // TEST_H 23 | -------------------------------------------------------------------------------- /gost_3412_2015_calc.h: -------------------------------------------------------------------------------- 1 | #ifndef GOST_3412_2015_CALC_H 2 | #define GOST_3412_2015_CALC_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "gost_3412_2015_const.h" 10 | #include "test.h" 11 | 12 | #define BLOCK_SIZE 16 13 | #define KEY_SIZE 32 14 | 15 | typedef uint8_t vect[BLOCK_SIZE]; //блок размером 128 бит 16 | 17 | vect iter_C[32]; //итерационные константы C 18 | 19 | vect iter_key[10]; //итерационные ключи шифрования 20 | 21 | void 22 | GOST_Kuz_Expand_Key(const uint8_t *key); 23 | 24 | void 25 | GOST_Kuz_Encrypt(const uint8_t *blk, uint8_t *out_blk); 26 | 27 | void 28 | GOST_Kuz_Decrypt(const uint8_t *blk, uint8_t *out_blk); 29 | 30 | #endif // GOST_3412_2015_CALC_H 31 | -------------------------------------------------------------------------------- /gost_3412_2015_const.h: -------------------------------------------------------------------------------- 1 | #ifndef GOST_3412_2015_CONST_H 2 | #define GOST_3412_2015_CONST_H 3 | 4 | /* 5 | * значения для нелинейного преобразования 6 | * множества двоичных векторов (преобразование S) 7 | */ 8 | static const unsigned char Pi[256] = { 9 | 0xFC, 0xEE, 0xDD, 0x11, 0xCF, 0x6E, 0x31, 0x16, 10 | 0xFB, 0xC4, 0xFA, 0xDA, 0x23, 0xC5, 0x04, 0x4D, 11 | 0xE9, 0x77, 0xF0, 0xDB, 0x93, 0x2E, 0x99, 0xBA, 12 | 0x17, 0x36, 0xF1, 0xBB, 0x14, 0xCD, 0x5F, 0xC1, 13 | 0xF9, 0x18, 0x65, 0x5A, 0xE2, 0x5C, 0xEF, 0x21, 14 | 0x81, 0x1C, 0x3C, 0x42, 0x8B, 0x01, 0x8E, 0x4F, 15 | 0x05, 0x84, 0x02, 0xAE, 0xE3, 0x6A, 0x8F, 0xA0, 16 | 0x06, 0x0B, 0xED, 0x98, 0x7F, 0xD4, 0xD3, 0x1F, 17 | 0xEB, 0x34, 0x2C, 0x51, 0xEA, 0xC8, 0x48, 0xAB, 18 | 0xF2, 0x2A, 0x68, 0xA2, 0xFD, 0x3A, 0xCE, 0xCC, 19 | 0xB5, 0x70, 0x0E, 0x56, 0x08, 0x0C, 0x76, 0x12, 20 | 0xBF, 0x72, 0x13, 0x47, 0x9C, 0xB7, 0x5D, 0x87, 21 | 0x15, 0xA1, 0x96, 0x29, 0x10, 0x7B, 0x9A, 0xC7, 22 | 0xF3, 0x91, 0x78, 0x6F, 0x9D, 0x9E, 0xB2, 0xB1, 23 | 0x32, 0x75, 0x19, 0x3D, 0xFF, 0x35, 0x8A, 0x7E, 24 | 0x6D, 0x54, 0xC6, 0x80, 0xC3, 0xBD, 0x0D, 0x57, 25 | 0xDF, 0xF5, 0x24, 0xA9, 0x3E, 0xA8, 0x43, 0xC9, 26 | 0xD7, 0x79, 0xD6, 0xF6, 0x7C, 0x22, 0xB9, 0x03, 27 | 0xE0, 0x0F, 0xEC, 0xDE, 0x7A, 0x94, 0xB0, 0xBC, 28 | 0xDC, 0xE8, 0x28, 0x50, 0x4E, 0x33, 0x0A, 0x4A, 29 | 0xA7, 0x97, 0x60, 0x73, 0x1E, 0x00, 0x62, 0x44, 30 | 0x1A, 0xB8, 0x38, 0x82, 0x64, 0x9F, 0x26, 0x41, 31 | 0xAD, 0x45, 0x46, 0x92, 0x27, 0x5E, 0x55, 0x2F, 32 | 0x8C, 0xA3, 0xA5, 0x7D, 0x69, 0xD5, 0x95, 0x3B, 33 | 0x07, 0x58, 0xB3, 0x40, 0x86, 0xAC, 0x1D, 0xF7, 34 | 0x30, 0x37, 0x6B, 0xE4, 0x88, 0xD9, 0xE7, 0x89, 35 | 0xE1, 0x1B, 0x83, 0x49, 0x4C, 0x3F, 0xF8, 0xFE, 36 | 0x8D, 0x53, 0xAA, 0x90, 0xCA, 0xD8, 0x85, 0x61, 37 | 0x20, 0x71, 0x67, 0xA4, 0x2D, 0x2B, 0x09, 0x5B, 38 | 0xCB, 0x9B, 0x25, 0xD0, 0xBE, 0xE5, 0x6C, 0x52, 39 | 0x59, 0xA6, 0x74, 0xD2, 0xE6, 0xF4, 0xB4, 0xC0, 40 | 0xD1, 0x66, 0xAF, 0xC2, 0x39, 0x4B, 0x63, 0xB6 41 | }; 42 | 43 | /* 44 | * значения для обратного нелинейного преобразования 45 | * множества двоичных векторов (обратное преобразование S) 46 | */ 47 | static const unsigned char reverse_Pi[256] = { 48 | 0xA5, 0x2D, 0x32, 0x8F, 0x0E, 0x30, 0x38, 0xC0, 49 | 0x54, 0xE6, 0x9E, 0x39, 0x55, 0x7E, 0x52, 0x91, 50 | 0x64, 0x03, 0x57, 0x5A, 0x1C, 0x60, 0x07, 0x18, 51 | 0x21, 0x72, 0xA8, 0xD1, 0x29, 0xC6, 0xA4, 0x3F, 52 | 0xE0, 0x27, 0x8D, 0x0C, 0x82, 0xEA, 0xAE, 0xB4, 53 | 0x9A, 0x63, 0x49, 0xE5, 0x42, 0xE4, 0x15, 0xB7, 54 | 0xC8, 0x06, 0x70, 0x9D, 0x41, 0x75, 0x19, 0xC9, 55 | 0xAA, 0xFC, 0x4D, 0xBF, 0x2A, 0x73, 0x84, 0xD5, 56 | 0xC3, 0xAF, 0x2B, 0x86, 0xA7, 0xB1, 0xB2, 0x5B, 57 | 0x46, 0xD3, 0x9F, 0xFD, 0xD4, 0x0F, 0x9C, 0x2F, 58 | 0x9B, 0x43, 0xEF, 0xD9, 0x79, 0xB6, 0x53, 0x7F, 59 | 0xC1, 0xF0, 0x23, 0xE7, 0x25, 0x5E, 0xB5, 0x1E, 60 | 0xA2, 0xDF, 0xA6, 0xFE, 0xAC, 0x22, 0xF9, 0xE2, 61 | 0x4A, 0xBC, 0x35, 0xCA, 0xEE, 0x78, 0x05, 0x6B, 62 | 0x51, 0xE1, 0x59, 0xA3, 0xF2, 0x71, 0x56, 0x11, 63 | 0x6A, 0x89, 0x94, 0x65, 0x8C, 0xBB, 0x77, 0x3C, 64 | 0x7B, 0x28, 0xAB, 0xD2, 0x31, 0xDE, 0xC4, 0x5F, 65 | 0xCC, 0xCF, 0x76, 0x2C, 0xB8, 0xD8, 0x2E, 0x36, 66 | 0xDB, 0x69, 0xB3, 0x14, 0x95, 0xBE, 0x62, 0xA1, 67 | 0x3B, 0x16, 0x66, 0xE9, 0x5C, 0x6C, 0x6D, 0xAD, 68 | 0x37, 0x61, 0x4B, 0xB9, 0xE3, 0xBA, 0xF1, 0xA0, 69 | 0x85, 0x83, 0xDA, 0x47, 0xC5, 0xB0, 0x33, 0xFA, 70 | 0x96, 0x6F, 0x6E, 0xC2, 0xF6, 0x50, 0xFF, 0x5D, 71 | 0xA9, 0x8E, 0x17, 0x1B, 0x97, 0x7D, 0xEC, 0x58, 72 | 0xF7, 0x1F, 0xFB, 0x7C, 0x09, 0x0D, 0x7A, 0x67, 73 | 0x45, 0x87, 0xDC, 0xE8, 0x4F, 0x1D, 0x4E, 0x04, 74 | 0xEB, 0xF8, 0xF3, 0x3E, 0x3D, 0xBD, 0x8A, 0x88, 75 | 0xDD, 0xCD, 0x0B, 0x13, 0x98, 0x02, 0x93, 0x80, 76 | 0x90, 0xD0, 0x24, 0x34, 0xCB, 0xED, 0xF4, 0xCE, 77 | 0x99, 0x10, 0x44, 0x40, 0x92, 0x3A, 0x01, 0x26, 78 | 0x12, 0x1A, 0x48, 0x68, 0xF5, 0x81, 0x8B, 0xC7, 79 | 0xD6, 0x20, 0x0A, 0x08, 0x00, 0x4C, 0xD7, 0x74 80 | }; 81 | 82 | static const unsigned char l_vec[16] = { 83 | 1, 148, 32, 133, 16, 194, 192, 1, 84 | 251, 1, 192, 194, 16, 133, 32, 148 85 | }; 86 | 87 | #endif // GOST_3412_2015_CONST_H 88 | -------------------------------------------------------------------------------- /gost_3412_2015_calc.c: -------------------------------------------------------------------------------- 1 | #include "gost_3412_2015_calc.h" 2 | 3 | #define DEBUG_MODE 4 | 5 | #ifdef DEBUG_MODE 6 | static void 7 | GOST_Kuz_PrintDebug(uint8_t *state) 8 | { 9 | int i; 10 | for (i = 0; i < BLOCK_SIZE; i++) 11 | printf("%02x", state[i]); 12 | printf("\n"); 13 | } 14 | #endif 15 | 16 | static void 17 | GOST_Kuz_S(const uint8_t *in_data, uint8_t *out_data) 18 | { 19 | int i; 20 | for (i = 0; i < BLOCK_SIZE; i++) 21 | out_data[i] = Pi[in_data[i]]; 22 | } 23 | 24 | static void 25 | GOST_Kuz_reverse_S(const uint8_t *in_data, uint8_t *out_data) 26 | { 27 | int i; 28 | for (i = 0; i < BLOCK_SIZE; i++) 29 | out_data[i] = reverse_Pi[in_data[i]]; 30 | } 31 | 32 | static void 33 | GOST_Kuz_X(const uint8_t *a, const uint8_t *b, uint8_t *c) 34 | { 35 | int i; 36 | for (i = 0; i < BLOCK_SIZE; i++) 37 | c[i] = a[i] ^ b[i]; 38 | } 39 | 40 | static uint8_t 41 | GOST_Kuz_GF_mul(uint8_t a, uint8_t b) 42 | { 43 | uint8_t c = 0; 44 | uint8_t hi_bit; 45 | int i; 46 | for (i = 0; i < 8; i++) 47 | { 48 | if (b & 1) 49 | c ^= a; 50 | hi_bit = a & 0x80; 51 | a <<= 1; 52 | if (hi_bit) 53 | a ^= 0xc3; //полином x^8+x^7+x^6+x+1 54 | b >>= 1; 55 | } 56 | return c; 57 | } 58 | 59 | static void 60 | GOST_Kuz_R(uint8_t *state) 61 | { 62 | int i; 63 | uint8_t a_15 = 0; 64 | vect internal; 65 | for (i = 15; i >= 0; i--) 66 | { 67 | if (i - 1 >= 0) 68 | internal[i - 1] = state[i]; 69 | a_15 ^= GOST_Kuz_GF_mul(state[i], l_vec[i]); 70 | } 71 | internal[15] = a_15; 72 | memcpy(state, internal, BLOCK_SIZE); 73 | } 74 | 75 | static void 76 | GOST_Kuz_reverse_R(uint8_t *state) 77 | { 78 | int i; 79 | uint8_t a_0; 80 | a_0 = state[15]; 81 | vect internal; 82 | for (i = 1; i < 16; i++) 83 | { 84 | internal[i] = state[i - 1]; 85 | a_0 ^= GOST_Kuz_GF_mul(internal[i], l_vec[i]); 86 | } 87 | internal[0] = a_0; 88 | memcpy(state, internal, BLOCK_SIZE); 89 | } 90 | 91 | static void 92 | GOST_Kuz_L(const uint8_t *in_data, uint8_t *out_data) 93 | { 94 | int i; 95 | vect internal; 96 | memcpy(internal, in_data, BLOCK_SIZE); 97 | for (i = 0; i < 16; i++) 98 | GOST_Kuz_R(internal); 99 | memcpy(out_data, internal, BLOCK_SIZE); 100 | } 101 | 102 | static void 103 | GOST_Kuz_reverse_L(const uint8_t *in_data, uint8_t *out_data) 104 | { 105 | int i; 106 | vect internal; 107 | memcpy(internal, in_data, BLOCK_SIZE); 108 | for (i = 0; i < 16; i++) 109 | GOST_Kuz_reverse_R(internal); 110 | memcpy(out_data, internal, BLOCK_SIZE); 111 | } 112 | 113 | static void 114 | GOST_Kuz_Get_C() 115 | { 116 | int i; 117 | vect iter_num[32]; 118 | for (i = 0; i < 32; i++) 119 | { 120 | memset(iter_num[i], 0, BLOCK_SIZE); 121 | iter_num[i][0] = i+1; 122 | } 123 | for (i = 0; i < 32; i++) 124 | GOST_Kuz_L(iter_num[i], iter_C[i]); 125 | } 126 | 127 | static void 128 | GOST_Kuz_F(const uint8_t *in_key_1, const uint8_t *in_key_2, 129 | uint8_t *out_key_1, uint8_t *out_key_2, 130 | uint8_t *iter_const) 131 | { 132 | vect internal; 133 | memcpy(out_key_2, in_key_1, BLOCK_SIZE); 134 | GOST_Kuz_X(in_key_1, iter_const, internal); 135 | GOST_Kuz_S(internal, internal); 136 | GOST_Kuz_L(internal, internal); 137 | GOST_Kuz_X(internal, in_key_2, out_key_1); 138 | } 139 | 140 | void 141 | GOST_Kuz_Expand_Key(const uint8_t *key) 142 | { 143 | int i; 144 | uint8_t key_1[KEY_SIZE/2]; 145 | uint8_t key_2[KEY_SIZE/2]; 146 | uint8_t iter_1[KEY_SIZE/2]; 147 | uint8_t iter_2[KEY_SIZE/2]; 148 | uint8_t iter_3[KEY_SIZE/2]; 149 | uint8_t iter_4[KEY_SIZE/2]; 150 | memcpy(key_1, key + KEY_SIZE/2, KEY_SIZE/2); 151 | memcpy(key_2, key, KEY_SIZE/2); 152 | GOST_Kuz_Get_C(); 153 | memcpy(iter_key[0], key_1, KEY_SIZE/2); 154 | memcpy(iter_key[1], key_2, KEY_SIZE/2); 155 | memcpy(iter_1, key_1, KEY_SIZE/2); 156 | memcpy(iter_2, key_2, KEY_SIZE/2); 157 | for (i = 0; i < 4; i++) 158 | { 159 | GOST_Kuz_F(iter_1, iter_2, iter_3, iter_4, iter_C[0 + 8 * i]); 160 | GOST_Kuz_F(iter_3, iter_4, iter_1, iter_2, iter_C[1 + 8 * i]); 161 | GOST_Kuz_F(iter_1, iter_2, iter_3, iter_4, iter_C[2 + 8 * i]); 162 | GOST_Kuz_F(iter_3, iter_4, iter_1, iter_2, iter_C[3 + 8 * i]); 163 | GOST_Kuz_F(iter_1, iter_2, iter_3, iter_4, iter_C[4 + 8 * i]); 164 | GOST_Kuz_F(iter_3, iter_4, iter_1, iter_2, iter_C[5 + 8 * i]); 165 | GOST_Kuz_F(iter_1, iter_2, iter_3, iter_4, iter_C[6 + 8 * i]); 166 | GOST_Kuz_F(iter_3, iter_4, iter_1, iter_2, iter_C[7 + 8 * i]); 167 | memcpy(iter_key[2 * i + 2], iter_1, KEY_SIZE/2); 168 | memcpy(iter_key[2 * i + 3], iter_2, KEY_SIZE/2); 169 | } 170 | 171 | #ifdef DEBUG_MODE 172 | printf("Iteration cipher keys:\n"); 173 | for (i = 0; i < 10; i++) 174 | GOST_Kuz_PrintDebug(iter_key[i]); 175 | #endif 176 | } 177 | 178 | void 179 | GOST_Kuz_Encrypt(const uint8_t *blk, uint8_t *out_blk) 180 | { 181 | int i; 182 | memcpy(out_blk, blk, BLOCK_SIZE); 183 | 184 | #ifdef DEBUG_MODE 185 | printf("Text:\n"); 186 | GOST_Kuz_PrintDebug(out_blk); 187 | #endif 188 | 189 | for(i = 0; i < 9; i++) 190 | { 191 | GOST_Kuz_X(iter_key[i], out_blk, out_blk); 192 | 193 | GOST_Kuz_S(out_blk, out_blk); 194 | 195 | GOST_Kuz_L(out_blk, out_blk); 196 | } 197 | GOST_Kuz_X(out_blk, iter_key[9], out_blk); 198 | 199 | #ifdef DEBUG_MODE 200 | printf("Encrypted text:\n"); 201 | GOST_Kuz_PrintDebug(out_blk); 202 | #endif 203 | } 204 | 205 | void 206 | GOST_Kuz_Decrypt(const uint8_t *blk, uint8_t *out_blk) 207 | { 208 | int i; 209 | memcpy(out_blk, blk, BLOCK_SIZE); 210 | 211 | #ifdef DEBUG_MODE 212 | printf("Gipher text:\n"); 213 | GOST_Kuz_PrintDebug(out_blk); 214 | #endif 215 | 216 | GOST_Kuz_X(out_blk, iter_key[9], out_blk); 217 | for(i = 8; i >= 0; i--) 218 | { 219 | GOST_Kuz_reverse_L(out_blk, out_blk); 220 | 221 | GOST_Kuz_reverse_S(out_blk, out_blk); 222 | 223 | GOST_Kuz_X(iter_key[i], out_blk, out_blk); 224 | } 225 | 226 | #ifdef DEBUG_MODE 227 | printf("Decrypted text:\n"); 228 | GOST_Kuz_PrintDebug(out_blk); 229 | #endif 230 | } 231 | --------------------------------------------------------------------------------