Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ГОСТ 28147-89 в режиме простой замены.
- */
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- /*
- Функция преобразования символа в число.
- Предполагается, что входной символ 0..9 или A..F.
- */
- static uint8_t char_to_dec(char c)
- {
- return c < 'A' ? c - '0' : c - 'A' + 10;
- }
- /*
- Функция разбора hex-строки с ключом в массив байт.
- Записывает ключ в pk.
- Возвращает либо длину ключа в байтах, либо -1 в случае некорректной входной строки.
- */
- static int parse_key(char* ps, uint8_t* pk)
- {
- int n = 0;
- char *s = ps;
- uint8_t *k = pk;
- /* строка заканчивается нулевым символом */
- while(*s != '\0')
- {
- /* наращиваем количество пройденных символов в строке */
- n++;
- if(*s >= 'a' && *s <= 'f')
- {
- /* делаем из строчной буквы прописную */
- *s = toupper(*s); /* подключается из ctype.h */
- }
- else if(*s < '0' || (*s > '9' && *s < 'A') || *s > 'F')
- {
- /* попался некорректный символ, строка не может быть разобрана */
- return -1;
- }
- if(n % 2 != 0)
- {
- /* записываем число, которое представляет собой символ, в старшие биты ключа */
- *k = char_to_dec(*s) << 4;
- }
- else
- {
- /* пишем число в младшие биты ключа и переходим к следующему байту */
- *k += char_to_dec(*s) & 0xF;
- k++;
- }
- /* переходим к следующему символу в строке */
- s++;
- }
- /* если длина входной строки не делится на два - всё плохо. */
- return n % 2 != 0 ? -1 : k - pk;
- }
- /*
- Часть алгоритма ГОСТ 28147-89, вынесенная в отдельную функцию.
- */
- static uint32_t f(uint32_t x, uint8_t k)
- {
- /* описание таблицы замен */
- static const uint8_t s_table[][16] =
- {
- { 0x4, 0xA, 0x9, 0x2, 0xD, 0x8, 0x0, 0xE, 0x6, 0xB, 0x1, 0xC, 0x7, 0xF, 0x5, 0x3 },
- { 0xE, 0xB, 0x4, 0xC, 0x6, 0xD, 0xF, 0xA, 0x2, 0x3, 0x8, 0x1, 0x0, 0x7, 0x5, 0x9 },
- { 0x5, 0x8, 0x1, 0xD, 0xA, 0x3, 0x4, 0x2, 0xE, 0xF, 0xC, 0x7, 0x6, 0x0, 0x9, 0xB },
- { 0x7, 0xD, 0xA, 0x1, 0x0, 0x8, 0x9, 0xF, 0xE, 0x4, 0x6, 0xC, 0xB, 0x2, 0x5, 0x3 },
- { 0x6, 0xC, 0x7, 0x1, 0x5, 0xF, 0xD, 0x8, 0x4, 0xA, 0x9, 0xE, 0x0, 0x3, 0xB, 0x2 },
- { 0x4, 0xB, 0xA, 0x0, 0x7, 0x2, 0x1, 0xD, 0x3, 0x6, 0x8, 0x5, 0x9, 0xC, 0xF, 0xE },
- { 0xD, 0xB, 0x4, 0x1, 0x3, 0xF, 0x5, 0x9, 0x0, 0xA, 0xE, 0x7, 0x6, 0x8, 0x2, 0xC },
- { 0x1, 0xF, 0xD, 0x0, 0x5, 0x7, 0xA, 0x4, 0x9, 0x2, 0x3, 0xE, 0x6, 0xB, 0x8, 0xC }
- };
- uint32_t mp;
- /* при сложении переполнение разрядной сетки отбрасывается, в mp остается сумма по модулю 32 */
- mp = x + k;
- /* разбиваем mp на группы по 4 бита, прогоняем их через таблицы замены, затем склеиваем */
- mp = (s_table[7][(mp >> 0 ) & 0xF] << 0 ) + (s_table[6][(mp >> 4 ) & 0xF] << 4 ) +
- (s_table[5][(mp >> 8 ) & 0xF] << 8 ) + (s_table[4][(mp >> 12) & 0xF] << 12) +
- (s_table[3][(mp >> 16) & 0xF] << 16) + (s_table[2][(mp >> 20) & 0xF] << 20) +
- (s_table[1][(mp >> 24) & 0xF] << 24) + (s_table[0][(mp >> 28) & 0xF] << 28) ;
- /* циклически сдвигаем результат влево на 11 бит */
- mp = (mp << 11) + (mp >> (sizeof(mp) * 8 - 11));
- return mp;
- }
- /*
- Основная функция обработки блока текста.
- Используется и при зашифровании, и при расшифровании.
- */
- static void process_block(uint8_t* x, const uint8_t* k, const uint8_t* ki)
- {
- const uint8_t* end = ki + 32;
- uint32_t a, b, c;
- /* разбиваем входной 64-битный блок на группы по 32 бита */
- memcpy(&a, x + sizeof(b), sizeof(a)); /* для memcpy и strcpy нужен string.h */
- memcpy(&b, x, sizeof(b));
- /* 32 раунда шифрования */
- for(; ki < end; ki++)
- {
- c = a;
- a = b ^ f(a, k[*ki]);
- b = c;
- }
- /* склеиваем 32-битные группы в обратном порядке */
- memcpy(x, &a, sizeof(a));
- memcpy(x + sizeof(a), &b, sizeof(b));
- }
- /*
- Функция шифрования блока.
- При шифровании используется прямой порядок подключей.
- */
- void encrypt_block(uint8_t* x, const uint8_t* k)
- {
- /* массив индексов подключей */
- static const uint8_t encrypt_ki[] =
- {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 0, 1, 2, 3, 4, 5, 6, 7,
- 0, 1, 2, 3, 4, 5, 6, 7,
- 7, 6, 5, 4, 3, 2, 1, 0
- };
- process_block(x, k, encrypt_ki);
- }
- /*
- Функция расшифрования блока.
- Порядок подключей инвертируется.
- */
- void decrypt_block(uint8_t* x, const uint8_t* k)
- {
- /* массив индексов подключей */
- static const uint8_t decrypt_ki[] =
- {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 7, 6, 5, 4, 3, 2, 1, 0,
- 7, 6, 5, 4, 3, 2, 1, 0,
- 7, 6, 5, 4, 3, 2, 1, 0
- };
- process_block(x, k, decrypt_ki);
- }
- /*
- Точка входа в программу.
- */
- int main(int argc, char** argv)
- {
- uint8_t key[8]; /* для типов uint8_t, uint32_t, ... нужен stdint.h */
- char data[8 + 1]; /* восемь байт на блок, один - для нулевого символа */
- int n;
- /* возврат, если не удалось прочитать ключ из аргументов, если не удалось его разобрать или он имеет неверную длину */
- if(argc < 2 || (n = parse_key(argv[1], key)) < 0 || n != 8)
- {
- return -1;
- }
- /* блок открытого текста помещается в буфер */
- strcpy(data, "opentext");
- /* шифрование и расшифрование с выводом на консоль */
- encrypt_block((uint8_t*)data, key);
- printf("enc: %s\n", data); /* для printf нужен stdio.h */
- decrypt_block((uint8_t*)data, key);
- printf("dec: %s\n", data);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment