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,
27 {0XD, 0XB, 0X4, 0X1, 0X3, 0XF, 0X5, 0X9, 0X0, 0XA, 0XE, 0X7, 0X6, 0X8,
30 {0X4, 0XB, 0XA, 0X0, 0X7, 0X2, 0X1, 0XD, 0X3, 0X6, 0X8, 0X5, 0X9, 0XC,
33 {0X6, 0XC, 0X7, 0X1, 0X5, 0XF, 0XD, 0X8, 0X4, 0XA, 0X9, 0XE, 0X0, 0X3,
36 {0X7, 0XD, 0XA, 0X1, 0X0, 0X8, 0X9, 0XF, 0XE, 0X4, 0X6, 0XC, 0XB, 0X2,
39 {0X5, 0X8, 0X1, 0XD, 0XA, 0X3, 0X4, 0X2, 0XE, 0XF, 0XC, 0X7, 0X6, 0X0,
42 {0XE, 0XB, 0X4, 0XC, 0X6, 0XD, 0XF, 0XA, 0X2, 0X3, 0X8, 0X1, 0X0, 0X7,
45 {0X4, 0XA, 0X9, 0X2, 0XD, 0X8, 0X0, 0XE, 0X6, 0XB, 0X1, 0XC, 0X7, 0XF,
49 /* Substitution blocks for hash function 1.2.643.2.9.1.6.1 */
50 gost_subst_block GostR3411_94_CryptoProParamSet = {
51 {0x1, 0x3, 0xA, 0x9, 0x5, 0xB, 0x4, 0xF, 0x8, 0x6, 0x7, 0xE, 0xD, 0x0,
54 {0xD, 0xE, 0x4, 0x1, 0x7, 0x0, 0x5, 0xA, 0x3, 0xC, 0x8, 0xF, 0x6, 0x2,
57 {0x7, 0x6, 0x2, 0x4, 0xD, 0x9, 0xF, 0x0, 0xA, 0x1, 0x5, 0xB, 0x8, 0xE,
60 {0x7, 0x6, 0x4, 0xB, 0x9, 0xC, 0x2, 0xA, 0x1, 0x8, 0x0, 0xE, 0xF, 0xD,
63 {0x4, 0xA, 0x7, 0xC, 0x0, 0xF, 0x2, 0x8, 0xE, 0x1, 0x6, 0x5, 0xD, 0xB,
66 {0x7, 0xF, 0xC, 0xE, 0x9, 0x4, 0x1, 0x0, 0x3, 0xB, 0x5, 0x2, 0x6, 0xA,
69 {0x5, 0xF, 0x4, 0x0, 0x2, 0xD, 0xB, 0x9, 0x1, 0x7, 0x6, 0x3, 0xC, 0xE,
72 {0xA, 0x4, 0x5, 0x6, 0x8, 0x1, 0x3, 0x7, 0xD, 0xC, 0xE, 0x0, 0x9, 0x2,
76 /* Test paramset from GOST 28147 */
77 gost_subst_block Gost28147_TestParamSet = {
78 {0xC, 0x6, 0x5, 0x2, 0xB, 0x0, 0x9, 0xD, 0x3, 0xE, 0x7, 0xA, 0xF, 0x4,
81 {0x9, 0xB, 0xC, 0x0, 0x3, 0x6, 0x7, 0x5, 0x4, 0x8, 0xE, 0xF, 0x1, 0xA,
84 {0x8, 0xF, 0x6, 0xB, 0x1, 0x9, 0xC, 0x5, 0xD, 0x3, 0x7, 0xA, 0x0, 0xE,
87 {0x3, 0xE, 0x5, 0x9, 0x6, 0x8, 0x0, 0xD, 0xA, 0xB, 0x7, 0xC, 0x2, 0x1,
90 {0xE, 0x9, 0xB, 0x2, 0x5, 0xF, 0x7, 0x1, 0x0, 0xD, 0xC, 0x6, 0xA, 0x4,
93 {0xD, 0x8, 0xE, 0xC, 0x7, 0x3, 0x9, 0xA, 0x1, 0x5, 0x2, 0x4, 0x6, 0xF,
96 {0xC, 0x9, 0xF, 0xE, 0x8, 0x1, 0x3, 0xA, 0x2, 0x7, 0x4, 0xD, 0x6, 0x0,
99 {0x4, 0x2, 0xF, 0x5, 0x9, 0x1, 0x0, 0x8, 0xE, 0x3, 0xB, 0xC, 0xD, 0x7,
103 /* 1.2.643.2.2.31.1 */
104 gost_subst_block Gost28147_CryptoProParamSetA = {
105 {0xB, 0xA, 0xF, 0x5, 0x0, 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7,
108 {0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8, 0xC, 0x4, 0x5, 0xF, 0x3,
111 {0x3, 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8, 0xF,
114 {0xB, 0x5, 0x1, 0x9, 0x8, 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7,
117 {0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0, 0x2, 0xB, 0x4, 0xF, 0x8,
120 {0xE, 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0, 0x7,
123 {0x3, 0x7, 0xE, 0x9, 0x8, 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4,
126 {0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA, 0x4, 0xE, 0xF, 0xC, 0x0,
130 /* 1.2.643.2.2.31.2 */
131 gost_subst_block Gost28147_CryptoProParamSetB = {
132 {0x0, 0x4, 0xB, 0xE, 0x8, 0x3, 0x7, 0x1, 0xA, 0x2, 0x9, 0x6, 0xF, 0xD,
135 {0x5, 0x2, 0xA, 0xB, 0x9, 0x1, 0xC, 0x3, 0x7, 0x4, 0xD, 0x0, 0x6, 0xF,
138 {0x8, 0x3, 0x2, 0x6, 0x4, 0xD, 0xE, 0xB, 0xC, 0x1, 0x7, 0xF, 0xA, 0x0,
141 {0x2, 0x7, 0xC, 0xF, 0x9, 0x5, 0xA, 0xB, 0x1, 0x4, 0x0, 0xD, 0x6, 0x8,
144 {0x7, 0x5, 0x0, 0xD, 0xB, 0x6, 0x1, 0x2, 0x3, 0xA, 0xC, 0xF, 0x4, 0xE,
147 {0xE, 0xC, 0x0, 0xA, 0x9, 0x2, 0xD, 0xB, 0x7, 0x5, 0x8, 0xF, 0x3, 0x6,
150 {0x0, 0x1, 0x2, 0xA, 0x4, 0xD, 0x5, 0xC, 0x9, 0x7, 0x3, 0xF, 0xB, 0x8,
153 {0x8, 0x4, 0xB, 0x1, 0x3, 0x5, 0x0, 0x9, 0x2, 0xE, 0xA, 0xC, 0xD, 0x6,
157 /* 1.2.643.2.2.31.3 */
158 gost_subst_block Gost28147_CryptoProParamSetC = {
159 {0x7, 0x4, 0x0, 0x5, 0xA, 0x2, 0xF, 0xE, 0xC, 0x6, 0x1, 0xB, 0xD, 0x9,
162 {0xA, 0x9, 0x6, 0x8, 0xD, 0xE, 0x2, 0x0, 0xF, 0x3, 0x5, 0xB, 0x4, 0x1,
165 {0xC, 0x9, 0xB, 0x1, 0x8, 0xE, 0x2, 0x4, 0x7, 0x3, 0x6, 0x5, 0xA, 0x0,
168 {0x8, 0xD, 0xB, 0x0, 0x4, 0x5, 0x1, 0x2, 0x9, 0x3, 0xC, 0xE, 0x6, 0xF,
171 {0x3, 0x6, 0x0, 0x1, 0x5, 0xD, 0xA, 0x8, 0xB, 0x2, 0x9, 0x7, 0xE, 0xF,
174 {0x8, 0x2, 0x5, 0x0, 0x4, 0x9, 0xF, 0xA, 0x3, 0x7, 0xC, 0xD, 0x6, 0xE,
177 {0x0, 0x1, 0x7, 0xD, 0xB, 0x4, 0x5, 0x2, 0x8, 0xE, 0xF, 0xC, 0x9, 0xA,
180 {0x1, 0xB, 0xC, 0x2, 0x9, 0xD, 0x0, 0xF, 0x4, 0x5, 0x8, 0xE, 0xA, 0x7,
184 /* 1.2.643.2.2.31.4 */
185 gost_subst_block Gost28147_CryptoProParamSetD = {
186 {0x1, 0xA, 0x6, 0x8, 0xF, 0xB, 0x0, 0x4, 0xC, 0x3, 0x5, 0x9, 0x7, 0xD,
189 {0x3, 0x0, 0x6, 0xF, 0x1, 0xE, 0x9, 0x2, 0xD, 0x8, 0xC, 0x4, 0xB, 0xA,
192 {0x8, 0x0, 0xF, 0x3, 0x2, 0x5, 0xE, 0xB, 0x1, 0xA, 0x4, 0x7, 0xC, 0x9,
195 {0x0, 0xC, 0x8, 0x9, 0xD, 0x2, 0xA, 0xB, 0x7, 0x3, 0x6, 0x5, 0x4, 0xE,
198 {0x1, 0x5, 0xE, 0xC, 0xA, 0x7, 0x0, 0xD, 0x6, 0x2, 0xB, 0x4, 0x9, 0x3,
201 {0x1, 0xC, 0xB, 0x0, 0xF, 0xE, 0x6, 0x5, 0xA, 0xD, 0x4, 0x8, 0x9, 0x3,
204 {0xB, 0x6, 0x3, 0x4, 0xC, 0xF, 0xE, 0x2, 0x7, 0xD, 0x8, 0x0, 0x5, 0xA,
207 {0xF, 0xC, 0x2, 0xA, 0x6, 0x4, 0x5, 0x0, 0x7, 0x9, 0xE, 0xD, 0x1, 0xB,
211 /* 1.2.643.7.1.2.5.1.1 */
212 gost_subst_block Gost28147_TC26ParamSetZ = {
213 {0x1, 0x7, 0xe, 0xd, 0x0, 0x5, 0x8, 0x3, 0x4, 0xf, 0xa, 0x6, 0x9, 0xc,
216 {0x8, 0xe, 0x2, 0x5, 0x6, 0x9, 0x1, 0xc, 0xf, 0x4, 0xb, 0x0, 0xd, 0xa,
219 {0x5, 0xd, 0xf, 0x6, 0x9, 0x2, 0xc, 0xa, 0xb, 0x7, 0x8, 0x1, 0x4, 0x3,
222 {0x7, 0xf, 0x5, 0xa, 0x8, 0x1, 0x6, 0xd, 0x0, 0x9, 0x3, 0xe, 0xb, 0x4,
225 {0xc, 0x8, 0x2, 0x1, 0xd, 0x4, 0xf, 0x6, 0x7, 0x0, 0xa, 0x5, 0x3, 0xe,
228 {0xb, 0x3, 0x5, 0x8, 0x2, 0xf, 0xa, 0xd, 0xe, 0x1, 0x7, 0x4, 0xc, 0x9,
231 {0x6, 0x8, 0x2, 0x3, 0x9, 0xa, 0x5, 0xc, 0x1, 0xe, 0x4, 0x7, 0xb, 0xd,
234 {0xc, 0x4, 0x6, 0x2, 0xa, 0x5, 0xb, 0x9, 0xe, 0x8, 0xd, 0x7, 0x0, 0x3,
238 const byte CryptoProKeyMeshingKey[] = {
239 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23,
240 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4,
241 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12,
242 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B
245 const byte ACPKM_D_const[] = {
246 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
247 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
248 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
249 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
252 /* Initialization of gost_ctx subst blocks*/
253 static void kboxinit(gost_ctx * c, const gost_subst_block * b)
257 for (i = 0; i < 256; i++) {
258 c->k87[i] = (word32) (b->k8[i >> 4] << 4 | b->k7[i & 15]) << 24;
259 c->k65[i] = (b->k6[i >> 4] << 4 | b->k5[i & 15]) << 16;
260 c->k43[i] = (b->k4[i >> 4] << 4 | b->k3[i & 15]) << 8;
261 c->k21[i] = b->k2[i >> 4] << 4 | b->k1[i & 15];
266 /* Part of GOST 28147 algorithm moved into separate function */
267 static word32 f(gost_ctx * c, word32 x)
269 x = c->k87[x >> 24 & 255] | c->k65[x >> 16 & 255] |
270 c->k43[x >> 8 & 255] | c->k21[x & 255];
271 /* Rotate left 11 bits */
272 return x << 11 | x >> (32 - 11);
275 /* Low-level encryption routine - encrypts one 64 bit block*/
276 void gostcrypt(gost_ctx * c, const byte * in, byte * out)
278 register word32 n1, n2; /* As named in the GOST */
279 n1 = in[0] | (in[1] << 8) | (in[2] << 16) | ((word32) in[3] << 24);
280 n2 = in[4] | (in[5] << 8) | (in[6] << 16) | ((word32) in[7] << 24);
281 /* Instead of swapping halves, swap names each round */
283 n2 ^= f(c, n1 + c->k[0]);
284 n1 ^= f(c, n2 + c->k[1]);
285 n2 ^= f(c, n1 + c->k[2]);
286 n1 ^= f(c, n2 + c->k[3]);
287 n2 ^= f(c, n1 + c->k[4]);
288 n1 ^= f(c, n2 + c->k[5]);
289 n2 ^= f(c, n1 + c->k[6]);
290 n1 ^= f(c, n2 + c->k[7]);
292 n2 ^= f(c, n1 + c->k[0]);
293 n1 ^= f(c, n2 + c->k[1]);
294 n2 ^= f(c, n1 + c->k[2]);
295 n1 ^= f(c, n2 + c->k[3]);
296 n2 ^= f(c, n1 + c->k[4]);
297 n1 ^= f(c, n2 + c->k[5]);
298 n2 ^= f(c, n1 + c->k[6]);
299 n1 ^= f(c, n2 + c->k[7]);
301 n2 ^= f(c, n1 + c->k[0]);
302 n1 ^= f(c, n2 + c->k[1]);
303 n2 ^= f(c, n1 + c->k[2]);
304 n1 ^= f(c, n2 + c->k[3]);
305 n2 ^= f(c, n1 + c->k[4]);
306 n1 ^= f(c, n2 + c->k[5]);
307 n2 ^= f(c, n1 + c->k[6]);
308 n1 ^= f(c, n2 + c->k[7]);
310 n2 ^= f(c, n1 + c->k[7]);
311 n1 ^= f(c, n2 + c->k[6]);
312 n2 ^= f(c, n1 + c->k[5]);
313 n1 ^= f(c, n2 + c->k[4]);
314 n2 ^= f(c, n1 + c->k[3]);
315 n1 ^= f(c, n2 + c->k[2]);
316 n2 ^= f(c, n1 + c->k[1]);
317 n1 ^= f(c, n2 + c->k[0]);
319 out[0] = (byte) (n2 & 0xff);
320 out[1] = (byte) ((n2 >> 8) & 0xff);
321 out[2] = (byte) ((n2 >> 16) & 0xff);
322 out[3] = (byte) (n2 >> 24);
323 out[4] = (byte) (n1 & 0xff);
324 out[5] = (byte) ((n1 >> 8) & 0xff);
325 out[6] = (byte) ((n1 >> 16) & 0xff);
326 out[7] = (byte) (n1 >> 24);
329 /* Low-level decryption routine. Decrypts one 64-bit block */
330 void gostdecrypt(gost_ctx * c, const byte * in, byte * out)
332 register word32 n1, n2; /* As named in the GOST */
333 n1 = in[0] | (in[1] << 8) | (in[2] << 16) | ((word32) in[3] << 24);
334 n2 = in[4] | (in[5] << 8) | (in[6] << 16) | ((word32) in[7] << 24);
336 n2 ^= f(c, n1 + c->k[0]);
337 n1 ^= f(c, n2 + c->k[1]);
338 n2 ^= f(c, n1 + c->k[2]);
339 n1 ^= f(c, n2 + c->k[3]);
340 n2 ^= f(c, n1 + c->k[4]);
341 n1 ^= f(c, n2 + c->k[5]);
342 n2 ^= f(c, n1 + c->k[6]);
343 n1 ^= f(c, n2 + c->k[7]);
345 n2 ^= f(c, n1 + c->k[7]);
346 n1 ^= f(c, n2 + c->k[6]);
347 n2 ^= f(c, n1 + c->k[5]);
348 n1 ^= f(c, n2 + c->k[4]);
349 n2 ^= f(c, n1 + c->k[3]);
350 n1 ^= f(c, n2 + c->k[2]);
351 n2 ^= f(c, n1 + c->k[1]);
352 n1 ^= f(c, n2 + c->k[0]);
354 n2 ^= f(c, n1 + c->k[7]);
355 n1 ^= f(c, n2 + c->k[6]);
356 n2 ^= f(c, n1 + c->k[5]);
357 n1 ^= f(c, n2 + c->k[4]);
358 n2 ^= f(c, n1 + c->k[3]);
359 n1 ^= f(c, n2 + c->k[2]);
360 n2 ^= f(c, n1 + c->k[1]);
361 n1 ^= f(c, n2 + c->k[0]);
363 n2 ^= f(c, n1 + c->k[7]);
364 n1 ^= f(c, n2 + c->k[6]);
365 n2 ^= f(c, n1 + c->k[5]);
366 n1 ^= f(c, n2 + c->k[4]);
367 n2 ^= f(c, n1 + c->k[3]);
368 n1 ^= f(c, n2 + c->k[2]);
369 n2 ^= f(c, n1 + c->k[1]);
370 n1 ^= f(c, n2 + c->k[0]);
372 out[0] = (byte) (n2 & 0xff);
373 out[1] = (byte) ((n2 >> 8) & 0xff);
374 out[2] = (byte) ((n2 >> 16) & 0xff);
375 out[3] = (byte) (n2 >> 24);
376 out[4] = (byte) (n1 & 0xff);
377 out[5] = (byte) ((n1 >> 8) & 0xff);
378 out[6] = (byte) ((n1 >> 16) & 0xff);
379 out[7] = (byte) (n1 >> 24);
382 /* Encrypts several blocks in ECB mode */
383 void gost_enc(gost_ctx * c, const byte * clear, byte * cipher, int blocks)
386 for (i = 0; i < blocks; i++) {
387 gostcrypt(c, clear, cipher);
393 /* Decrypts several blocks in ECB mode */
394 void gost_dec(gost_ctx * c, const byte * cipher, byte * clear, int blocks)
397 for (i = 0; i < blocks; i++) {
398 gostdecrypt(c, cipher, clear);
404 /* Encrypts several full blocks in CFB mode using 8byte IV */
405 void gost_enc_cfb(gost_ctx * ctx, const byte * iv, const byte * clear,
406 byte * cipher, int blocks)
413 memcpy(cur_iv, iv, 8);
414 for (i = 0, in = clear, out = cipher; i < blocks; i++, in += 8, out += 8) {
415 gostcrypt(ctx, cur_iv, gamma);
416 for (j = 0; j < 8; j++) {
417 cur_iv[j] = out[j] = in[j] ^ gamma[j];
422 /* Decrypts several full blocks in CFB mode using 8byte IV */
423 void gost_dec_cfb(gost_ctx * ctx, const byte * iv, const byte * cipher,
424 byte * clear, int blocks)
431 memcpy(cur_iv, iv, 8);
432 for (i = 0, in = cipher, out = clear; i < blocks; i++, in += 8, out += 8) {
433 gostcrypt(ctx, cur_iv, gamma);
434 for (j = 0; j < 8; j++) {
435 out[j] = (cur_iv[j] = in[j]) ^ gamma[j];
440 /* Encrypts one block using specified key */
441 void gost_enc_with_key(gost_ctx * c, byte * key, byte * inblock,
445 gostcrypt(c, inblock, outblock);
448 /* Set 256 bit gost89 key into context */
449 void gost_key(gost_ctx * c, const byte * k)
452 for (i = 0, j = 0; i < 8; i++, j += 4) {
454 k[j] | (k[j + 1] << 8) | (k[j + 2] << 16) | ((word32) k[j + 3] <<
459 /* Set 256 bit Magma key into context */
460 void magma_key(gost_ctx * c, const byte * k)
463 for (i = 0, j = 0; i < 8; i++, j += 4) {
465 k[j + 3] | (k[j + 2] << 8) | (k[j + 1] << 16) | ((word32) k[j] <<
470 /* Retrieve 256-bit gost89 key from context */
471 void gost_get_key(gost_ctx * c, byte * k)
474 for (i = 0, j = 0; i < 8; i++, j += 4) {
475 k[j] = (byte) (c->k[i] & 0xFF);
476 k[j + 1] = (byte) ((c->k[i] >> 8) & 0xFF);
477 k[j + 2] = (byte) ((c->k[i] >> 16) & 0xFF);
478 k[j + 3] = (byte) ((c->k[i] >> 24) & 0xFF);
482 /* Retrieve 256-bit magma key from context */
483 void magma_get_key(gost_ctx * c, byte * k)
486 for (i = 0, j = 0; i < 8; i++, j += 4) {
487 k[j + 3] = (byte) (c->k[i] & 0xFF);
488 k[j + 2] = (byte) ((c->k[i] >> 8) & 0xFF);
489 k[j + 1] = (byte) ((c->k[i] >> 16) & 0xFF);
490 k[j + 0] = (byte) ((c->k[i] >> 24) & 0xFF);
494 /* Initalize context. Provides default value for subst_block */
495 void gost_init(gost_ctx * c, const gost_subst_block * b)
498 b = &GostR3411_94_TestParamSet;
503 /* Cleans up key from context */
504 void gost_destroy(gost_ctx * c)
507 for (i = 0; i < 8; i++)
512 * Compute GOST 28147 mac block Parameters gost_ctx *c - context initalized
513 * with substitution blocks and key buffer - 8-byte mac state buffer block
514 * 8-byte block to process.
516 void mac_block(gost_ctx * c, byte * buffer, const byte * block)
518 register word32 n1, n2; /* As named in the GOST */
520 for (i = 0; i < 8; i++) {
521 buffer[i] ^= block[i];
523 n1 = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | ((word32)
525 n2 = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | ((word32)
527 /* Instead of swapping halves, swap names each round */
529 n2 ^= f(c, n1 + c->k[0]);
530 n1 ^= f(c, n2 + c->k[1]);
531 n2 ^= f(c, n1 + c->k[2]);
532 n1 ^= f(c, n2 + c->k[3]);
533 n2 ^= f(c, n1 + c->k[4]);
534 n1 ^= f(c, n2 + c->k[5]);
535 n2 ^= f(c, n1 + c->k[6]);
536 n1 ^= f(c, n2 + c->k[7]);
538 n2 ^= f(c, n1 + c->k[0]);
539 n1 ^= f(c, n2 + c->k[1]);
540 n2 ^= f(c, n1 + c->k[2]);
541 n1 ^= f(c, n2 + c->k[3]);
542 n2 ^= f(c, n1 + c->k[4]);
543 n1 ^= f(c, n2 + c->k[5]);
544 n2 ^= f(c, n1 + c->k[6]);
545 n1 ^= f(c, n2 + c->k[7]);
547 buffer[0] = (byte) (n1 & 0xff);
548 buffer[1] = (byte) ((n1 >> 8) & 0xff);
549 buffer[2] = (byte) ((n1 >> 16) & 0xff);
550 buffer[3] = (byte) (n1 >> 24);
551 buffer[4] = (byte) (n2 & 0xff);
552 buffer[5] = (byte) ((n2 >> 8) & 0xff);
553 buffer[6] = (byte) ((n2 >> 16) & 0xff);
554 buffer[7] = (byte) (n2 >> 24);
557 /* Get mac with specified number of bits from MAC state buffer */
558 void get_mac(byte * buffer, int nbits, byte * out)
560 int nbytes = nbits >> 3;
561 int rembits = nbits & 7;
562 int mask = rembits ? ((1 < rembits) - 1) : 0;
564 for (i = 0; i < nbytes; i++)
567 out[i] = buffer[i] & mask;
571 * Compute mac of specified length (in bits) from data. Context should be
572 * initialized with key and subst blocks
574 int gost_mac(gost_ctx * ctx, int mac_len, const unsigned char *data,
575 unsigned int data_len, unsigned char *mac)
577 byte buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
580 for (i = 0; i + 8 <= data_len; i += 8)
581 mac_block(ctx, buffer, data + i);
584 memcpy(buf2, data + i, data_len - i);
585 mac_block(ctx, buffer, buf2);
590 mac_block(ctx, buffer, buf2);
592 get_mac(buffer, mac_len, mac);
596 /* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
597 int gost_mac_iv(gost_ctx * ctx, int mac_len, const unsigned char *iv,
598 const unsigned char *data, unsigned int data_len,
604 memcpy(buffer, iv, 8);
605 for (i = 0; i + 8 <= data_len; i += 8)
606 mac_block(ctx, buffer, data + i);
609 memcpy(buf2, data + i, data_len - i);
610 mac_block(ctx, buffer, buf2);
615 mac_block(ctx, buffer, buf2);
617 get_mac(buffer, mac_len, mac);
621 /* Implements key meshing algorithm by modifing ctx and IV in place */
622 void cryptopro_key_meshing(gost_ctx * ctx, unsigned char *iv)
624 unsigned char newkey[32], newiv[8];
625 /* Set static keymeshing key */
626 /* "Decrypt" key with keymeshing key */
627 gost_dec(ctx, CryptoProKeyMeshingKey, newkey, 4);
629 gost_key(ctx, newkey);
630 /* Encrypt iv with new key */
631 gostcrypt(ctx, iv, newiv);
632 memcpy(iv, newiv, 8);
635 void acpkm_magma_key_meshing(gost_ctx * ctx)
637 unsigned char newkey[32];
639 unsigned char buf[8], keybuf[8];
641 for (i = 0; i < 4; i++) {
642 for (j = 0; j < 8; j++) {
643 buf[j] = ACPKM_D_const[8 * i + 7 - j];
645 gostcrypt(ctx, buf, keybuf);
646 memcpy(newkey + 8 * i, keybuf + 4, 4);
647 memcpy(newkey + 8 * i + 4, keybuf, 4);
650 gost_key(ctx, newkey);
653 #ifdef ENABLE_UNIT_TESTS
657 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
661 fprintf(f, "%s", title);
664 fprintf(f, "\n%04x", n);
665 fprintf(f, " %02x", s[n]);
672 const unsigned char initial_key[] = {
673 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
674 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
675 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
676 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
679 const unsigned char meshed_key[] = {
680 0x86, 0x3E, 0xA0, 0x17, 0x84, 0x2C, 0x3D, 0x37,
681 0x2B, 0x18, 0xA8, 0x5A, 0x28, 0xE2, 0x31, 0x7D,
682 0x74, 0xBE, 0xFC, 0x10, 0x77, 0x20, 0xDE, 0x0C,
683 0x9E, 0x8A, 0xB9, 0x74, 0xAB, 0xD0, 0x0C, 0xA0,
686 unsigned char buf[32];
689 kboxinit(&ctx, &Gost28147_TC26ParamSetZ);
690 magma_key(&ctx, initial_key);
691 magma_get_key(&ctx, buf);
693 hexdump(stdout, "Initial key", buf, 32);
695 acpkm_magma_key_meshing(&ctx);
696 magma_get_key(&ctx, buf);
697 hexdump(stdout, "Meshed key - K2", buf, 32);
699 if (memcmp(meshed_key, buf, 32)) {
700 fprintf(stderr, "Magma meshing failed");
703 acpkm_magma_key_meshing(&ctx);
704 magma_get_key(&ctx, buf);
705 hexdump(stdout, "Meshed key - K3", buf, 32);
707 acpkm_magma_key_meshing(&ctx);
708 magma_get_key(&ctx, buf);
709 hexdump(stdout, "Meshed key - K4", buf, 32);