kapger Млять, а поиск юзать ? Почти на каждой странице яндекса мелькает Брюс Шнайер со своей книгой, а вней приложение, а там на си стоко сорцов, хоть задницей жуй
Спасибо за добрые слова! Поиск юзается, но НЕ НАШЕЛ! Шнайера только начал... P.S. ссылка http://darksoftware.narod.ru/narod_is_best/libgost.ppmp - не понял что с ней делать... И IE, и FireFox предлагают сохранить файл. Сохранил. И что с ним дальше делать?
не тестировал : Код (Text): /* * The GOST 28147-89 cipher * * This is based on the 25 Movember 1993 draft translation * by Aleksandr Malchik, with Whitfield Diffie, of the Government * Standard of the U.S.S.R. GOST 28149-89, "Cryptographic Transformation * Algorithm", effective 1 July 1990. (Whitfield.Diffie@eng.sun.com) * * That is a draft, and may contain errors, which will be faithfully * reflected here, along with possible exciting new bugs. * * Some details have been cleared up by the paper "Soviet Encryption * Algorithm" by Josef Pieprzyk and Leonid Tombak of the University * of Wollongong, New South Wales. (josef/leo@cs.adfa.oz.au) * * The standard is written by A. Zabotin (project leader), G.P. Glazkov, * and V.B. Isaeva. It was accepted and introduced into use by the * action of the State Standards Committee of the USSR on 2 June 89 as * No. 1409. It was to be reviewed in 1993, but whether anyone wishes * to take on this obligation from the USSR is questionable. * * This code is placed in the public domain. */ /* * If you read the standard, it belabors the point of copying corresponding * bits from point A to point B quite a bit. It helps to understand that * the standard is uniformly little-endian, although it numbers bits from * 1 rather than 0, so bit n has value 2^(n-1). The least significant bit * of the 32-bit words that are manipulated in the algorithm is the first, * lowest-numbered, in the bit string. */ /* A 32-bit data type */ #ifdef __alpha /* Any other 64-bit machines? */ typedef unsigned int word32; #else typedef unsigned long word32; #endif /* * The standard does not specify the contents of the 8 4 bit->4 bit * substitution boxes, saying they're a parameter of the network * being set up. For illustration purposes here, I have used * the first rows of the 8 S-boxes from the DES. (Note that the * DES S-boxes are numbered starting from 1 at the msb. In keeping * with the rest of the GOST, I have used little-endian numbering. * Thus, k8 is S-box 1. * * Obviously, a careful look at the cryptographic properties of the cipher * must be undertaken before "production" substitution boxes are defined. * * The standard also does not specify a standard bit-string representation * for the contents of these blocks. */ static unsigned char const k8[16] = { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }; static unsigned char const k7[16] = { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }; static unsigned char const k6[16] = { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }; static unsigned char const k5[16] = { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }; static unsigned char const k4[16] = { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }; static unsigned char const k3[16] = { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }; static unsigned char const k2[16] = { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }; static unsigned char const k1[16] = { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }; /* Byte-at-a-time substitution boxes */ static unsigned char k87[256]; static unsigned char k65[256]; static unsigned char k43[256]; static unsigned char k21[256]; /* * Build byte-at-a-time subtitution tables. * This must be called once for global setup. */ void kboxinit(void) { int i; for (i = 0; i < 256; i++) { k87[i] = k8[i >> 4] << 4 | k7[i & 15]; k65[i] = k6[i >> 4] << 4 | k5[i & 15]; k43[i] = k4[i >> 4] << 4 | k3[i & 15]; k21[i] = k2[i >> 4] << 4 | k1[i & 15]; } } /* * Do the substitution and rotation that are the core of the operation, * like the expansion, substitution and permutation of the DES. * It would be possible to perform DES-like optimisations and store * the table entries as 32-bit words, already rotated, but the * efficiency gain is questionable. * * This should be inlined for maximum speed */ #if __GNUC__ __inline__ #endif static word32 f(word32 x) { /* Do substitutions */ #if 0 /* This is annoyingly slow */ x = k8[x>>28 & 15] << 28 | k7[x>>24 & 15] << 24 | k6[x>>20 & 15] << 20 | k5[x>>16 & 15] << 16 | k4[x>>12 & 15] << 12 | k3[x>> 8 & 15] << 8 | k2[x>> 4 & 15] << 4 | k1[x & 15]; #else /* This is faster */ x = k87[x>>24 & 255] << 24 | k65[x>>16 & 255] << 16 | k43[x>> 8 & 255] << 8 | k21[x & 255]; #endif /* Rotate left 11 bits */ return x<<11 | x>>(32-11); } /* * The GOST standard defines the input in terms of bits 1..64, with * bit 1 being the lsb of in[0] and bit 64 being the msb of in[1]. * * The keys are defined similarly, with bit 256 being the msb of key[7]. */ void gostcrypt(word32 const in[2], word32 out[2], word32 const key[8]) { register word32 n1, n2; /* As named in the GOST */ n1 = in[0]; n2 = in[1]; /* Instead of swapping halves, swap names each round */ n2 ^= f(n1+key[0]); n1 ^= f(n2+key[1]); n2 ^= f(n1+key[2]); n1 ^= f(n2+key[3]); n2 ^= f(n1+key[4]); n1 ^= f(n2+key[5]); n2 ^= f(n1+key[6]); n1 ^= f(n2+key[7]); n2 ^= f(n1+key[0]); n1 ^= f(n2+key[1]); n2 ^= f(n1+key[2]); n1 ^= f(n2+key[3]); n2 ^= f(n1+key[4]); n1 ^= f(n2+key[5]); n2 ^= f(n1+key[6]); n1 ^= f(n2+key[7]); n2 ^= f(n1+key[0]); n1 ^= f(n2+key[1]); n2 ^= f(n1+key[2]); n1 ^= f(n2+key[3]); n2 ^= f(n1+key[4]); n1 ^= f(n2+key[5]); n2 ^= f(n1+key[6]); n1 ^= f(n2+key[7]); n2 ^= f(n1+key[7]); n1 ^= f(n2+key[6]); n2 ^= f(n1+key[5]); n1 ^= f(n2+key[4]); n2 ^= f(n1+key[3]); n1 ^= f(n2+key[2]); n2 ^= f(n1+key[1]); n1 ^= f(n2+key[0]); /* There is no swap after the last round */ out[0] = n2; out[1] = n1; } /* * The key schedule is somewhat different for decryption. * (The key table is used once forward and three times backward.) * You could define an expanded key, or just write the code twice, * as done here. */ void gostdecrypt(word32 const in[2], word32 out[2], word32 const key[8]) { register word32 n1, n2; /* As named in the GOST */ n1 = in[0]; n2 = in[1]; n2 ^= f(n1+key[0]); n1 ^= f(n2+key[1]); n2 ^= f(n1+key[2]); n1 ^= f(n2+key[3]); n2 ^= f(n1+key[4]); n1 ^= f(n2+key[5]); n2 ^= f(n1+key[6]); n1 ^= f(n2+key[7]); n2 ^= f(n1+key[7]); n1 ^= f(n2+key[6]); n2 ^= f(n1+key[5]); n1 ^= f(n2+key[4]); n2 ^= f(n1+key[3]); n1 ^= f(n2+key[2]); n2 ^= f(n1+key[1]); n1 ^= f(n2+key[0]); n2 ^= f(n1+key[7]); n1 ^= f(n2+key[6]); n2 ^= f(n1+key[5]); n1 ^= f(n2+key[4]); n2 ^= f(n1+key[3]); n1 ^= f(n2+key[2]); n2 ^= f(n1+key[1]); n1 ^= f(n2+key[0]); n2 ^= f(n1+key[7]); n1 ^= f(n2+key[6]); n2 ^= f(n1+key[5]); n1 ^= f(n2+key[4]); n2 ^= f(n1+key[3]); n1 ^= f(n2+key[2]); n2 ^= f(n1+key[1]); n1 ^= f(n2+key[0]); out[0] = n2; out[1] = n1; } /* * The GOST "Output feedback" standard. It seems closer morally * to the counter feedback mode some people have proposed for DES. * The avoidance of the short cycles that are possible in OFB seems * like a Good Thing. * * Calling it the stream mode makes more sense. * * The IV is encrypted with the key to produce the initial counter value. * Then, for each output block, a constant is added, modulo 2^32-1 * (0 is represented as all-ones, not all-zeros), to each half of * the counter, and the counter is encrypted to produce the value * to XOR with the output. * * Len is the number of blocks. Sub-block encryption is * left as an exercise for the user. Remember that the * standard defines everything in a little-endian manner, * so you want to use the low bit of gamma[0] first. * * OFB is, of course, self-inverse, so there is only one function. */ /* The constants for addition */ #define C1 0x01010104 #define C2 0x01010101 void gostofb(word32 const *in, word32 *out, int len, word32 const iv[2], word32 const key[8]) { word32 temp[2]; /* Counter */ word32 gamma[2]; /* Output XOR value */ /* Compute starting value for counter */ gostcrypt(iv, temp, key); while (len--) { temp[0] += C2; if (temp[0] < C2) /* Wrap modulo 2^32? */ temp[0]++; /* Make it modulo 2^32-1 */ temp[1] += C1; if (temp[1] < C1) /* Wrap modulo 2^32? */ temp[1]++; /* Make it modulo 2^32-1 */ gostcrypt(temp, gamma, key); *out++ = *in++ ^ gamma[0]; *out++ = *in++ ^ gamma[1]; } } /* * The CFB mode is just what you'd expect. Each block of ciphertext y[] is * derived from the input x[] by the following pseudocode: * y[i] = x[i] ^ gostcrypt(y[i-1]) * x[i] = y[i] ^ gostcrypt(y[i-1]) * Where y[-1] is the IV. * * The IV is modified in place. Again, len is in *blocks*. */ void gostcfbencrypt(word32 const *in, word32 *out, int len, word32 iv[2], word32 const key[8]) { while (len--) { gostcrypt(iv, iv, key); iv[0] = *out++ ^= iv[0]; iv[1] = *out++ ^= iv[1]; } } void gostcfbdecrypt(word32 const *in, word32 *out, int len, word32 iv[2], word32 const key[8]) { word32 t; while (len--) { gostcrypt(iv, iv, key); t = *out; *out++ ^= iv[0]; iv[0] = t; t = *out; *out++ ^= iv[1]; iv[1] = t; } } /* * The message suthetication code uses only 16 of the 32 rounds. * There *is* a swap after the 16th round. * The last block should be padded to 64 bits with zeros. * len is the number of *blocks* in the input. */ void gostmac(word32 const *in, int len, word32 out[2], word32 const key[8]) { register word32 n1, n2; /* As named in the GOST */ n1 = 0; n2 = 0; while (len--) { n1 ^= *in++; n2 = *in++; /* Instead of swapping halves, swap names each round */ n2 ^= f(n1+key[0]); n1 ^= f(n2+key[1]); n2 ^= f(n1+key[2]); n1 ^= f(n2+key[3]); n2 ^= f(n1+key[4]); n1 ^= f(n2+key[5]); n2 ^= f(n1+key[6]); n1 ^= f(n2+key[7]); n2 ^= f(n1+key[0]); n1 ^= f(n2+key[1]); n2 ^= f(n1+key[2]); n1 ^= f(n2+key[3]); n2 ^= f(n1+key[4]); n1 ^= f(n2+key[5]); n2 ^= f(n1+key[6]); n1 ^= f(n2+key[7]); } out[0] = n1; out[1] = n2; } #ifdef TEST #include <stdio.h> #include <stdlib.h> /* Designed to cope with 15-bit rand() implementations */ #define RAND32 ((word32)rand() << 17 ^ (word32)rand() << 9 ^ rand()) int main(void) { word32 key[8]; word32 plain[2]; word32 cipher[2]; int i, j; kboxinit(); printf("GOST 21847-89 test driver.\n"); for (i = 0; i < 1000; i++) { for (j = 0; j < 8; j++) key[j] = RAND32; plain[0] = RAND32; plain[1] = RAND32; printf("%3d\r", i); fflush(stdout); gostcrypt(plain, cipher, key); for (j = 0; j < 99; j++) gostcrypt(cipher, cipher, key); for (j = 0; j < 100; j++) gostdecrypt(cipher, cipher, key); if (plain[0] != cipher[0] || plain[1] != cipher[1]) { fprintf(stderr, "\nError! i = %d\n", i); return 1; } } printf("All tests passed.\n"); return 0; } #endif /* TEST */
2OLS: В этой реализации, к-рая гуляет по сети еще со времен книги Шнайера, SBOX взяты с потолка, при преобразовании в byte-to-byte u8 SBOX[4][256] мы видим множество левых перестановок x (sbox[x]) = 0. На радостях криптоаналитики и объявили, что ГОСТ - слабый, поскольку реальных перестановок не было. Если заметить SBOX, к примеру, на тот, к-рый используется в примерах к стандарту и в ЦБ u8 sbox[8][16] = { {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3}, {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9}, {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11}, {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3}, {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2}, {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14}, {13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12}, {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12} }; четыре 256 байтных SBOX дадут уже нормальные перестановки. в принципе, можно исключить runtime генерацию этих массивов и заменить константами... Код (Text): /* Byte-at-a-time substitution boxes */ const static u8 k87[256] = { 0x4E, 0x4B, 0x44, 0x4C, 0x46, 0x4D, 0x4F, 0x4A, 0x42, 0x43, 0x48, 0x41, 0x40, 0x47, 0x45, 0x49, 0xAE, 0xAB, 0xA4, 0xAC, 0xA6, 0xAD, 0xAF, 0xAA, 0xA2, 0xA3, 0xA8, 0xA1, 0xA0, 0xA7, 0xA5, 0xA9, 0x9E, 0x9B, 0x94, 0x9C, 0x96, 0x9D, 0x9F, 0x9A, 0x92, 0x93, 0x98, 0x91, 0x90, 0x97, 0x95, 0x99, 0x2E, 0x2B, 0x24, 0x2C, 0x26, 0x2D, 0x2F, 0x2A, 0x22, 0x23, 0x28, 0x21, 0x20, 0x27, 0x25, 0x29, 0xDE, 0xDB, 0xD4, 0xDC, 0xD6, 0xDD, 0xDF, 0xDA, 0xD2, 0xD3, 0xD8, 0xD1, 0xD0, 0xD7, 0xD5, 0xD9, 0x8E, 0x8B, 0x84, 0x8C, 0x86, 0x8D, 0x8F, 0x8A, 0x82, 0x83, 0x88, 0x81, 0x80, 0x87, 0x85, 0x89, 0x0E, 0x0B, 0x04, 0x0C, 0x06, 0x0D, 0x0F, 0x0A, 0x02, 0x03, 0x08, 0x01, 0x00, 0x07, 0x05, 0x09, 0xEE, 0xEB, 0xE4, 0xEC, 0xE6, 0xED, 0xEF, 0xEA, 0xE2, 0xE3, 0xE8, 0xE1, 0xE0, 0xE7, 0xE5, 0xE9, 0x6E, 0x6B, 0x64, 0x6C, 0x66, 0x6D, 0x6F, 0x6A, 0x62, 0x63, 0x68, 0x61, 0x60, 0x67, 0x65, 0x69, 0xBE, 0xBB, 0xB4, 0xBC, 0xB6, 0xBD, 0xBF, 0xBA, 0xB2, 0xB3, 0xB8, 0xB1, 0xB0, 0xB7, 0xB5, 0xB9, 0x1E, 0x1B, 0x14, 0x1C, 0x16, 0x1D, 0x1F, 0x1A, 0x12, 0x13, 0x18, 0x11, 0x10, 0x17, 0x15, 0x19, 0xCE, 0xCB, 0xC4, 0xCC, 0xC6, 0xCD, 0xCF, 0xCA, 0xC2, 0xC3, 0xC8, 0xC1, 0xC0, 0xC7, 0xC5, 0xC9, 0x7E, 0x7B, 0x74, 0x7C, 0x76, 0x7D, 0x7F, 0x7A, 0x72, 0x73, 0x78, 0x71, 0x70, 0x77, 0x75, 0x79, 0xFE, 0xFB, 0xF4, 0xFC, 0xF6, 0xFD, 0xFF, 0xFA, 0xF2, 0xF3, 0xF8, 0xF1, 0xF0, 0xF7, 0xF5, 0xF9, 0x5E, 0x5B, 0x54, 0x5C, 0x56, 0x5D, 0x5F, 0x5A, 0x52, 0x53, 0x58, 0x51, 0x50, 0x57, 0x55, 0x59, 0x3E, 0x3B, 0x34, 0x3C, 0x36, 0x3D, 0x3F, 0x3A, 0x32, 0x33, 0x38, 0x31, 0x30, 0x37, 0x35, 0x39 }; const static u8 k65[256] = { 0x57, 0x5D, 0x5A, 0x51, 0x50, 0x58, 0x59, 0x5F, 0x5E, 0x54, 0x56, 0x5C, 0x5B, 0x52, 0x55, 0x53, 0x87, 0x8D, 0x8A, 0x81, 0x80, 0x88, 0x89, 0x8F, 0x8E, 0x84, 0x86, 0x8C, 0x8B, 0x82, 0x85, 0x83, 0x17, 0x1D, 0x1A, 0x11, 0x10, 0x18, 0x19, 0x1F, 0x1E, 0x14, 0x16, 0x1C, 0x1B, 0x12, 0x15, 0x13, 0xD7, 0xDD, 0xDA, 0xD1, 0xD0, 0xD8, 0xD9, 0xDF, 0xDE, 0xD4, 0xD6, 0xDC, 0xDB, 0xD2, 0xD5, 0xD3, 0xA7, 0xAD, 0xAA, 0xA1, 0xA0, 0xA8, 0xA9, 0xAF, 0xAE, 0xA4, 0xA6, 0xAC, 0xAB, 0xA2, 0xA5, 0xA3, 0x37, 0x3D, 0x3A, 0x31, 0x30, 0x38, 0x39, 0x3F, 0x3E, 0x34, 0x36, 0x3C, 0x3B, 0x32, 0x35, 0x33, 0x47, 0x4D, 0x4A, 0x41, 0x40, 0x48, 0x49, 0x4F, 0x4E, 0x44, 0x46, 0x4C, 0x4B, 0x42, 0x45, 0x43, 0x27, 0x2D, 0x2A, 0x21, 0x20, 0x28, 0x29, 0x2F, 0x2E, 0x24, 0x26, 0x2C, 0x2B, 0x22, 0x25, 0x23, 0xE7, 0xED, 0xEA, 0xE1, 0xE0, 0xE8, 0xE9, 0xEF, 0xEE, 0xE4, 0xE6, 0xEC, 0xEB, 0xE2, 0xE5, 0xE3, 0xF7, 0xFD, 0xFA, 0xF1, 0xF0, 0xF8, 0xF9, 0xFF, 0xFE, 0xF4, 0xF6, 0xFC, 0xFB, 0xF2, 0xF5, 0xF3, 0xC7, 0xCD, 0xCA, 0xC1, 0xC0, 0xC8, 0xC9, 0xCF, 0xCE, 0xC4, 0xC6, 0xCC, 0xCB, 0xC2, 0xC5, 0xC3, 0x77, 0x7D, 0x7A, 0x71, 0x70, 0x78, 0x79, 0x7F, 0x7E, 0x74, 0x76, 0x7C, 0x7B, 0x72, 0x75, 0x73, 0x67, 0x6D, 0x6A, 0x61, 0x60, 0x68, 0x69, 0x6F, 0x6E, 0x64, 0x66, 0x6C, 0x6B, 0x62, 0x65, 0x63, 0x07, 0x0D, 0x0A, 0x01, 0x00, 0x08, 0x09, 0x0F, 0x0E, 0x04, 0x06, 0x0C, 0x0B, 0x02, 0x05, 0x03, 0x97, 0x9D, 0x9A, 0x91, 0x90, 0x98, 0x99, 0x9F, 0x9E, 0x94, 0x96, 0x9C, 0x9B, 0x92, 0x95, 0x93, 0xB7, 0xBD, 0xBA, 0xB1, 0xB0, 0xB8, 0xB9, 0xBF, 0xBE, 0xB4, 0xB6, 0xBC, 0xBB, 0xB2, 0xB5, 0xB3 }; const static u8 k43[256] = { 0x64, 0x6B, 0x6A, 0x60, 0x67, 0x62, 0x61, 0x6D, 0x63, 0x66, 0x68, 0x65, 0x69, 0x6C, 0x6F, 0x6E, 0xC4, 0xCB, 0xCA, 0xC0, 0xC7, 0xC2, 0xC1, 0xCD, 0xC3, 0xC6, 0xC8, 0xC5, 0xC9, 0xCC, 0xCF, 0xCE, 0x74, 0x7B, 0x7A, 0x70, 0x77, 0x72, 0x71, 0x7D, 0x73, 0x76, 0x78, 0x75, 0x79, 0x7C, 0x7F, 0x7E, 0x14, 0x1B, 0x1A, 0x10, 0x17, 0x12, 0x11, 0x1D, 0x13, 0x16, 0x18, 0x15, 0x19, 0x1C, 0x1F, 0x1E, 0x54, 0x5B, 0x5A, 0x50, 0x57, 0x52, 0x51, 0x5D, 0x53, 0x56, 0x58, 0x55, 0x59, 0x5C, 0x5F, 0x5E, 0xF4, 0xFB, 0xFA, 0xF0, 0xF7, 0xF2, 0xF1, 0xFD, 0xF3, 0xF6, 0xF8, 0xF5, 0xF9, 0xFC, 0xFF, 0xFE, 0xD4, 0xDB, 0xDA, 0xD0, 0xD7, 0xD2, 0xD1, 0xDD, 0xD3, 0xD6, 0xD8, 0xD5, 0xD9, 0xDC, 0xDF, 0xDE, 0x84, 0x8B, 0x8A, 0x80, 0x87, 0x82, 0x81, 0x8D, 0x83, 0x86, 0x88, 0x85, 0x89, 0x8C, 0x8F, 0x8E, 0x44, 0x4B, 0x4A, 0x40, 0x47, 0x42, 0x41, 0x4D, 0x43, 0x46, 0x48, 0x45, 0x49, 0x4C, 0x4F, 0x4E, 0xA4, 0xAB, 0xAA, 0xA0, 0xA7, 0xA2, 0xA1, 0xAD, 0xA3, 0xA6, 0xA8, 0xA5, 0xA9, 0xAC, 0xAF, 0xAE, 0x94, 0x9B, 0x9A, 0x90, 0x97, 0x92, 0x91, 0x9D, 0x93, 0x96, 0x98, 0x95, 0x99, 0x9C, 0x9F, 0x9E, 0xE4, 0xEB, 0xEA, 0xE0, 0xE7, 0xE2, 0xE1, 0xED, 0xE3, 0xE6, 0xE8, 0xE5, 0xE9, 0xEC, 0xEF, 0xEE, 0x04, 0x0B, 0x0A, 0x00, 0x07, 0x02, 0x01, 0x0D, 0x03, 0x06, 0x08, 0x05, 0x09, 0x0C, 0x0F, 0x0E, 0x34, 0x3B, 0x3A, 0x30, 0x37, 0x32, 0x31, 0x3D, 0x33, 0x36, 0x38, 0x35, 0x39, 0x3C, 0x3F, 0x3E, 0xB4, 0xBB, 0xBA, 0xB0, 0xB7, 0xB2, 0xB1, 0xBD, 0xB3, 0xB6, 0xB8, 0xB5, 0xB9, 0xBC, 0xBF, 0xBE, 0x24, 0x2B, 0x2A, 0x20, 0x27, 0x22, 0x21, 0x2D, 0x23, 0x26, 0x28, 0x25, 0x29, 0x2C, 0x2F, 0x2E }; const static u8 k21[256] = { 0xD1, 0xDF, 0xDD, 0xD0, 0xD5, 0xD7, 0xDA, 0xD4, 0xD9, 0xD2, 0xD3, 0xDE, 0xD6, 0xDB, 0xD8, 0xD2, 0xB1, 0xBF, 0xBD, 0xB0, 0xB5, 0xB7, 0xBA, 0xB4, 0xB9, 0xB2, 0xB3, 0xBE, 0xB6, 0xBB, 0xB8, 0xB2, 0x41, 0x4F, 0x4D, 0x40, 0x45, 0x47, 0x4A, 0x44, 0x49, 0x42, 0x43, 0x4E, 0x46, 0x4B, 0x48, 0x42, 0x11, 0x1F, 0x1D, 0x10, 0x15, 0x17, 0x1A, 0x14, 0x19, 0x12, 0x13, 0x1E, 0x16, 0x1B, 0x18, 0x12, 0x31, 0x3F, 0x3D, 0x30, 0x35, 0x37, 0x3A, 0x34, 0x39, 0x32, 0x33, 0x3E, 0x36, 0x3B, 0x38, 0x32, 0xF1, 0xFF, 0xFD, 0xF0, 0xF5, 0xF7, 0xFA, 0xF4, 0xF9, 0xF2, 0xF3, 0xFE, 0xF6, 0xFB, 0xF8, 0xF2, 0x51, 0x5F, 0x5D, 0x50, 0x55, 0x57, 0x5A, 0x54, 0x59, 0x52, 0x53, 0x5E, 0x56, 0x5B, 0x58, 0x52, 0x91, 0x9F, 0x9D, 0x90, 0x95, 0x97, 0x9A, 0x94, 0x99, 0x92, 0x93, 0x9E, 0x96, 0x9B, 0x98, 0x92, 0x01, 0x0F, 0x0D, 0x00, 0x05, 0x07, 0x0A, 0x04, 0x09, 0x02, 0x03, 0x0E, 0x06, 0x0B, 0x08, 0x02, 0xA1, 0xAF, 0xAD, 0xA0, 0xA5, 0xA7, 0xAA, 0xA4, 0xA9, 0xA2, 0xA3, 0xAE, 0xA6, 0xAB, 0xA8, 0xA2, 0xE1, 0xEF, 0xED, 0xE0, 0xE5, 0xE7, 0xEA, 0xE4, 0xE9, 0xE2, 0xE3, 0xEE, 0xE6, 0xEB, 0xE8, 0xE2, 0x71, 0x7F, 0x7D, 0x70, 0x75, 0x77, 0x7A, 0x74, 0x79, 0x72, 0x73, 0x7E, 0x76, 0x7B, 0x78, 0x72, 0x61, 0x6F, 0x6D, 0x60, 0x65, 0x67, 0x6A, 0x64, 0x69, 0x62, 0x63, 0x6E, 0x66, 0x6B, 0x68, 0x62, 0x81, 0x8F, 0x8D, 0x80, 0x85, 0x87, 0x8A, 0x84, 0x89, 0x82, 0x83, 0x8E, 0x86, 0x8B, 0x88, 0x82, 0x21, 0x2F, 0x2D, 0x20, 0x25, 0x27, 0x2A, 0x24, 0x29, 0x22, 0x23, 0x2E, 0x26, 0x2B, 0x28, 0x22, 0xC1, 0xCF, 0xCD, 0xC0, 0xC5, 0xC7, 0xCA, 0xC4, 0xC9, 0xC2, 0xC3, 0xCE, 0xC6, 0xCB, 0xC8, 0xC2 };
Ну во-первых, честно скажу, что С для меня малознаком - я об это предупредил перед постом с кодом. А во-вторых, человек просил исходники - я полагаю, общеизвестно, что ГОСТ 28147 не специфицирует сами узлы замен. Следовательно, для учебных целей он может брать узлы какие угодно, хоть из ЦБ хоть из ГОСТ Р 34.11, а если пишет для серьезного проекта, то ему их "сверху спустят".
Спасибо большое за помощь! Начало положено, буду разбираться... Я очень (!) малознаком с С и совсем не знаком с ассемблером, так что и искал без ассемблерных вставок. Писал в свое время на VB, немножко Паскаль и Perl. А теперь приспичило на С, причем на очень своеобразной реализации - Neuron C для LON-контроллеров.
Доброго времени суток! Пытаюсь вникать... Получается не очень... Из исходных кодов алгоритма выбрал два файла: 1. Тот, который по ссылке из этой темы в архиве PPMP (libgost.ppmp). 2. Тот, который показан в этой же теме в конце первой страницы в открытом виде. ... Есть и еще куча различных файлов, нарытых в инете, однако все они с ассемблерными вставками, что мне противопоказано, поэтому вопросы, с Вашего позволения, буду задавать касательно этих двух файлов. Почему эти два файла так сильно отличаются, если в файле №1 указано, что это доработанный вариант в части S-BOX. Насколько я понимаю, другие S-BOX и отсутствие в файле "инициализации" этих S-BOX должны иметь отличия в файлах, а остальное должно быть одинаковое? Где, например, в файле №1 имеющиеся в файле №2 строки, которые идут начиная со строки #define C1 0x01010104 и далее (до конца)? И самый главный вопрос, который касается несоответствия типов языка Neuron C и языка ANSI C: В Neuron C тип char = 8 бит, тип short int = 8 бит, тип long int = 16 бит. К сожалению, 32-битных типов там нет, а это, насколько я понимаю, краеугольный камень ГОСТа? А реализовать этот ГОСТ очень нужно на этом языке и для этого железа. Как выходить из этого положения?
Небольшое дополнение... Если быть совсем точным, то Neron C немножко умеет работать с 32-битными числами, но очень ущербно... Вот выдержка из мануала: Код (Text): Signed 32-Bit Integer Support Functions The Neuron C compiler does not directly support the use of the C arithmetic and comparison operators with signed 32-bit integers. However, there is a complete library of functions for 32-bit integer match. These functions are listed under Integer Math in the previous section. For example, in standard ANSI C, to evaluate X = A + B * C in long (32-bit) arithmetic, the '+' and '*' infix operators may be used as follows: long X, A, B, C; X = A + B * C; With Neuron C, this can be expressed as follows: s32_type X, A, B, C; s32_mul(&B, &C, &X); s32_add(&X, &A, &X); The signed 32-bit integer format can represent numbers in the range of ±2,147,483,647 with an absolute resolution of ±1. An s32_type structure data type for signed 32-bit integers is defined by means of a typedef in the file <S32.H>. It defines a structure containing an array of four bytes that represents a signed 32-bit integer in Neuron C format. This is represented as a two's complement number stored with the most significant byte first. The type declaration is shown here for reference: typedef struct { int bytes[ 4 ]; } s32_type; All the constants and functions in <S32.H> are defined using the Neuron C signed 32-bit data type, which is a structure. Neuron C does not permit structures to be passed as parameters or returned as values from functions. When these objects are passed as parameters to C functions, they are passed as addresses (using the '&' operator) rather than as values. However, Neuron C does support structure assignment, so signed 32-bit integers may be assigned to each other with the '=' operator. No errors are detected by the 32-bit functions. Overflows follow the rules of the C programming language for integers, namely, they are ignored. Only the least significant 32 bits of the results are returned. Initializers can be defined using structure initialization syntax. For example: s32_type some_number = { 0, 0, 0, 4 }; // initialized to 4 on reset s32_type another_number = { -1, -1, -1, -16 }; // initialized to -16 A number of constants are defined for use by the application if desired. s32_zero, s32_one, s32_minus_one represent the numbers 0, 1, and -1. If other constants are desired, they may be converted at runtime from ASCII strings using the function s32_from_ascii. EXAMPLE: s32_type one_million; when(reset) { s32_from_ascii("1000000", one_million); } Since this function is fairly time consuming, it may be advantageous to precompute constants with the NXT.EXE utility. This program accepts an input file with declarations using standard integer initializers, and creates an output file with Neuron C initializers. See the Neuron C Extended Arithmetic Translator section below. For example, if the input file contains: const s32_type one_million = 1000000; then the output file will contain: const s32_type one_million = {0x00,0x0f,0x42,0x40} /* 1000000 */; Users of the NodeBuilder tool can use Code Wizard to create initializer data for s32_type network variables and configuration parameters. The NodeBuilder Neuron C debugger can display signed 32-bit integers through the s32_type shown above. The LonBuilder’s Neuron C debugger can display signed 32-bit integers as raw data at a specific address. To examine the value of one or more contiguous signed 32-bit integer variables, enter the address of the first variable into the raw data evaluation window, select Raw Data at Address type, Data Size as quad, Count as the number of variables you wish to display, and Format as Dec. The data will be displayed as unsigned, even if it is negative. To view the data as signed, click on the value field, and the Modify Variable window will show the data in both formats. You can also modify signed 32-bit integer variables by clicking on the value field, and entering new data in the usual format for integers. The signed 32-bit integer arguments are all passed as addresses of structures. The calling function or task is responsible for declaring storage for the arguments themselves. Argument lists are ordered so that input arguments precede output arguments. In all cases, signed 32-bit integer output arguments may match any of the input arguments to facilitate operations in place. Binary Arithmetic Operators void s32_add( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Adds two signed 32-bit integers. ( arg3 = arg1 + arg2 ) void s32_sub( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Subtracts two signed 32-bit integers. ( arg3 = arg1 - arg2 ) void s32_mul( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Multiplies two signed 32-bit integers. ( arg3 = arg1 * arg2 ) void s32_div( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Divides two signed 32-bit integers. ( arg3 = arg1 / arg2 ) void s32_rem( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Returns the remainder of the division of two signed 32-bit integers ( arg3 = arg1 % arg2 ). The sign of arg3 is always the same as the sign of arg1. void s32_max( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Returns the maximum of two signed 32-bit integers. ( arg3 = max(arg1, arg2 )). void s32_min( const s32_type * arg1, const s32_type * arg2, s32_type * arg3 ); Returns the minimum of two signed 32-bit integers. ( arg3 = min( arg1, arg2 )). Unary Arithmetic Operators void s32_abs( const s32_type * arg1, s32_type * arg2 ); Returns the absolute value of a signed 32-bit integer. ( arg2 = abs(arg1 ) ) void s32_neg( const s32_type * arg1, s32_type * arg2 ); Returns the negative of a signed 32-bit integer. ( arg2 = - arg1 ) Comparison Operators boolean s32_eq( const s32_type * arg1, const s32_type * arg2 ); Returns TRUE if the first argument is equal to the second argument, otherwise FALSE. ( arg1 == arg2 ) boolean s32_ne( const s32_type * arg1, const s32_type * arg2 ); Returns TRUE if the first argument is not equal to the second argument, otherwise FALSE. ( arg1 != arg2 ) boolean s32_gt( const s32_type * arg1, const s32_type * arg2 ); Returns TRUE if the first argument is greater than the second argument, otherwise FALSE. ( arg1 > arg2 ) boolean s32_lt( const s32_type * arg1, const s32_type * arg2 ); Returns TRUE if the first argument is less than the second argument, otherwise FALSE. ( arg1 < arg2 ) boolean s32_ge( const s32_type * arg1, const s32_type * arg2 ); Returns TRUE if the first argument is greater than or equal to the second argument, otherwise FALSE. ( arg1 >= arg2 ) boolean s32_le( const s32_type * arg1, const s32_type * arg2 ); Returns TRUE if the first argument is less than or equal to the second argument, otherwise FALSE. ( arg1 <= arg2 ) int s32_cmp( const s32_type * arg1, const s32_type * arg2 ); Returns +1 if the first argument is greater than the second argument, -1 if it is less, and 0 if it is equal. Miscellaneous Signed 32-bit Functions int s32_sign( const s32_type * arg ); Sign function, returns +1 if the argument is positive, 0 if the argument is zero, and -1 if the argument is negative. void s32_inc( s32_type * arg ); Increments a signed 32-bit integer. void s32_dec( s32_type * arg ); Decrements a signed 32-bit integer. void s32_mul2( s32_type * arg ); Multiplies a signed 32-bit integer by two. void s32_div2( s32_type * arg ); Divides a signed 32-bit integer by two. void s32_rand( s32_type * arg ); Returns a random integer uniformly distributed in the range [-2,147,483,648 to +2,147,483,647]. Integer Conversions signed long s32_to_slong( const s32_type * arg ); Converts a signed 32-bit integer to a Neuron C signed long integer (range 32,768 to +32,767). Overflow is ignored. unsigned long s32_to_ulong( const s32_type * arg ); Converts a signed 32-bit integer to a Neuron C unsigned long integer (range 0 to 65,535). Overflow is ignored. void s32_from_slong( signed long arg1, s32_type * arg2 ); Converts a Neuron C signed long integer (range -32,768 to +32,767) to a signed 32-bit integer. void s32_from_ulong( unsigned long arg1, s32_type * arg2 ); Converts a Neuron C unsigned long integer (range 0 to +65,535) to a signed 32-bit integer. Conversion of Signed 32-bit to ASCII String void s32_to_ascii( const s32_type * arg1, char * arg2 ); Converts a signed 32-bit integer *arg1 to an ASCII string followed by a terminating null character. The *arg2 output buffer should be at least 12 bytes long. The general output format is [-]xxxxxxxxxx, with one to nine digits. Conversion of ASCII String to Signed 32-bit void s32_from_ascii( const char * arg1, s32_type * arg2 ); Converts an ASCII string arg1 to a signed 32-bit integer *arg2. The conversion stops at the first invalid character in the input buffer - there is no error notification. The acceptable format is [-]xxxxxxxxxx. The number of digits should not exceed ten. Embedded spaces within the string are not allowed. Достаточно ли этого расширенного набора для проведения вычислений и преобразований по ГОСТ?
В ГОСТе всего 3 вида 32-разрядных операций (подстановку sbox не считаю) : - XOR - сложение ADD - циклический сдвиг ROL Если процессор 16-разрядный, то XOR делается по частям вообще без каких-либо дополнений ADD делается с учетом флага переноса (ADD младших половинок, затем ADC старших половинок) ROL делается за 4 операции 16-битных ROL/ROR с учетом того в какие позиции должны попасть соответствующие биты
Поправьте, если ошибаюсь... Например, имеем 32-битные беззнаковые числа, состоящие в моей реализации из двух 16-битных беззнаковых чисел: unsigned long xHi, xLo, tmpHi, tmpLo; тогда функция замены и сдвига на 11 бит, описанная в этой теме, аналогично показанной ниже: Код (Text): tmp = k87[x >> 24 & 255] << 24 | k65[x >> 16 & 255] << 16 | k43[x >> 8 & 255] << 8 | k21[x & 255]; x = (tmp << 11) | (tmp >> (32 - 11)); получаем: Код (Text): tmpHi = k87[xHi >> 8 & 255] << 8 | k65[xHi & 255]; tmpLo = k43[xLo >> 8 & 255] << 8 | k21[xLo & 255]; xHi = (tmpHi << 11) | (tmpLo >> (16-11)); xLo = (tmpLo << 11) | (tmpHi >> (16-11)); Не уверен, что правильно... P.S. Вообще не понимаю, как сделать
Да именно так. По моему все коэффициенты верны. В Ассемблере в случае переполнения при сложении/вычитании устанавливается флаг переноса в значение 1. А команда ADC складывает кроме двух чисел еще и третий компонент - значение флага переноса (от предыдущего сложения). Как это реализовать на языке высокого уровня ? Могу лишь предположить вот такой код, наверное, программисты меня подправят более простым решением : Код (Text): пытаемся вычислить z=x+y zLo:=xLo+yLo; zHi:=xHi+yHi; if (zLo<xLo) then zHi:=zHi+1 все 6 переменных обязательно должны быть беззнаковыми (16-битными), только тогда условие (zLo<xLo) уникально указывает на произошедшее переполнение из 15-го в 16-ый разряд при сложении (проверять можно и второе условие zLo<yLo - без разницы)
Продолжим, с Вашего позволения... По поводу инициализации синхропосылки. Нашел вот такой кусок: Код (Text): ULONG64 WINAPI gInitSynchro(PULONG Key){ ULONG64 Result = 0; PULONG64 p_int64 = (PULONG64)Key; // Инициируем синхропосылку из ключей (XOR 64-х битные слова) for(int i = 0; i < 4; i++){ Result ^= *(p_int64 + i); } return Result; } Зачем нужен этот кусок? И как он увязывается, например, с описанной ниже опцией, взятой из программы GOST32.EXE А.Винокурова: /s<значение> - задает синхропосылку, <значение> - от 1 до 16 16-ричных цифр;
За такие куски надо отрывать руки программистам А этот кусок нужен для того, чтобы помочь злоумышленнику дешифровать шифртекст, очевидно.
Тогда как правильно должна выглядеть инициализация синхропосылки и дальнейшее вычисление гаммы? Особенно интересует как правильно реализовать на Си формулы вычисления шага работы РГПЧ, описанный у А.Винокурова: S0=(S0+C1)mod2^32 S1=(S1+C2–1)mod(2^32–1)+1 А то есть много (нарытого на просторах инета) кусков, написанных настолько по-разному, что общая картина никак не складывается! И ведь для того, чтобы весь алгоритм переложить на 16-тиразрядную платформу, нужно полностью разобраться с тем, что есть...
Синхропосылка выбирается случайным образом,т.е. для её успешной реализации необходим псевдослучайный генератор. У Винокурова написано что используется не сама сгенерированная синхропосылка S, а результат шифрования S на ключе K. Мне кажется вы совершенно не понимаете, что есть синхропосылка и почему нельзя её генерировать так, как написано в предыдущем куске кода. А это плохо. Если нужно могу объяснить. Лучше замутить на асме, тогда первая команда add S0,C1 а вторая adc S1,C2. Надеюсь не наврал. Если же нужен Си, то, как известно, mod - это оператор "%".
Однозначно не понимаю... И буду премного благодарен, если Вы объясните. Асм не пойдет, т.к. я уже писал выше, что нужна реализация на Си-подобном языке для 16-разрядной платформы: