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 **********************************************************************/
13 Substitution blocks from RFC 4357
15 Note: our implementation of gost 28147-89 algorithm
16 uses S-box matrix rotated 90 degrees counterclockwise, relative to
17 examples given in RFC.
22 /* Substitution blocks from test examples for GOST R 34.11-94*/
23 gost_subst_block GostR3411_94_TestParamSet = {
24 {0X1,0XF,0XD,0X0,0X5,0X7,0XA,0X4,0X9,0X2,0X3,0XE,0X6,0XB,0X8,0XC},
25 {0XD,0XB,0X4,0X1,0X3,0XF,0X5,0X9,0X0,0XA,0XE,0X7,0X6,0X8,0X2,0XC},
26 {0X4,0XB,0XA,0X0,0X7,0X2,0X1,0XD,0X3,0X6,0X8,0X5,0X9,0XC,0XF,0XE},
27 {0X6,0XC,0X7,0X1,0X5,0XF,0XD,0X8,0X4,0XA,0X9,0XE,0X0,0X3,0XB,0X2},
28 {0X7,0XD,0XA,0X1,0X0,0X8,0X9,0XF,0XE,0X4,0X6,0XC,0XB,0X2,0X5,0X3},
29 {0X5,0X8,0X1,0XD,0XA,0X3,0X4,0X2,0XE,0XF,0XC,0X7,0X6,0X0,0X9,0XB},
30 {0XE,0XB,0X4,0XC,0X6,0XD,0XF,0XA,0X2,0X3,0X8,0X1,0X0,0X7,0X5,0X9},
31 {0X4,0XA,0X9,0X2,0XD,0X8,0X0,0XE,0X6,0XB,0X1,0XC,0X7,0XF,0X5,0X3}
33 /* Substitution blocks for hash function 1.2.643.2.9.1.6.1 */
34 gost_subst_block GostR3411_94_CryptoProParamSet= {
35 {0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC},
36 {0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB},
37 {0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3},
38 {0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5},
39 {0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3},
40 {0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD},
41 {0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8},
42 {0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF}
45 /* Test paramset from GOST 28147 */
46 gost_subst_block Gost28147_TestParamSet =
48 {0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8},
49 {0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD},
50 {0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4},
51 {0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4},
52 {0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8},
53 {0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB},
54 {0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5},
55 {0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6}
61 /* 1.2.643.2.2.31.1 */
62 gost_subst_block Gost28147_CryptoProParamSetA= {
63 {0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4},
64 {0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE},
65 {0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6},
66 {0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6},
67 {0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6},
68 {0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9},
69 {0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1},
70 {0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5}
72 /* 1.2.643.2.2.31.2 */
73 gost_subst_block Gost28147_CryptoProParamSetB=
75 {0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC},
76 {0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE},
77 {0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5},
78 {0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3},
79 {0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8},
80 {0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4},
81 {0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE},
82 {0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF}
84 /* 1.2.643.2.2.31.3 */
85 gost_subst_block Gost28147_CryptoProParamSetC=
87 {0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8},
88 {0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7},
89 {0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD},
90 {0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7},
91 {0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4},
92 {0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB},
93 {0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3},
94 {0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3}
97 /* 1.2.643.2.2.31.4 */
98 gost_subst_block Gost28147_CryptoProParamSetD=
100 {0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE},
101 {0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7},
102 {0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6},
103 {0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1},
104 {0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8},
105 {0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2},
106 {0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1},
107 {0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3}
111 const byte CryptoProKeyMeshingKey[]={
112 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23,
113 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4,
114 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12,
115 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B
117 /* Initialization of gost_ctx subst blocks*/
118 static void kboxinit(gost_ctx *c, const gost_subst_block *b)
122 for (i = 0; i < 256; i++)
124 c->k87[i] = (word32)(b->k8[i>>4] <<4 | b->k7 [i &15])<<24;
125 c->k65[i] = (b->k6[i>>4] << 4 | b->k5 [i &15])<<16;
126 c->k43[i] = (b->k4[i>>4] <<4 | b->k3 [i &15])<<8;
127 c->k21[i] = b->k2[i>>4] <<4 | b->k1 [i &15];
132 /* Part of GOST 28147 algorithm moved into separate function */
133 static word32 f(gost_ctx *c,word32 x)
135 x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]|
136 c->k43[x>> 8 & 255] | c->k21[x & 255];
137 /* Rotate left 11 bits */
138 return x<<11 | x>>(32-11);
140 /* Low-level encryption routine - encrypts one 64 bit block*/
141 void gostcrypt(gost_ctx *c, const byte *in, byte *out)
143 register word32 n1, n2; /* As named in the GOST */
144 n1 = in[0]|(in[1]<<8)|(in[2]<<16)|((word32)in[3]<<24);
145 n2 = in[4]|(in[5]<<8)|(in[6]<<16)|((word32)in[7]<<24);
146 /* Instead of swapping halves, swap names each round */
148 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
149 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
150 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
151 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
153 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
154 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
155 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
156 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
158 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
159 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
160 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
161 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
163 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
164 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
165 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
166 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
168 out[0] = (byte)(n2&0xff); out[1] = (byte)((n2>>8)&0xff);
169 out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
170 out[4] = (byte)(n1&0xff); out[5] = (byte)((n1>>8)&0xff);
171 out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
173 /* Low-level decryption routine. Decrypts one 64-bit block */
174 void gostdecrypt(gost_ctx *c, const byte *in,byte *out)
176 register word32 n1, n2; /* As named in the GOST */
177 n1 = in[0]|(in[1]<<8)|(in[2]<<16)|((word32)in[3]<<24);
178 n2 = in[4]|(in[5]<<8)|(in[6]<<16)|((word32)in[7]<<24);
180 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
181 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
182 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
183 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
185 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
186 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
187 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
188 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
190 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
191 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
192 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
193 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
195 n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
196 n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
197 n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
198 n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
200 out[0] = (byte)(n2&0xff); out[1] = (byte)((n2>>8)&0xff);
201 out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
202 out[4] = (byte)(n1&0xff); out[5] = (byte)((n1>>8)&0xff);
203 out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
206 /* Encrypts several blocks in ECB mode */
207 void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
210 for(i=0;i<blocks;i++)
212 gostcrypt(c,clear,cipher);
217 /* Decrypts several blocks in ECB mode */
218 void gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks)
221 for(i=0;i<blocks;i++)
223 gostdecrypt(c,cipher,clear);
229 /* Encrypts several full blocks in CFB mode using 8byte IV */
230 void gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher, int blocks)
238 for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8)
240 gostcrypt(ctx,cur_iv,gamma);
243 cur_iv[j]=out[j]=in[j]^gamma[j];
247 /* Decrypts several full blocks in CFB mode using 8byte IV */
248 void gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear, int blocks)
256 for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8)
258 gostcrypt(ctx,cur_iv,gamma);
261 out[j]=(cur_iv[j]=in[j])^gamma[j];
266 /* Encrypts one block using specified key */
267 void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock)
270 gostcrypt(c,inblock,outblock);
273 /* Set 256 bit key into context */
274 void gost_key(gost_ctx *c, const byte *k)
277 for(i=0,j=0;i<8;i++,j+=4)
279 c->k[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|((word32)k[j+3]<<24);
283 /* Retrieve 256-bit key from context */
284 void gost_get_key(gost_ctx *c, byte *k)
287 for(i=0,j=0;i<8;i++,j+=4)
289 k[j]=(byte)(c->k[i]& 0xFF);
290 k[j+1]=(byte)((c->k[i]>>8 )&0xFF);
291 k[j+2]=(byte)((c->k[i]>>16) &0xFF);
292 k[j+3]=(byte)((c->k[i]>>24) &0xFF);
296 /* Initalize context. Provides default value for subst_block */
297 void gost_init(gost_ctx *c, const gost_subst_block *b)
301 b=&GostR3411_94_TestParamSet;
306 /* Cleans up key from context */
307 void gost_destroy(gost_ctx *c)
309 int i; for(i=0;i<8;i++) c->k[i]=0;
312 /* Compute GOST 28147 mac block
315 * gost_ctx *c - context initalized with substitution blocks and key
316 * buffer - 8-byte mac state buffer
317 * block 8-byte block to process.
319 void mac_block(gost_ctx *c,byte *buffer,const byte *block)
321 register word32 n1, n2; /* As named in the GOST */
327 n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|((word32)buffer[3]<<24);
328 n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|((word32)buffer[7]<<24);
329 /* Instead of swapping halves, swap names each round */
331 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
332 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
333 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
334 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
336 n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
337 n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
338 n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
339 n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
341 buffer[0] = (byte)(n1&0xff); buffer[1] = (byte)((n1>>8)&0xff);
342 buffer[2] = (byte)((n1>>16)&0xff); buffer[3] = (byte)(n1>>24);
343 buffer[4] = (byte)(n2&0xff); buffer[5] = (byte)((n2>>8)&0xff);
344 buffer[6] = (byte)((n2>>16)&0xff); buffer[7] = (byte)(n2>>24);
347 /* Get mac with specified number of bits from MAC state buffer */
348 void get_mac(byte *buffer,int nbits,byte *out)
350 int nbytes= nbits >> 3;
351 int rembits = nbits & 7;
352 int mask =rembits?((1<rembits)-1):0;
354 for (i=0;i<nbytes;i++) out[i]=buffer[i];
355 if (rembits) out[i]=buffer[i]&mask;
358 /* Compute mac of specified length (in bits) from data.
359 * Context should be initialized with key and subst blocks */
360 int gost_mac(gost_ctx *ctx,int mac_len,const unsigned char *data,
361 unsigned int data_len,unsigned char *mac)
363 byte buffer[8]={0,0,0,0,0,0,0,0};
366 for (i=0;i+8<=data_len;i+=8)
367 mac_block(ctx,buffer,data+i);
371 memcpy(buf2,data+i,data_len-i);
372 mac_block(ctx,buffer,buf2);
378 mac_block(ctx,buffer,buf2);
380 get_mac(buffer,mac_len,mac);
384 /* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
385 int gost_mac_iv(gost_ctx *ctx,int mac_len,const unsigned char *iv,const unsigned char *data,
386 unsigned int data_len,unsigned char *mac)
391 memcpy (buffer,iv,8);
392 for (i=0;i+8<=data_len;i+=8)
393 mac_block(ctx,buffer,data+i);
397 memcpy(buf2,data+i,data_len-i);
398 mac_block(ctx,buffer,buf2);
404 mac_block(ctx,buffer,buf2);
406 get_mac(buffer,mac_len,mac);
410 /* Implements key meshing algorithm by modifing ctx and IV in place */
411 void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv)
413 unsigned char newkey[32],newiv[8];
414 /* Set static keymeshing key */
415 /* "Decrypt" key with keymeshing key */
416 gost_dec(ctx,CryptoProKeyMeshingKey,newkey,4);
418 gost_key(ctx,newkey);
419 /* Encrypt iv with new key */
420 gostcrypt(ctx,iv,newiv);