1238384Sjkim/**********************************************************************
2238384Sjkim *                        gost89.c                                    *
3238384Sjkim *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4238384Sjkim *         This file is distributed under the same license as OpenSSL *
5238384Sjkim *                                                                    *
6238384Sjkim *          Implementation of GOST 28147-89 encryption algorithm      *
7238384Sjkim *            No OpenSSL libraries required to compile and use        *
8238384Sjkim *                              this code                             *
9238384Sjkim **********************************************************************/
10238384Sjkim#include <string.h>
11238384Sjkim#include "gost89.h"
12238384Sjkim/* Substitution blocks from RFC 4357
13238384Sjkim
14238384Sjkim   Note: our implementation of gost 28147-89 algorithm
15238384Sjkim   uses S-box matrix rotated 90 degrees counterclockwise, relative to
16238384Sjkim   examples given in RFC.
17238384Sjkim
18238384Sjkim
19238384Sjkim*/
20238384Sjkim
21238384Sjkim/* Substitution blocks from test examples for GOST R 34.11-94*/
22238384Sjkimgost_subst_block GostR3411_94_TestParamSet = {
23238384Sjkim	{0X1,0XF,0XD,0X0,0X5,0X7,0XA,0X4,0X9,0X2,0X3,0XE,0X6,0XB,0X8,0XC},
24238384Sjkim	{0XD,0XB,0X4,0X1,0X3,0XF,0X5,0X9,0X0,0XA,0XE,0X7,0X6,0X8,0X2,0XC},
25238384Sjkim	{0X4,0XB,0XA,0X0,0X7,0X2,0X1,0XD,0X3,0X6,0X8,0X5,0X9,0XC,0XF,0XE},
26238384Sjkim	{0X6,0XC,0X7,0X1,0X5,0XF,0XD,0X8,0X4,0XA,0X9,0XE,0X0,0X3,0XB,0X2},
27238384Sjkim	{0X7,0XD,0XA,0X1,0X0,0X8,0X9,0XF,0XE,0X4,0X6,0XC,0XB,0X2,0X5,0X3},
28238384Sjkim	{0X5,0X8,0X1,0XD,0XA,0X3,0X4,0X2,0XE,0XF,0XC,0X7,0X6,0X0,0X9,0XB},
29238384Sjkim	{0XE,0XB,0X4,0XC,0X6,0XD,0XF,0XA,0X2,0X3,0X8,0X1,0X0,0X7,0X5,0X9},
30238384Sjkim	{0X4,0XA,0X9,0X2,0XD,0X8,0X0,0XE,0X6,0XB,0X1,0XC,0X7,0XF,0X5,0X3}
31238384Sjkim	};
32238384Sjkim/* Substitution blocks for hash function 1.2.643.2.9.1.6.1  */
33238384Sjkimgost_subst_block GostR3411_94_CryptoProParamSet= {
34238384Sjkim	{0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC},
35238384Sjkim	{0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB},
36238384Sjkim	{0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3},
37238384Sjkim	{0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5},
38238384Sjkim	{0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3},
39238384Sjkim	{0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD},
40238384Sjkim	{0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8},
41238384Sjkim	{0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF}
42238384Sjkim	} ;
43238384Sjkim
44238384Sjkim/* Test paramset from GOST 28147 */
45238384Sjkimgost_subst_block Gost28147_TestParamSet =
46238384Sjkim	{
47238384Sjkim	{0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8},
48238384Sjkim	{0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD},
49238384Sjkim	{0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4},
50238384Sjkim	{0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4},
51238384Sjkim	{0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8},
52238384Sjkim	{0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB},
53238384Sjkim	{0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5},
54238384Sjkim	{0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6}
55238384Sjkim	};
56238384Sjkim
57238384Sjkim
58238384Sjkim
59238384Sjkim
60238384Sjkim/* 1.2.643.2.2.31.1 */
61238384Sjkimgost_subst_block Gost28147_CryptoProParamSetA= {
62238384Sjkim	{0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4},
63238384Sjkim	{0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE},
64238384Sjkim	{0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6},
65238384Sjkim	{0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6},
66238384Sjkim	{0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6},
67238384Sjkim	{0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9},
68238384Sjkim	{0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1},
69238384Sjkim	{0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5}
70238384Sjkim	};
71238384Sjkim/* 1.2.643.2.2.31.2 */
72238384Sjkimgost_subst_block Gost28147_CryptoProParamSetB=
73238384Sjkim	{
74238384Sjkim	{0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC},
75238384Sjkim	{0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE},
76238384Sjkim	{0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5},
77238384Sjkim	{0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3},
78238384Sjkim	{0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8},
79238384Sjkim	{0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4},
80238384Sjkim	{0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE},
81238384Sjkim	{0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF}
82238384Sjkim	};
83238384Sjkim/* 1.2.643.2.2.31.3 */
84238384Sjkimgost_subst_block Gost28147_CryptoProParamSetC=
85238384Sjkim	{
86238384Sjkim	{0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8},
87238384Sjkim	{0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7},
88238384Sjkim	{0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD},
89238384Sjkim	{0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7},
90238384Sjkim	{0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4},
91238384Sjkim	{0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB},
92238384Sjkim	{0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3},
93238384Sjkim	{0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3}
94238384Sjkim	};
95238384Sjkim
96238384Sjkim/* 1.2.643.2.2.31.4 */
97238384Sjkimgost_subst_block Gost28147_CryptoProParamSetD=
98238384Sjkim	{
99238384Sjkim	{0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE},
100238384Sjkim	{0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7},
101238384Sjkim	{0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6},
102238384Sjkim	{0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1},
103238384Sjkim	{0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8},
104238384Sjkim	{0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2},
105238384Sjkim	{0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1},
106238384Sjkim	{0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3}
107238384Sjkim	};
108238384Sjkim
109238384Sjkim
110238384Sjkimconst byte CryptoProKeyMeshingKey[]={
111238384Sjkim	0x69, 0x00, 0x72, 0x22,   0x64, 0xC9, 0x04, 0x23,
112238384Sjkim    0x8D, 0x3A, 0xDB, 0x96,   0x46, 0xE9, 0x2A, 0xC4,
113238384Sjkim    0x18, 0xFE, 0xAC, 0x94,   0x00, 0xED, 0x07, 0x12,
114238384Sjkim    0xC0, 0x86, 0xDC, 0xC2,   0xEF, 0x4C, 0xA9, 0x2B
115238384Sjkim	};
116238384Sjkim/* Initialization of gost_ctx subst blocks*/
117238384Sjkimstatic void kboxinit(gost_ctx *c, const gost_subst_block *b)
118238384Sjkim	{
119238384Sjkim	int i;
120238384Sjkim
121238384Sjkim	for (i = 0; i < 256; i++)
122238384Sjkim		{
123238384Sjkim		c->k87[i] = (b->k8[i>>4] <<4 | b->k7 [i &15])<<24;
124238384Sjkim		c->k65[i] = (b->k6[i>>4] << 4 | b->k5 [i &15])<<16;
125238384Sjkim		c->k43[i] = (b->k4[i>>4] <<4  | b->k3 [i &15])<<8;
126238384Sjkim		c->k21[i] = b->k2[i>>4] <<4  | b->k1 [i &15];
127238384Sjkim
128238384Sjkim		}
129238384Sjkim	}
130238384Sjkim
131238384Sjkim/* Part of GOST 28147 algorithm moved into separate function */
132238384Sjkimstatic word32 f(gost_ctx *c,word32 x)
133238384Sjkim	{
134238384Sjkim	x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]|
135238384Sjkim		c->k43[x>> 8 & 255] | c->k21[x & 255];
136238384Sjkim	/* Rotate left 11 bits */
137238384Sjkim	return x<<11 | x>>(32-11);
138238384Sjkim	}
139238384Sjkim/* Low-level encryption routine - encrypts one 64 bit block*/
140238384Sjkimvoid gostcrypt(gost_ctx *c, const byte *in, byte *out)
141238384Sjkim	{
142238384Sjkim	register word32 n1, n2; /* As named in the GOST */
143238384Sjkim	n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24);
144238384Sjkim	n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24);
145238384Sjkim	/* Instead of swapping halves, swap names each round */
146238384Sjkim
147238384Sjkim	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
148238384Sjkim	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
149238384Sjkim	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
150238384Sjkim	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
151238384Sjkim
152238384Sjkim	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
153238384Sjkim	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
154238384Sjkim	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
155238384Sjkim	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
156238384Sjkim
157238384Sjkim	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
158238384Sjkim	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
159238384Sjkim	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
160238384Sjkim	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
161238384Sjkim
162238384Sjkim	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
163238384Sjkim	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
164238384Sjkim	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
165238384Sjkim	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
166238384Sjkim
167238384Sjkim	out[0] = (byte)(n2&0xff);  out[1] = (byte)((n2>>8)&0xff);
168238384Sjkim	out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
169238384Sjkim	out[4] = (byte)(n1&0xff);  out[5] = (byte)((n1>>8)&0xff);
170238384Sjkim	out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
171238384Sjkim	}
172238384Sjkim/* Low-level decryption routine. Decrypts one 64-bit block */
173238384Sjkimvoid gostdecrypt(gost_ctx *c, const byte *in,byte *out)
174238384Sjkim	{
175238384Sjkim	register word32 n1, n2; /* As named in the GOST */
176238384Sjkim	n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24);
177238384Sjkim	n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24);
178238384Sjkim
179238384Sjkim	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
180238384Sjkim	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
181238384Sjkim	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
182238384Sjkim	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
183238384Sjkim
184238384Sjkim	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
185238384Sjkim	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
186238384Sjkim	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
187238384Sjkim	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
188238384Sjkim
189238384Sjkim	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
190238384Sjkim	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
191238384Sjkim	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
192238384Sjkim	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
193238384Sjkim
194238384Sjkim	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
195238384Sjkim	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
196238384Sjkim	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
197238384Sjkim	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
198238384Sjkim
199238384Sjkim	out[0] = (byte)(n2&0xff);  out[1] = (byte)((n2>>8)&0xff);
200238384Sjkim	out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
201238384Sjkim	out[4] = (byte)(n1&0xff);  out[5] = (byte)((n1>>8)&0xff);
202238384Sjkim	out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
203238384Sjkim	}
204238384Sjkim
205238384Sjkim/* Encrypts several blocks in ECB mode */
206238384Sjkimvoid gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
207238384Sjkim	{
208238384Sjkim	int i;
209238384Sjkim	for(i=0;i<blocks;i++)
210238384Sjkim		{
211238384Sjkim		gostcrypt(c,clear,cipher);
212238384Sjkim		clear+=8;
213238384Sjkim		cipher+=8;
214238384Sjkim		}
215238384Sjkim	}
216238384Sjkim/* Decrypts several blocks in ECB mode */
217238384Sjkimvoid gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks)
218238384Sjkim	{
219238384Sjkim	int i;
220238384Sjkim	for(i=0;i<blocks;i++)
221238384Sjkim		{
222238384Sjkim		gostdecrypt(c,cipher,clear);
223238384Sjkim		clear+=8;
224238384Sjkim		cipher+=8;
225238384Sjkim		}
226238384Sjkim	}
227238384Sjkim
228238384Sjkim/* Encrypts several full blocks in CFB mode using 8byte IV */
229238384Sjkimvoid gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher, int blocks)
230238384Sjkim	{
231238384Sjkim	byte cur_iv[8];
232238384Sjkim	byte gamma[8];
233238384Sjkim	int i,j;
234238384Sjkim	const byte *in;
235238384Sjkim	byte *out;
236238384Sjkim	memcpy(cur_iv,iv,8);
237238384Sjkim	for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8)
238238384Sjkim		{
239238384Sjkim		gostcrypt(ctx,cur_iv,gamma);
240238384Sjkim		for (j=0;j<8;j++)
241238384Sjkim			{
242238384Sjkim			cur_iv[j]=out[j]=in[j]^gamma[j];
243238384Sjkim			}
244238384Sjkim		}
245238384Sjkim	}
246238384Sjkim/* Decrypts several full blocks in CFB mode using 8byte IV */
247238384Sjkimvoid gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,  int blocks)
248238384Sjkim	{
249238384Sjkim	byte cur_iv[8];
250238384Sjkim	byte gamma[8];
251238384Sjkim	int i,j;
252238384Sjkim	const byte *in;
253238384Sjkim	byte *out;
254238384Sjkim	memcpy(cur_iv,iv,8);
255238384Sjkim	for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8)
256238384Sjkim		{
257238384Sjkim		gostcrypt(ctx,cur_iv,gamma);
258238384Sjkim		for (j=0;j<8;j++)
259238384Sjkim			{
260238384Sjkim			out[j]=(cur_iv[j]=in[j])^gamma[j];
261238384Sjkim			}
262238384Sjkim		}
263238384Sjkim	}
264238384Sjkim
265238384Sjkim/* Encrypts one block using specified key */
266238384Sjkimvoid gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock)
267238384Sjkim	{
268238384Sjkim	gost_key(c,key);
269238384Sjkim	gostcrypt(c,inblock,outblock);
270238384Sjkim	}
271238384Sjkim
272238384Sjkim/* Set 256 bit  key into context */
273238384Sjkimvoid gost_key(gost_ctx *c, const byte *k)
274238384Sjkim	{
275238384Sjkim	int i,j;
276238384Sjkim	for(i=0,j=0;i<8;i++,j+=4)
277238384Sjkim		{
278238384Sjkim		c->k[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|(k[j+3]<<24);
279238384Sjkim		}
280238384Sjkim	}
281238384Sjkim
282238384Sjkim/* Retrieve 256-bit key from context */
283238384Sjkimvoid gost_get_key(gost_ctx *c, byte *k)
284238384Sjkim	{
285238384Sjkim	int i,j;
286238384Sjkim	for(i=0,j=0;i<8;i++,j+=4)
287238384Sjkim		{
288238384Sjkim		k[j]=(byte)(c->k[i]& 0xFF);
289238384Sjkim		k[j+1]=(byte)((c->k[i]>>8 )&0xFF);
290238384Sjkim		k[j+2]=(byte)((c->k[i]>>16) &0xFF);
291238384Sjkim		k[j+3]=(byte)((c->k[i]>>24) &0xFF);
292238384Sjkim		}
293238384Sjkim	}
294238384Sjkim
295238384Sjkim/* Initalize context. Provides default value for subst_block */
296238384Sjkimvoid gost_init(gost_ctx *c, const gost_subst_block *b)
297238384Sjkim	{
298238384Sjkim	if(!b)
299238384Sjkim		{
300238384Sjkim		b=&GostR3411_94_TestParamSet;
301238384Sjkim		}
302238384Sjkim	kboxinit(c,b);
303238384Sjkim	}
304238384Sjkim
305238384Sjkim/* Cleans up key from context */
306238384Sjkimvoid gost_destroy(gost_ctx *c)
307238384Sjkim	{
308238384Sjkim	int i; for(i=0;i<8;i++) c->k[i]=0;
309238384Sjkim	}
310238384Sjkim
311238384Sjkim/* Compute GOST 28147 mac block
312238384Sjkim *
313238384Sjkim * Parameters
314238384Sjkim *   gost_ctx *c - context initalized with substitution blocks and key
315238384Sjkim *   buffer - 8-byte mac state buffer
316238384Sjkim *   block 8-byte block to process.
317238384Sjkim * */
318238384Sjkimvoid mac_block(gost_ctx *c,byte *buffer,const  byte *block)
319238384Sjkim	{
320238384Sjkim	register word32 n1, n2; /* As named in the GOST */
321238384Sjkim	int i;
322238384Sjkim	for (i=0; i<8; i++)
323238384Sjkim		{
324238384Sjkim		buffer[i]^=block[i];
325238384Sjkim		}
326238384Sjkim	n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|(buffer[3]<<24);
327238384Sjkim	n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
328238384Sjkim	/* Instead of swapping halves, swap names each round */
329238384Sjkim
330238384Sjkim	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
331238384Sjkim	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
332238384Sjkim	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
333238384Sjkim	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
334238384Sjkim
335238384Sjkim	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
336238384Sjkim	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
337238384Sjkim	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
338238384Sjkim	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
339238384Sjkim
340238384Sjkim	buffer[0] = (byte)(n1&0xff);  buffer[1] = (byte)((n1>>8)&0xff);
341238384Sjkim	buffer[2] = (byte)((n1>>16)&0xff); buffer[3] = (byte)(n1>>24);
342238384Sjkim	buffer[4] = (byte)(n2&0xff);  buffer[5] = (byte)((n2>>8)&0xff);
343238384Sjkim	buffer[6] = (byte)((n2>>16)&0xff); buffer[7] = (byte)(n2>>24);
344238384Sjkim	}
345238384Sjkim
346238384Sjkim/* Get mac with specified number of bits from MAC state buffer */
347238384Sjkimvoid get_mac(byte *buffer,int nbits,byte *out)
348238384Sjkim	{
349238384Sjkim	int nbytes= nbits >> 3;
350238384Sjkim	int rembits = nbits & 7;
351238384Sjkim	int mask =rembits?((1<rembits)-1):0;
352238384Sjkim	int i;
353238384Sjkim	for (i=0;i<nbytes;i++) out[i]=buffer[i];
354238384Sjkim	if (rembits) out[i]=buffer[i]&mask;
355238384Sjkim	}
356238384Sjkim
357238384Sjkim/* Compute mac of specified length (in bits) from data.
358238384Sjkim * Context should be initialized with key and subst blocks */
359238384Sjkimint gost_mac(gost_ctx *ctx,int mac_len,const unsigned char *data,
360238384Sjkim	unsigned int data_len,unsigned char *mac)
361238384Sjkim	{
362238384Sjkim	byte buffer[8]={0,0,0,0,0,0,0,0};
363238384Sjkim	byte buf2[8];
364238384Sjkim	unsigned int i;
365238384Sjkim	for (i=0;i+8<=data_len;i+=8)
366238384Sjkim		mac_block(ctx,buffer,data+i);
367238384Sjkim	if (i<data_len)
368238384Sjkim		{
369238384Sjkim		memset(buf2,0,8);
370238384Sjkim		memcpy(buf2,data+i,data_len-i);
371238384Sjkim		mac_block(ctx,buffer,buf2);
372246772Sjkim		i+=8;
373246772Sjkim		}
374246772Sjkim	if (i==8)
375246772Sjkim		{
376246772Sjkim		memset(buf2,0,8);
377246772Sjkim		mac_block(ctx,buffer,buf2);
378246772Sjkim		}
379238384Sjkim	get_mac(buffer,mac_len,mac);
380238384Sjkim	return 1;
381238384Sjkim	}
382238384Sjkim
383238384Sjkim/* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
384238384Sjkimint gost_mac_iv(gost_ctx *ctx,int mac_len,const unsigned char *iv,const unsigned char *data,
385238384Sjkim	unsigned int data_len,unsigned char *mac)
386238384Sjkim	{
387238384Sjkim	byte buffer[8];
388238384Sjkim	byte buf2[8];
389238384Sjkim	unsigned int i;
390238384Sjkim	memcpy (buffer,iv,8);
391238384Sjkim	for (i=0;i+8<=data_len;i+=8)
392238384Sjkim		mac_block(ctx,buffer,data+i);
393238384Sjkim	if (i<data_len)
394238384Sjkim		{
395238384Sjkim		memset(buf2,0,8);
396238384Sjkim		memcpy(buf2,data+i,data_len-i);
397238384Sjkim		mac_block(ctx,buffer,buf2);
398246772Sjkim		i+=8;
399238384Sjkim		}
400246772Sjkim	if (i==8)
401246772Sjkim		{
402246772Sjkim		memset(buf2,0,8);
403246772Sjkim		mac_block(ctx,buffer,buf2);
404246772Sjkim		}
405238384Sjkim	get_mac(buffer,mac_len,mac);
406238384Sjkim	return 1;
407238384Sjkim	}
408238384Sjkim
409238384Sjkim/* Implements key meshing algorithm by modifing ctx and IV in place */
410238384Sjkimvoid cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv)
411238384Sjkim	{
412238384Sjkim	unsigned char newkey[32],newiv[8];
413238384Sjkim	/* Set static keymeshing key */
414238384Sjkim	/* "Decrypt" key with keymeshing key */
415238384Sjkim	gost_dec(ctx,CryptoProKeyMeshingKey,newkey,4);
416238384Sjkim	/* set new key */
417238384Sjkim	gost_key(ctx,newkey);
418238384Sjkim	/* Encrypt iv with new key */
419238384Sjkim	gostcrypt(ctx,iv,newiv);
420238384Sjkim	memcpy(iv,newiv,8);
421238384Sjkim	}
422