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                             *
9280304Sjkim **********************************************************************/
10238384Sjkim#include <string.h>
11238384Sjkim#include "gost89.h"
12280304Sjkim/*-
13280304Sjkim   Substitution blocks from RFC 4357
14280304Sjkim
15280304Sjkim   Note: our implementation of gost 28147-89 algorithm
16280304Sjkim   uses S-box matrix rotated 90 degrees counterclockwise, relative to
17238384Sjkim   examples given in RFC.
18238384Sjkim
19280304Sjkim
20238384Sjkim*/
21238384Sjkim
22238384Sjkim/* Substitution blocks from test examples for GOST R 34.11-94*/
23238384Sjkimgost_subst_block GostR3411_94_TestParamSet = {
24280304Sjkim    {0X1, 0XF, 0XD, 0X0, 0X5, 0X7, 0XA, 0X4, 0X9, 0X2, 0X3, 0XE, 0X6, 0XB,
25280304Sjkim     0X8, 0XC}
26280304Sjkim    ,
27280304Sjkim    {0XD, 0XB, 0X4, 0X1, 0X3, 0XF, 0X5, 0X9, 0X0, 0XA, 0XE, 0X7, 0X6, 0X8,
28280304Sjkim     0X2, 0XC}
29280304Sjkim    ,
30280304Sjkim    {0X4, 0XB, 0XA, 0X0, 0X7, 0X2, 0X1, 0XD, 0X3, 0X6, 0X8, 0X5, 0X9, 0XC,
31280304Sjkim     0XF, 0XE}
32280304Sjkim    ,
33280304Sjkim    {0X6, 0XC, 0X7, 0X1, 0X5, 0XF, 0XD, 0X8, 0X4, 0XA, 0X9, 0XE, 0X0, 0X3,
34280304Sjkim     0XB, 0X2}
35280304Sjkim    ,
36280304Sjkim    {0X7, 0XD, 0XA, 0X1, 0X0, 0X8, 0X9, 0XF, 0XE, 0X4, 0X6, 0XC, 0XB, 0X2,
37280304Sjkim     0X5, 0X3}
38280304Sjkim    ,
39280304Sjkim    {0X5, 0X8, 0X1, 0XD, 0XA, 0X3, 0X4, 0X2, 0XE, 0XF, 0XC, 0X7, 0X6, 0X0,
40280304Sjkim     0X9, 0XB}
41280304Sjkim    ,
42280304Sjkim    {0XE, 0XB, 0X4, 0XC, 0X6, 0XD, 0XF, 0XA, 0X2, 0X3, 0X8, 0X1, 0X0, 0X7,
43280304Sjkim     0X5, 0X9}
44280304Sjkim    ,
45280304Sjkim    {0X4, 0XA, 0X9, 0X2, 0XD, 0X8, 0X0, 0XE, 0X6, 0XB, 0X1, 0XC, 0X7, 0XF,
46280304Sjkim     0X5, 0X3}
47280304Sjkim};
48280304Sjkim
49238384Sjkim/* Substitution blocks for hash function 1.2.643.2.9.1.6.1  */
50280304Sjkimgost_subst_block GostR3411_94_CryptoProParamSet = {
51280304Sjkim    {0x1, 0x3, 0xA, 0x9, 0x5, 0xB, 0x4, 0xF, 0x8, 0x6, 0x7, 0xE, 0xD, 0x0,
52280304Sjkim     0x2, 0xC}
53280304Sjkim    ,
54280304Sjkim    {0xD, 0xE, 0x4, 0x1, 0x7, 0x0, 0x5, 0xA, 0x3, 0xC, 0x8, 0xF, 0x6, 0x2,
55280304Sjkim     0x9, 0xB}
56280304Sjkim    ,
57280304Sjkim    {0x7, 0x6, 0x2, 0x4, 0xD, 0x9, 0xF, 0x0, 0xA, 0x1, 0x5, 0xB, 0x8, 0xE,
58280304Sjkim     0xC, 0x3}
59280304Sjkim    ,
60280304Sjkim    {0x7, 0x6, 0x4, 0xB, 0x9, 0xC, 0x2, 0xA, 0x1, 0x8, 0x0, 0xE, 0xF, 0xD,
61280304Sjkim     0x3, 0x5}
62280304Sjkim    ,
63280304Sjkim    {0x4, 0xA, 0x7, 0xC, 0x0, 0xF, 0x2, 0x8, 0xE, 0x1, 0x6, 0x5, 0xD, 0xB,
64280304Sjkim     0x9, 0x3}
65280304Sjkim    ,
66280304Sjkim    {0x7, 0xF, 0xC, 0xE, 0x9, 0x4, 0x1, 0x0, 0x3, 0xB, 0x5, 0x2, 0x6, 0xA,
67280304Sjkim     0x8, 0xD}
68280304Sjkim    ,
69280304Sjkim    {0x5, 0xF, 0x4, 0x0, 0x2, 0xD, 0xB, 0x9, 0x1, 0x7, 0x6, 0x3, 0xC, 0xE,
70280304Sjkim     0xA, 0x8}
71280304Sjkim    ,
72280304Sjkim    {0xA, 0x4, 0x5, 0x6, 0x8, 0x1, 0x3, 0x7, 0xD, 0xC, 0xE, 0x0, 0x9, 0x2,
73280304Sjkim     0xB, 0xF}
74280304Sjkim};
75238384Sjkim
76238384Sjkim/* Test paramset from GOST 28147 */
77280304Sjkimgost_subst_block Gost28147_TestParamSet = {
78280304Sjkim    {0xC, 0x6, 0x5, 0x2, 0xB, 0x0, 0x9, 0xD, 0x3, 0xE, 0x7, 0xA, 0xF, 0x4,
79280304Sjkim     0x1, 0x8}
80280304Sjkim    ,
81280304Sjkim    {0x9, 0xB, 0xC, 0x0, 0x3, 0x6, 0x7, 0x5, 0x4, 0x8, 0xE, 0xF, 0x1, 0xA,
82280304Sjkim     0x2, 0xD}
83280304Sjkim    ,
84280304Sjkim    {0x8, 0xF, 0x6, 0xB, 0x1, 0x9, 0xC, 0x5, 0xD, 0x3, 0x7, 0xA, 0x0, 0xE,
85280304Sjkim     0x2, 0x4}
86280304Sjkim    ,
87280304Sjkim    {0x3, 0xE, 0x5, 0x9, 0x6, 0x8, 0x0, 0xD, 0xA, 0xB, 0x7, 0xC, 0x2, 0x1,
88280304Sjkim     0xF, 0x4}
89280304Sjkim    ,
90280304Sjkim    {0xE, 0x9, 0xB, 0x2, 0x5, 0xF, 0x7, 0x1, 0x0, 0xD, 0xC, 0x6, 0xA, 0x4,
91280304Sjkim     0x3, 0x8}
92280304Sjkim    ,
93280304Sjkim    {0xD, 0x8, 0xE, 0xC, 0x7, 0x3, 0x9, 0xA, 0x1, 0x5, 0x2, 0x4, 0x6, 0xF,
94280304Sjkim     0x0, 0xB}
95280304Sjkim    ,
96280304Sjkim    {0xC, 0x9, 0xF, 0xE, 0x8, 0x1, 0x3, 0xA, 0x2, 0x7, 0x4, 0xD, 0x6, 0x0,
97280304Sjkim     0xB, 0x5}
98280304Sjkim    ,
99280304Sjkim    {0x4, 0x2, 0xF, 0x5, 0x9, 0x1, 0x0, 0x8, 0xE, 0x3, 0xB, 0xC, 0xD, 0x7,
100280304Sjkim     0xA, 0x6}
101280304Sjkim};
102238384Sjkim
103280304Sjkim/* 1.2.643.2.2.31.1 */
104280304Sjkimgost_subst_block Gost28147_CryptoProParamSetA = {
105280304Sjkim    {0xB, 0xA, 0xF, 0x5, 0x0, 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7,
106280304Sjkim     0xD, 0x4}
107280304Sjkim    ,
108280304Sjkim    {0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8, 0xC, 0x4, 0x5, 0xF, 0x3,
109280304Sjkim     0xB, 0xE}
110280304Sjkim    ,
111280304Sjkim    {0x3, 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8, 0xF,
112280304Sjkim     0xE, 0x6}
113280304Sjkim    ,
114280304Sjkim    {0xB, 0x5, 0x1, 0x9, 0x8, 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7,
115280304Sjkim     0xA, 0x6}
116280304Sjkim    ,
117280304Sjkim    {0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0, 0x2, 0xB, 0x4, 0xF, 0x8,
118280304Sjkim     0x5, 0x6}
119280304Sjkim    ,
120280304Sjkim    {0xE, 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0, 0x7,
121280304Sjkim     0x1, 0x9}
122280304Sjkim    ,
123280304Sjkim    {0x3, 0x7, 0xE, 0x9, 0x8, 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4,
124280304Sjkim     0xD, 0x1}
125280304Sjkim    ,
126280304Sjkim    {0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA, 0x4, 0xE, 0xF, 0xC, 0x0,
127280304Sjkim     0xD, 0x5}
128280304Sjkim};
129238384Sjkim
130280304Sjkim/* 1.2.643.2.2.31.2 */
131280304Sjkimgost_subst_block Gost28147_CryptoProParamSetB = {
132280304Sjkim    {0x0, 0x4, 0xB, 0xE, 0x8, 0x3, 0x7, 0x1, 0xA, 0x2, 0x9, 0x6, 0xF, 0xD,
133280304Sjkim     0x5, 0xC}
134280304Sjkim    ,
135280304Sjkim    {0x5, 0x2, 0xA, 0xB, 0x9, 0x1, 0xC, 0x3, 0x7, 0x4, 0xD, 0x0, 0x6, 0xF,
136280304Sjkim     0x8, 0xE}
137280304Sjkim    ,
138280304Sjkim    {0x8, 0x3, 0x2, 0x6, 0x4, 0xD, 0xE, 0xB, 0xC, 0x1, 0x7, 0xF, 0xA, 0x0,
139280304Sjkim     0x9, 0x5}
140280304Sjkim    ,
141280304Sjkim    {0x2, 0x7, 0xC, 0xF, 0x9, 0x5, 0xA, 0xB, 0x1, 0x4, 0x0, 0xD, 0x6, 0x8,
142280304Sjkim     0xE, 0x3}
143280304Sjkim    ,
144280304Sjkim    {0x7, 0x5, 0x0, 0xD, 0xB, 0x6, 0x1, 0x2, 0x3, 0xA, 0xC, 0xF, 0x4, 0xE,
145280304Sjkim     0x9, 0x8}
146280304Sjkim    ,
147280304Sjkim    {0xE, 0xC, 0x0, 0xA, 0x9, 0x2, 0xD, 0xB, 0x7, 0x5, 0x8, 0xF, 0x3, 0x6,
148280304Sjkim     0x1, 0x4}
149280304Sjkim    ,
150280304Sjkim    {0x0, 0x1, 0x2, 0xA, 0x4, 0xD, 0x5, 0xC, 0x9, 0x7, 0x3, 0xF, 0xB, 0x8,
151280304Sjkim     0x6, 0xE}
152280304Sjkim    ,
153280304Sjkim    {0x8, 0x4, 0xB, 0x1, 0x3, 0x5, 0x0, 0x9, 0x2, 0xE, 0xA, 0xC, 0xD, 0x6,
154280304Sjkim     0x7, 0xF}
155280304Sjkim};
156238384Sjkim
157238384Sjkim/* 1.2.643.2.2.31.3 */
158280304Sjkimgost_subst_block Gost28147_CryptoProParamSetC = {
159280304Sjkim    {0x7, 0x4, 0x0, 0x5, 0xA, 0x2, 0xF, 0xE, 0xC, 0x6, 0x1, 0xB, 0xD, 0x9,
160280304Sjkim     0x3, 0x8}
161280304Sjkim    ,
162280304Sjkim    {0xA, 0x9, 0x6, 0x8, 0xD, 0xE, 0x2, 0x0, 0xF, 0x3, 0x5, 0xB, 0x4, 0x1,
163280304Sjkim     0xC, 0x7}
164280304Sjkim    ,
165280304Sjkim    {0xC, 0x9, 0xB, 0x1, 0x8, 0xE, 0x2, 0x4, 0x7, 0x3, 0x6, 0x5, 0xA, 0x0,
166280304Sjkim     0xF, 0xD}
167280304Sjkim    ,
168280304Sjkim    {0x8, 0xD, 0xB, 0x0, 0x4, 0x5, 0x1, 0x2, 0x9, 0x3, 0xC, 0xE, 0x6, 0xF,
169280304Sjkim     0xA, 0x7}
170280304Sjkim    ,
171280304Sjkim    {0x3, 0x6, 0x0, 0x1, 0x5, 0xD, 0xA, 0x8, 0xB, 0x2, 0x9, 0x7, 0xE, 0xF,
172280304Sjkim     0xC, 0x4}
173280304Sjkim    ,
174280304Sjkim    {0x8, 0x2, 0x5, 0x0, 0x4, 0x9, 0xF, 0xA, 0x3, 0x7, 0xC, 0xD, 0x6, 0xE,
175280304Sjkim     0x1, 0xB}
176280304Sjkim    ,
177280304Sjkim    {0x0, 0x1, 0x7, 0xD, 0xB, 0x4, 0x5, 0x2, 0x8, 0xE, 0xF, 0xC, 0x9, 0xA,
178280304Sjkim     0x6, 0x3}
179280304Sjkim    ,
180280304Sjkim    {0x1, 0xB, 0xC, 0x2, 0x9, 0xD, 0x0, 0xF, 0x4, 0x5, 0x8, 0xE, 0xA, 0x7,
181280304Sjkim     0x6, 0x3}
182280304Sjkim};
183238384Sjkim
184280304Sjkim/* 1.2.643.2.2.31.4 */
185280304Sjkimgost_subst_block Gost28147_CryptoProParamSetD = {
186280304Sjkim    {0x1, 0xA, 0x6, 0x8, 0xF, 0xB, 0x0, 0x4, 0xC, 0x3, 0x5, 0x9, 0x7, 0xD,
187280304Sjkim     0x2, 0xE}
188280304Sjkim    ,
189280304Sjkim    {0x3, 0x0, 0x6, 0xF, 0x1, 0xE, 0x9, 0x2, 0xD, 0x8, 0xC, 0x4, 0xB, 0xA,
190280304Sjkim     0x5, 0x7}
191280304Sjkim    ,
192280304Sjkim    {0x8, 0x0, 0xF, 0x3, 0x2, 0x5, 0xE, 0xB, 0x1, 0xA, 0x4, 0x7, 0xC, 0x9,
193280304Sjkim     0xD, 0x6}
194280304Sjkim    ,
195280304Sjkim    {0x0, 0xC, 0x8, 0x9, 0xD, 0x2, 0xA, 0xB, 0x7, 0x3, 0x6, 0x5, 0x4, 0xE,
196280304Sjkim     0xF, 0x1}
197280304Sjkim    ,
198280304Sjkim    {0x1, 0x5, 0xE, 0xC, 0xA, 0x7, 0x0, 0xD, 0x6, 0x2, 0xB, 0x4, 0x9, 0x3,
199280304Sjkim     0xF, 0x8}
200280304Sjkim    ,
201280304Sjkim    {0x1, 0xC, 0xB, 0x0, 0xF, 0xE, 0x6, 0x5, 0xA, 0xD, 0x4, 0x8, 0x9, 0x3,
202280304Sjkim     0x7, 0x2}
203280304Sjkim    ,
204280304Sjkim    {0xB, 0x6, 0x3, 0x4, 0xC, 0xF, 0xE, 0x2, 0x7, 0xD, 0x8, 0x0, 0x5, 0xA,
205280304Sjkim     0x9, 0x1}
206280304Sjkim    ,
207280304Sjkim    {0xF, 0xC, 0x2, 0xA, 0x6, 0x4, 0x5, 0x0, 0x7, 0x9, 0xE, 0xD, 0x1, 0xB,
208280304Sjkim     0x8, 0x3}
209280304Sjkim};
210238384Sjkim
211280304Sjkimconst byte CryptoProKeyMeshingKey[] = {
212280304Sjkim    0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23,
213280304Sjkim    0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4,
214280304Sjkim    0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12,
215280304Sjkim    0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B
216280304Sjkim};
217238384Sjkim
218238384Sjkim/* Initialization of gost_ctx subst blocks*/
219280304Sjkimstatic void kboxinit(gost_ctx * c, const gost_subst_block * b)
220280304Sjkim{
221280304Sjkim    int i;
222238384Sjkim
223280304Sjkim    for (i = 0; i < 256; i++) {
224280304Sjkim        c->k87[i] = (b->k8[i >> 4] << 4 | b->k7[i & 15]) << 24;
225280304Sjkim        c->k65[i] = (b->k6[i >> 4] << 4 | b->k5[i & 15]) << 16;
226280304Sjkim        c->k43[i] = (b->k4[i >> 4] << 4 | b->k3[i & 15]) << 8;
227280304Sjkim        c->k21[i] = b->k2[i >> 4] << 4 | b->k1[i & 15];
228238384Sjkim
229280304Sjkim    }
230280304Sjkim}
231280304Sjkim
232238384Sjkim/* Part of GOST 28147 algorithm moved into separate function */
233280304Sjkimstatic word32 f(gost_ctx * c, word32 x)
234280304Sjkim{
235280304Sjkim    x = c->k87[x >> 24 & 255] | c->k65[x >> 16 & 255] |
236280304Sjkim        c->k43[x >> 8 & 255] | c->k21[x & 255];
237280304Sjkim    /* Rotate left 11 bits */
238280304Sjkim    return x << 11 | x >> (32 - 11);
239280304Sjkim}
240280304Sjkim
241238384Sjkim/* Low-level encryption routine - encrypts one 64 bit block*/
242280304Sjkimvoid gostcrypt(gost_ctx * c, const byte * in, byte * out)
243280304Sjkim{
244280304Sjkim    register word32 n1, n2;     /* As named in the GOST */
245280304Sjkim    n1 = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24);
246280304Sjkim    n2 = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24);
247280304Sjkim    /* Instead of swapping halves, swap names each round */
248280304Sjkim
249280304Sjkim    n2 ^= f(c, n1 + c->k[0]);
250280304Sjkim    n1 ^= f(c, n2 + c->k[1]);
251280304Sjkim    n2 ^= f(c, n1 + c->k[2]);
252280304Sjkim    n1 ^= f(c, n2 + c->k[3]);
253280304Sjkim    n2 ^= f(c, n1 + c->k[4]);
254280304Sjkim    n1 ^= f(c, n2 + c->k[5]);
255280304Sjkim    n2 ^= f(c, n1 + c->k[6]);
256280304Sjkim    n1 ^= f(c, n2 + c->k[7]);
257280304Sjkim
258280304Sjkim    n2 ^= f(c, n1 + c->k[0]);
259280304Sjkim    n1 ^= f(c, n2 + c->k[1]);
260280304Sjkim    n2 ^= f(c, n1 + c->k[2]);
261280304Sjkim    n1 ^= f(c, n2 + c->k[3]);
262280304Sjkim    n2 ^= f(c, n1 + c->k[4]);
263280304Sjkim    n1 ^= f(c, n2 + c->k[5]);
264280304Sjkim    n2 ^= f(c, n1 + c->k[6]);
265280304Sjkim    n1 ^= f(c, n2 + c->k[7]);
266280304Sjkim
267280304Sjkim    n2 ^= f(c, n1 + c->k[0]);
268280304Sjkim    n1 ^= f(c, n2 + c->k[1]);
269280304Sjkim    n2 ^= f(c, n1 + c->k[2]);
270280304Sjkim    n1 ^= f(c, n2 + c->k[3]);
271280304Sjkim    n2 ^= f(c, n1 + c->k[4]);
272280304Sjkim    n1 ^= f(c, n2 + c->k[5]);
273280304Sjkim    n2 ^= f(c, n1 + c->k[6]);
274280304Sjkim    n1 ^= f(c, n2 + c->k[7]);
275280304Sjkim
276280304Sjkim    n2 ^= f(c, n1 + c->k[7]);
277280304Sjkim    n1 ^= f(c, n2 + c->k[6]);
278280304Sjkim    n2 ^= f(c, n1 + c->k[5]);
279280304Sjkim    n1 ^= f(c, n2 + c->k[4]);
280280304Sjkim    n2 ^= f(c, n1 + c->k[3]);
281280304Sjkim    n1 ^= f(c, n2 + c->k[2]);
282280304Sjkim    n2 ^= f(c, n1 + c->k[1]);
283280304Sjkim    n1 ^= f(c, n2 + c->k[0]);
284280304Sjkim
285280304Sjkim    out[0] = (byte) (n2 & 0xff);
286280304Sjkim    out[1] = (byte) ((n2 >> 8) & 0xff);
287280304Sjkim    out[2] = (byte) ((n2 >> 16) & 0xff);
288280304Sjkim    out[3] = (byte) (n2 >> 24);
289280304Sjkim    out[4] = (byte) (n1 & 0xff);
290280304Sjkim    out[5] = (byte) ((n1 >> 8) & 0xff);
291280304Sjkim    out[6] = (byte) ((n1 >> 16) & 0xff);
292280304Sjkim    out[7] = (byte) (n1 >> 24);
293280304Sjkim}
294280304Sjkim
295238384Sjkim/* Low-level decryption routine. Decrypts one 64-bit block */
296280304Sjkimvoid gostdecrypt(gost_ctx * c, const byte * in, byte * out)
297280304Sjkim{
298280304Sjkim    register word32 n1, n2;     /* As named in the GOST */
299280304Sjkim    n1 = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24);
300280304Sjkim    n2 = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24);
301238384Sjkim
302280304Sjkim    n2 ^= f(c, n1 + c->k[0]);
303280304Sjkim    n1 ^= f(c, n2 + c->k[1]);
304280304Sjkim    n2 ^= f(c, n1 + c->k[2]);
305280304Sjkim    n1 ^= f(c, n2 + c->k[3]);
306280304Sjkim    n2 ^= f(c, n1 + c->k[4]);
307280304Sjkim    n1 ^= f(c, n2 + c->k[5]);
308280304Sjkim    n2 ^= f(c, n1 + c->k[6]);
309280304Sjkim    n1 ^= f(c, n2 + c->k[7]);
310238384Sjkim
311280304Sjkim    n2 ^= f(c, n1 + c->k[7]);
312280304Sjkim    n1 ^= f(c, n2 + c->k[6]);
313280304Sjkim    n2 ^= f(c, n1 + c->k[5]);
314280304Sjkim    n1 ^= f(c, n2 + c->k[4]);
315280304Sjkim    n2 ^= f(c, n1 + c->k[3]);
316280304Sjkim    n1 ^= f(c, n2 + c->k[2]);
317280304Sjkim    n2 ^= f(c, n1 + c->k[1]);
318280304Sjkim    n1 ^= f(c, n2 + c->k[0]);
319280304Sjkim
320280304Sjkim    n2 ^= f(c, n1 + c->k[7]);
321280304Sjkim    n1 ^= f(c, n2 + c->k[6]);
322280304Sjkim    n2 ^= f(c, n1 + c->k[5]);
323280304Sjkim    n1 ^= f(c, n2 + c->k[4]);
324280304Sjkim    n2 ^= f(c, n1 + c->k[3]);
325280304Sjkim    n1 ^= f(c, n2 + c->k[2]);
326280304Sjkim    n2 ^= f(c, n1 + c->k[1]);
327280304Sjkim    n1 ^= f(c, n2 + c->k[0]);
328280304Sjkim
329280304Sjkim    n2 ^= f(c, n1 + c->k[7]);
330280304Sjkim    n1 ^= f(c, n2 + c->k[6]);
331280304Sjkim    n2 ^= f(c, n1 + c->k[5]);
332280304Sjkim    n1 ^= f(c, n2 + c->k[4]);
333280304Sjkim    n2 ^= f(c, n1 + c->k[3]);
334280304Sjkim    n1 ^= f(c, n2 + c->k[2]);
335280304Sjkim    n2 ^= f(c, n1 + c->k[1]);
336280304Sjkim    n1 ^= f(c, n2 + c->k[0]);
337280304Sjkim
338280304Sjkim    out[0] = (byte) (n2 & 0xff);
339280304Sjkim    out[1] = (byte) ((n2 >> 8) & 0xff);
340280304Sjkim    out[2] = (byte) ((n2 >> 16) & 0xff);
341280304Sjkim    out[3] = (byte) (n2 >> 24);
342280304Sjkim    out[4] = (byte) (n1 & 0xff);
343280304Sjkim    out[5] = (byte) ((n1 >> 8) & 0xff);
344280304Sjkim    out[6] = (byte) ((n1 >> 16) & 0xff);
345280304Sjkim    out[7] = (byte) (n1 >> 24);
346280304Sjkim}
347280304Sjkim
348238384Sjkim/* Encrypts several blocks in ECB mode */
349280304Sjkimvoid gost_enc(gost_ctx * c, const byte * clear, byte * cipher, int blocks)
350280304Sjkim{
351280304Sjkim    int i;
352280304Sjkim    for (i = 0; i < blocks; i++) {
353280304Sjkim        gostcrypt(c, clear, cipher);
354280304Sjkim        clear += 8;
355280304Sjkim        cipher += 8;
356280304Sjkim    }
357280304Sjkim}
358280304Sjkim
359238384Sjkim/* Decrypts several blocks in ECB mode */
360280304Sjkimvoid gost_dec(gost_ctx * c, const byte * cipher, byte * clear, int blocks)
361280304Sjkim{
362280304Sjkim    int i;
363280304Sjkim    for (i = 0; i < blocks; i++) {
364280304Sjkim        gostdecrypt(c, cipher, clear);
365280304Sjkim        clear += 8;
366280304Sjkim        cipher += 8;
367280304Sjkim    }
368280304Sjkim}
369238384Sjkim
370238384Sjkim/* Encrypts several full blocks in CFB mode using 8byte IV */
371280304Sjkimvoid gost_enc_cfb(gost_ctx * ctx, const byte * iv, const byte * clear,
372280304Sjkim                  byte * cipher, int blocks)
373280304Sjkim{
374280304Sjkim    byte cur_iv[8];
375280304Sjkim    byte gamma[8];
376280304Sjkim    int i, j;
377280304Sjkim    const byte *in;
378280304Sjkim    byte *out;
379280304Sjkim    memcpy(cur_iv, iv, 8);
380280304Sjkim    for (i = 0, in = clear, out = cipher; i < blocks; i++, in += 8, out += 8) {
381280304Sjkim        gostcrypt(ctx, cur_iv, gamma);
382280304Sjkim        for (j = 0; j < 8; j++) {
383280304Sjkim            cur_iv[j] = out[j] = in[j] ^ gamma[j];
384280304Sjkim        }
385280304Sjkim    }
386280304Sjkim}
387280304Sjkim
388238384Sjkim/* Decrypts several full blocks in CFB mode using 8byte IV */
389280304Sjkimvoid gost_dec_cfb(gost_ctx * ctx, const byte * iv, const byte * cipher,
390280304Sjkim                  byte * clear, int blocks)
391280304Sjkim{
392280304Sjkim    byte cur_iv[8];
393280304Sjkim    byte gamma[8];
394280304Sjkim    int i, j;
395280304Sjkim    const byte *in;
396280304Sjkim    byte *out;
397280304Sjkim    memcpy(cur_iv, iv, 8);
398280304Sjkim    for (i = 0, in = cipher, out = clear; i < blocks; i++, in += 8, out += 8) {
399280304Sjkim        gostcrypt(ctx, cur_iv, gamma);
400280304Sjkim        for (j = 0; j < 8; j++) {
401280304Sjkim            out[j] = (cur_iv[j] = in[j]) ^ gamma[j];
402280304Sjkim        }
403280304Sjkim    }
404280304Sjkim}
405238384Sjkim
406238384Sjkim/* Encrypts one block using specified key */
407280304Sjkimvoid gost_enc_with_key(gost_ctx * c, byte * key, byte * inblock,
408280304Sjkim                       byte * outblock)
409280304Sjkim{
410280304Sjkim    gost_key(c, key);
411280304Sjkim    gostcrypt(c, inblock, outblock);
412280304Sjkim}
413238384Sjkim
414238384Sjkim/* Set 256 bit  key into context */
415280304Sjkimvoid gost_key(gost_ctx * c, const byte * k)
416280304Sjkim{
417280304Sjkim    int i, j;
418280304Sjkim    for (i = 0, j = 0; i < 8; i++, j += 4) {
419280304Sjkim        c->k[i] =
420280304Sjkim            k[j] | (k[j + 1] << 8) | (k[j + 2] << 16) | (k[j + 3] << 24);
421280304Sjkim    }
422280304Sjkim}
423238384Sjkim
424238384Sjkim/* Retrieve 256-bit key from context */
425280304Sjkimvoid gost_get_key(gost_ctx * c, byte * k)
426280304Sjkim{
427280304Sjkim    int i, j;
428280304Sjkim    for (i = 0, j = 0; i < 8; i++, j += 4) {
429280304Sjkim        k[j] = (byte) (c->k[i] & 0xFF);
430280304Sjkim        k[j + 1] = (byte) ((c->k[i] >> 8) & 0xFF);
431280304Sjkim        k[j + 2] = (byte) ((c->k[i] >> 16) & 0xFF);
432280304Sjkim        k[j + 3] = (byte) ((c->k[i] >> 24) & 0xFF);
433280304Sjkim    }
434280304Sjkim}
435238384Sjkim
436238384Sjkim/* Initalize context. Provides default value for subst_block */
437280304Sjkimvoid gost_init(gost_ctx * c, const gost_subst_block * b)
438280304Sjkim{
439280304Sjkim    if (!b) {
440280304Sjkim        b = &GostR3411_94_TestParamSet;
441280304Sjkim    }
442280304Sjkim    kboxinit(c, b);
443280304Sjkim}
444238384Sjkim
445238384Sjkim/* Cleans up key from context */
446280304Sjkimvoid gost_destroy(gost_ctx * c)
447280304Sjkim{
448280304Sjkim    int i;
449280304Sjkim    for (i = 0; i < 8; i++)
450280304Sjkim        c->k[i] = 0;
451280304Sjkim}
452238384Sjkim
453280304Sjkim/*
454280304Sjkim * Compute GOST 28147 mac block Parameters gost_ctx *c - context initalized
455280304Sjkim * with substitution blocks and key buffer - 8-byte mac state buffer block
456280304Sjkim * 8-byte block to process.
457280304Sjkim */
458280304Sjkimvoid mac_block(gost_ctx * c, byte * buffer, const byte * block)
459280304Sjkim{
460280304Sjkim    register word32 n1, n2;     /* As named in the GOST */
461280304Sjkim    int i;
462280304Sjkim    for (i = 0; i < 8; i++) {
463280304Sjkim        buffer[i] ^= block[i];
464280304Sjkim    }
465280304Sjkim    n1 = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
466280304Sjkim    n2 = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24);
467280304Sjkim    /* Instead of swapping halves, swap names each round */
468238384Sjkim
469280304Sjkim    n2 ^= f(c, n1 + c->k[0]);
470280304Sjkim    n1 ^= f(c, n2 + c->k[1]);
471280304Sjkim    n2 ^= f(c, n1 + c->k[2]);
472280304Sjkim    n1 ^= f(c, n2 + c->k[3]);
473280304Sjkim    n2 ^= f(c, n1 + c->k[4]);
474280304Sjkim    n1 ^= f(c, n2 + c->k[5]);
475280304Sjkim    n2 ^= f(c, n1 + c->k[6]);
476280304Sjkim    n1 ^= f(c, n2 + c->k[7]);
477238384Sjkim
478280304Sjkim    n2 ^= f(c, n1 + c->k[0]);
479280304Sjkim    n1 ^= f(c, n2 + c->k[1]);
480280304Sjkim    n2 ^= f(c, n1 + c->k[2]);
481280304Sjkim    n1 ^= f(c, n2 + c->k[3]);
482280304Sjkim    n2 ^= f(c, n1 + c->k[4]);
483280304Sjkim    n1 ^= f(c, n2 + c->k[5]);
484280304Sjkim    n2 ^= f(c, n1 + c->k[6]);
485280304Sjkim    n1 ^= f(c, n2 + c->k[7]);
486280304Sjkim
487280304Sjkim    buffer[0] = (byte) (n1 & 0xff);
488280304Sjkim    buffer[1] = (byte) ((n1 >> 8) & 0xff);
489280304Sjkim    buffer[2] = (byte) ((n1 >> 16) & 0xff);
490280304Sjkim    buffer[3] = (byte) (n1 >> 24);
491280304Sjkim    buffer[4] = (byte) (n2 & 0xff);
492280304Sjkim    buffer[5] = (byte) ((n2 >> 8) & 0xff);
493280304Sjkim    buffer[6] = (byte) ((n2 >> 16) & 0xff);
494280304Sjkim    buffer[7] = (byte) (n2 >> 24);
495280304Sjkim}
496280304Sjkim
497238384Sjkim/* Get mac with specified number of bits from MAC state buffer */
498280304Sjkimvoid get_mac(byte * buffer, int nbits, byte * out)
499280304Sjkim{
500280304Sjkim    int nbytes = nbits >> 3;
501280304Sjkim    int rembits = nbits & 7;
502280304Sjkim    int mask = rembits ? ((1 < rembits) - 1) : 0;
503280304Sjkim    int i;
504280304Sjkim    for (i = 0; i < nbytes; i++)
505280304Sjkim        out[i] = buffer[i];
506280304Sjkim    if (rembits)
507280304Sjkim        out[i] = buffer[i] & mask;
508280304Sjkim}
509238384Sjkim
510280304Sjkim/*
511280304Sjkim * Compute mac of specified length (in bits) from data. Context should be
512280304Sjkim * initialized with key and subst blocks
513280304Sjkim */
514280304Sjkimint gost_mac(gost_ctx * ctx, int mac_len, const unsigned char *data,
515280304Sjkim             unsigned int data_len, unsigned char *mac)
516280304Sjkim{
517280304Sjkim    byte buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
518280304Sjkim    byte buf2[8];
519280304Sjkim    unsigned int i;
520280304Sjkim    for (i = 0; i + 8 <= data_len; i += 8)
521280304Sjkim        mac_block(ctx, buffer, data + i);
522280304Sjkim    if (i < data_len) {
523280304Sjkim        memset(buf2, 0, 8);
524280304Sjkim        memcpy(buf2, data + i, data_len - i);
525280304Sjkim        mac_block(ctx, buffer, buf2);
526280304Sjkim        i += 8;
527280304Sjkim    }
528280304Sjkim    if (i == 8) {
529280304Sjkim        memset(buf2, 0, 8);
530280304Sjkim        mac_block(ctx, buffer, buf2);
531280304Sjkim    }
532280304Sjkim    get_mac(buffer, mac_len, mac);
533280304Sjkim    return 1;
534280304Sjkim}
535238384Sjkim
536238384Sjkim/* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
537280304Sjkimint gost_mac_iv(gost_ctx * ctx, int mac_len, const unsigned char *iv,
538280304Sjkim                const unsigned char *data, unsigned int data_len,
539280304Sjkim                unsigned char *mac)
540280304Sjkim{
541280304Sjkim    byte buffer[8];
542280304Sjkim    byte buf2[8];
543280304Sjkim    unsigned int i;
544280304Sjkim    memcpy(buffer, iv, 8);
545280304Sjkim    for (i = 0; i + 8 <= data_len; i += 8)
546280304Sjkim        mac_block(ctx, buffer, data + i);
547280304Sjkim    if (i < data_len) {
548280304Sjkim        memset(buf2, 0, 8);
549280304Sjkim        memcpy(buf2, data + i, data_len - i);
550280304Sjkim        mac_block(ctx, buffer, buf2);
551280304Sjkim        i += 8;
552280304Sjkim    }
553280304Sjkim    if (i == 8) {
554280304Sjkim        memset(buf2, 0, 8);
555280304Sjkim        mac_block(ctx, buffer, buf2);
556280304Sjkim    }
557280304Sjkim    get_mac(buffer, mac_len, mac);
558280304Sjkim    return 1;
559280304Sjkim}
560238384Sjkim
561238384Sjkim/* Implements key meshing algorithm by modifing ctx and IV in place */
562280304Sjkimvoid cryptopro_key_meshing(gost_ctx * ctx, unsigned char *iv)
563280304Sjkim{
564280304Sjkim    unsigned char newkey[32], newiv[8];
565280304Sjkim    /* Set static keymeshing key */
566280304Sjkim    /* "Decrypt" key with keymeshing key */
567280304Sjkim    gost_dec(ctx, CryptoProKeyMeshingKey, newkey, 4);
568280304Sjkim    /* set new key */
569280304Sjkim    gost_key(ctx, newkey);
570280304Sjkim    /* Encrypt iv with new key */
571280304Sjkim    gostcrypt(ctx, iv, newiv);
572280304Sjkim    memcpy(iv, newiv, 8);
573280304Sjkim}
574