/* Copyright (C) 2008 Luigi Auriemma This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. http://www.gnu.org/licenses/gpl-2.0.txt */ // modified by Luigi Auriemma for emulating the shameful customizations of MagicISO /* * 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. */ #include <stdio.h> #include <stdint.h> /* A 32-bit data type */ #ifdef __alpha /* Any other 64-bit machines? */ typedef unsigned int word32; #else typedef uint32_t 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 = (char)k87[x>>24 & 255] << 24 | (char)k65[x>>16 & 255] << 16 | (char)k43[x>> 8 & 255] << 8 | (char)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 */

Generated by Doxygen 1.6.0 Back to index