1 /**********************************************************************
3 * Copyright (c) 2005-2006 Cryptocom LTD *
4 * This file is distributed under the same license as OpenSSL *
6 * Implementation of GOST 28147-89 encryption algorithm *
7 * No OpenSSL libraries required to compile and use *
9 **********************************************************************/
12 /* Substitution blocks from RFC 4357
14 Note: our implementation of gost 28147-89 algorithm
15 uses S-box matrix rotated 90 degrees counterclockwise, relative to
16 examples given in RFC.
21 /* Substitution blocks from test examples for GOST R 34.11-94*/
22 gost_subst_block GostR3411_94_TestParamSet = {
23 {0X1,0XF,0XD,0X0,0X5,0X7,0XA,0X4,0X9,0X2,0X3,0XE,0X6,0XB,0X8,0XC},
24 {0XD,0XB,0X4,0X1,0X3,0XF,0X5,0X9,0X0,0XA,0XE,0X7,0X6,0X8,0X2,0XC},
25 {0X4,0XB,0XA,0X0,0X7,0X2,0X1,0XD,0X3,0X6,0X8,0X5,0X9,0XC,0XF,0XE},
26 {0X6,0XC,0X7,0X1,0X5,0XF,0XD,0X8,0X4,0XA,0X9,0XE,0X0,0X3,0XB,0X2},
27 {0X7,0XD,0XA,0X1,0X0,0X8,0X9,0XF,0XE,0X4,0X6,0XC,0XB,0X2,0X5,0X3},
28 {0X5,0X8,0X1,0XD,0XA,0X3,0X4,0X2,0XE,0XF,0XC,0X7,0X6,0X0,0X9,0XB},
29 {0XE,0XB,0X4,0XC,0X6,0XD,0XF,0XA,0X2,0X3,0X8,0X1,0X0,0X7,0X5,0X9},
30 {0X4,0XA,0X9,0X2,0XD,0X8,0X0,0XE,0X6,0XB,0X1,0XC,0X7,0XF,0X5,0X3}
32 /* Substitution blocks for hash function 1.2.643.2.9.1.6.1 */
33 gost_subst_block GostR3411_94_CryptoProParamSet= {
34 {0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC},
35 {0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB},
36 {0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3},
37 {0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5},
38 {0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3},
39 {0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD},
40 {0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8},
41 {0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF}
44 /* Test paramset from GOST 28147 */
45 gost_subst_block Gost28147_TestParamSet =
47 {0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8},
48 {0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD},
49 {0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4},
50 {0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4},
51 {0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8},
52 {0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB},
53 {0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5},
54 {0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6}
60 /* 1.2.643.2.2.31.1 */
61 gost_subst_block Gost28147_CryptoProParamSetA= {
62 {0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4},
63 {0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE},
64 {0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6},
65 {0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6},
66 {0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6},
67 {0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9},
68 {0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1},
69 {0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5}
71 /* 1.2.643.2.2.31.2 */
72 gost_subst_block Gost28147_CryptoProParamSetB=
74 {0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC},
75 {0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE},
76 {0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5},
77 {0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3},
78 {0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8},
79 {0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4},
80 {0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE},
81 {0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF}
83 /* 1.2.643.2.2.31.3 */
84 gost_subst_block Gost28147_CryptoProParamSetC=
86 {0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8},
87 {0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7},
88 {0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD},
89 {0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7},
90 {0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4},
91 {0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB},
92 {0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3},
93 {0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3}
96 /* 1.2.643.2.2.31.4 */
97 gost_subst_block Gost28147_CryptoProParamSetD=
99 {0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE},
100 {0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7},
101 {0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6},
102 {0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1},
103 {0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8},
104 {0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2},
105 {0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1},
106 {0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3}
110 const byte CryptoProKeyMeshingKey[]={
111 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23,
112 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4,
113 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12,
114 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B
116 /* Initialization of gost_ctx subst blocks*/
117 static void kboxinit(gost_ctx *c, const gost_subst_block *b)
121 for (i = 0; i < 256; i++)
123 c->k87[i] = (b->k8[i>>4] <<4 | b->k7 [i &15])<<24;
124 c->k65[i] = (b->k6[i>>4] << 4 | b->k5 [i &15])<<16;
125 c->k43[i] = (b->k4[i>>4] <<4 | b->k3 [i &15])<<8;
126 c->k21[i] = b->k2[i>>4] <<4 | b->k1 [i &15];
131 /* Part of GOST 28147 algorithm moved into separate function */
132 static word32 f(gost_ctx *c,word32 x)
134 x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]|
135 c->k43[x>> 8 & 255] | c->k21[x & 255];
136 /* Rotate left 11 bits */
137 return x<<11 | x>>(32-11);
139 /* Low-level encryption routine - encrypts one 64 bit block*/
140 void gostcrypt(gost_ctx *c, const byte *in, byte *out)
142 register word32 n1, n2; /* As named in the GOST */
143 n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24);
144 n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24);
145 /* Instead of swapping halves, swap names each round */
147 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
148 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
149 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
150 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
152 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
153 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
154 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
155 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
157 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
158 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
159 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
160 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
162 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
163 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
164 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
165 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
167 out[0] = (byte)(n2&0xff); out[1] = (byte)((n2>>8)&0xff);
168 out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
169 out[4] = (byte)(n1&0xff); out[5] = (byte)((n1>>8)&0xff);
170 out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
172 /* Low-level decryption routine. Decrypts one 64-bit block */
173 void gostdecrypt(gost_ctx *c, const byte *in,byte *out)
175 register word32 n1, n2; /* As named in the GOST */
176 n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24);
177 n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24);
179 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
180 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
181 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
182 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
184 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
185 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
186 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
187 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
189 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
190 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
191 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
192 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
194 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
195 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
196 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
197 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
199 out[0] = (byte)(n2&0xff); out[1] = (byte)((n2>>8)&0xff);
200 out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
201 out[4] = (byte)(n1&0xff); out[5] = (byte)((n1>>8)&0xff);
202 out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
205 /* Encrypts several blocks in ECB mode */
206 void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
209 for(i=0;i<blocks;i++)
211 gostcrypt(c,clear,cipher);
216 /* Decrypts several blocks in ECB mode */
217 void gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks)
220 for(i=0;i<blocks;i++)
222 gostdecrypt(c,cipher,clear);
228 /* Encrypts several full blocks in CFB mode using 8byte IV */
229 void gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher, int blocks)
237 for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8)
239 gostcrypt(ctx,cur_iv,gamma);
242 cur_iv[j]=out[j]=in[j]^gamma[j];
246 /* Decrypts several full blocks in CFB mode using 8byte IV */
247 void gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear, int blocks)
255 for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8)
257 gostcrypt(ctx,cur_iv,gamma);
260 out[j]=(cur_iv[j]=in[j])^gamma[j];
265 /* Encrypts one block using specified key */
266 void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock)
269 gostcrypt(c,inblock,outblock);
272 /* Set 256 bit key into context */
273 void gost_key(gost_ctx *c, const byte *k)
276 for(i=0,j=0;i<8;i++,j+=4)
278 c->k[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|(k[j+3]<<24);
282 /* Retrieve 256-bit key from context */
283 void gost_get_key(gost_ctx *c, byte *k)
286 for(i=0,j=0;i<8;i++,j+=4)
288 k[j]=(byte)(c->k[i]& 0xFF);
289 k[j+1]=(byte)((c->k[i]>>8 )&0xFF);
290 k[j+2]=(byte)((c->k[i]>>16) &0xFF);
291 k[j+3]=(byte)((c->k[i]>>24) &0xFF);
295 /* Initalize context. Provides default value for subst_block */
296 void gost_init(gost_ctx *c, const gost_subst_block *b)
300 b=&GostR3411_94_TestParamSet;
305 /* Cleans up key from context */
306 void gost_destroy(gost_ctx *c)
308 int i; for(i=0;i<8;i++) c->k[i]=0;
311 /* Compute GOST 28147 mac block
314 * gost_ctx *c - context initalized with substitution blocks and key
315 * buffer - 8-byte mac state buffer
316 * block 8-byte block to process.
318 void mac_block(gost_ctx *c,byte *buffer,const byte *block)
320 register word32 n1, n2; /* As named in the GOST */
326 n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|(buffer[3]<<24);
327 n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
328 /* Instead of swapping halves, swap names each round */
330 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
331 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
332 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
333 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
335 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
336 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
337 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
338 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
340 buffer[0] = (byte)(n1&0xff); buffer[1] = (byte)((n1>>8)&0xff);
341 buffer[2] = (byte)((n1>>16)&0xff); buffer[3] = (byte)(n1>>24);
342 buffer[4] = (byte)(n2&0xff); buffer[5] = (byte)((n2>>8)&0xff);
343 buffer[6] = (byte)((n2>>16)&0xff); buffer[7] = (byte)(n2>>24);
346 /* Get mac with specified number of bits from MAC state buffer */
347 void get_mac(byte *buffer,int nbits,byte *out)
349 int nbytes= nbits >> 3;
350 int rembits = nbits & 7;
351 int mask =rembits?((1<rembits)-1):0;
353 for (i=0;i<nbytes;i++) out[i]=buffer[i];
354 if (rembits) out[i]=buffer[i]&mask;
357 /* Compute mac of specified length (in bits) from data.
358 * Context should be initialized with key and subst blocks */
359 int gost_mac(gost_ctx *ctx,int mac_len,const unsigned char *data,
360 unsigned int data_len,unsigned char *mac)
362 byte buffer[8]={0,0,0,0,0,0,0,0};
365 for (i=0;i+8<=data_len;i+=8)
366 mac_block(ctx,buffer,data+i);
370 memcpy(buf2,data+i,data_len-i);
371 mac_block(ctx,buffer,buf2);
377 mac_block(ctx,buffer,buf2);
379 get_mac(buffer,mac_len,mac);
383 /* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
384 int gost_mac_iv(gost_ctx *ctx,int mac_len,const unsigned char *iv,const unsigned char *data,
385 unsigned int data_len,unsigned char *mac)
390 memcpy (buffer,iv,8);
391 for (i=0;i+8<=data_len;i+=8)
392 mac_block(ctx,buffer,data+i);
396 memcpy(buf2,data+i,data_len-i);
397 mac_block(ctx,buffer,buf2);
403 mac_block(ctx,buffer,buf2);
405 get_mac(buffer,mac_len,mac);
409 /* Implements key meshing algorithm by modifing ctx and IV in place */
410 void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv)
412 unsigned char newkey[32],newiv[8];
413 /* Set static keymeshing key */
414 /* "Decrypt" key with keymeshing key */
415 gost_dec(ctx,CryptoProKeyMeshingKey,newkey,4);
417 gost_key(ctx,newkey);
418 /* Encrypt iv with new key */
419 gostcrypt(ctx,iv,newiv);