| /********************************************************************** |
| * gost89.c * |
| * Copyright (c) 2005-2006 Cryptocom LTD * |
| * This file is distributed under the same license as OpenSSL * |
| * * |
| * Implementation of GOST 28147-89 encryption algorithm * |
| * No OpenSSL libraries required to compile and use * |
| * this code * |
| **********************************************************************/ |
| #include <string.h> |
| #include "gost89.h" |
| /*- |
| Substitution blocks from RFC 4357 |
| |
| Note: our implementation of gost 28147-89 algorithm |
| uses S-box matrix rotated 90 degrees counterclockwise, relative to |
| examples given in RFC. |
| |
| |
| */ |
| |
| /* Substitution blocks from test examples for GOST R 34.11-94*/ |
| gost_subst_block GostR3411_94_TestParamSet = { |
| {0X1, 0XF, 0XD, 0X0, 0X5, 0X7, 0XA, 0X4, 0X9, 0X2, 0X3, 0XE, 0X6, 0XB, |
| 0X8, 0XC} |
| , |
| {0XD, 0XB, 0X4, 0X1, 0X3, 0XF, 0X5, 0X9, 0X0, 0XA, 0XE, 0X7, 0X6, 0X8, |
| 0X2, 0XC} |
| , |
| {0X4, 0XB, 0XA, 0X0, 0X7, 0X2, 0X1, 0XD, 0X3, 0X6, 0X8, 0X5, 0X9, 0XC, |
| 0XF, 0XE} |
| , |
| {0X6, 0XC, 0X7, 0X1, 0X5, 0XF, 0XD, 0X8, 0X4, 0XA, 0X9, 0XE, 0X0, 0X3, |
| 0XB, 0X2} |
| , |
| {0X7, 0XD, 0XA, 0X1, 0X0, 0X8, 0X9, 0XF, 0XE, 0X4, 0X6, 0XC, 0XB, 0X2, |
| 0X5, 0X3} |
| , |
| {0X5, 0X8, 0X1, 0XD, 0XA, 0X3, 0X4, 0X2, 0XE, 0XF, 0XC, 0X7, 0X6, 0X0, |
| 0X9, 0XB} |
| , |
| {0XE, 0XB, 0X4, 0XC, 0X6, 0XD, 0XF, 0XA, 0X2, 0X3, 0X8, 0X1, 0X0, 0X7, |
| 0X5, 0X9} |
| , |
| {0X4, 0XA, 0X9, 0X2, 0XD, 0X8, 0X0, 0XE, 0X6, 0XB, 0X1, 0XC, 0X7, 0XF, |
| 0X5, 0X3} |
| }; |
| |
| /* Substitution blocks for hash function 1.2.643.2.9.1.6.1 */ |
| gost_subst_block GostR3411_94_CryptoProParamSet = { |
| {0x1, 0x3, 0xA, 0x9, 0x5, 0xB, 0x4, 0xF, 0x8, 0x6, 0x7, 0xE, 0xD, 0x0, |
| 0x2, 0xC} |
| , |
| {0xD, 0xE, 0x4, 0x1, 0x7, 0x0, 0x5, 0xA, 0x3, 0xC, 0x8, 0xF, 0x6, 0x2, |
| 0x9, 0xB} |
| , |
| {0x7, 0x6, 0x2, 0x4, 0xD, 0x9, 0xF, 0x0, 0xA, 0x1, 0x5, 0xB, 0x8, 0xE, |
| 0xC, 0x3} |
| , |
| {0x7, 0x6, 0x4, 0xB, 0x9, 0xC, 0x2, 0xA, 0x1, 0x8, 0x0, 0xE, 0xF, 0xD, |
| 0x3, 0x5} |
| , |
| {0x4, 0xA, 0x7, 0xC, 0x0, 0xF, 0x2, 0x8, 0xE, 0x1, 0x6, 0x5, 0xD, 0xB, |
| 0x9, 0x3} |
| , |
| {0x7, 0xF, 0xC, 0xE, 0x9, 0x4, 0x1, 0x0, 0x3, 0xB, 0x5, 0x2, 0x6, 0xA, |
| 0x8, 0xD} |
| , |
| {0x5, 0xF, 0x4, 0x0, 0x2, 0xD, 0xB, 0x9, 0x1, 0x7, 0x6, 0x3, 0xC, 0xE, |
| 0xA, 0x8} |
| , |
| {0xA, 0x4, 0x5, 0x6, 0x8, 0x1, 0x3, 0x7, 0xD, 0xC, 0xE, 0x0, 0x9, 0x2, |
| 0xB, 0xF} |
| }; |
| |
| /* Test paramset from GOST 28147 */ |
| gost_subst_block Gost28147_TestParamSet = { |
| {0xC, 0x6, 0x5, 0x2, 0xB, 0x0, 0x9, 0xD, 0x3, 0xE, 0x7, 0xA, 0xF, 0x4, |
| 0x1, 0x8} |
| , |
| {0x9, 0xB, 0xC, 0x0, 0x3, 0x6, 0x7, 0x5, 0x4, 0x8, 0xE, 0xF, 0x1, 0xA, |
| 0x2, 0xD} |
| , |
| {0x8, 0xF, 0x6, 0xB, 0x1, 0x9, 0xC, 0x5, 0xD, 0x3, 0x7, 0xA, 0x0, 0xE, |
| 0x2, 0x4} |
| , |
| {0x3, 0xE, 0x5, 0x9, 0x6, 0x8, 0x0, 0xD, 0xA, 0xB, 0x7, 0xC, 0x2, 0x1, |
| 0xF, 0x4} |
| , |
| {0xE, 0x9, 0xB, 0x2, 0x5, 0xF, 0x7, 0x1, 0x0, 0xD, 0xC, 0x6, 0xA, 0x4, |
| 0x3, 0x8} |
| , |
| {0xD, 0x8, 0xE, 0xC, 0x7, 0x3, 0x9, 0xA, 0x1, 0x5, 0x2, 0x4, 0x6, 0xF, |
| 0x0, 0xB} |
| , |
| {0xC, 0x9, 0xF, 0xE, 0x8, 0x1, 0x3, 0xA, 0x2, 0x7, 0x4, 0xD, 0x6, 0x0, |
| 0xB, 0x5} |
| , |
| {0x4, 0x2, 0xF, 0x5, 0x9, 0x1, 0x0, 0x8, 0xE, 0x3, 0xB, 0xC, 0xD, 0x7, |
| 0xA, 0x6} |
| }; |
| |
| /* 1.2.643.2.2.31.1 */ |
| gost_subst_block Gost28147_CryptoProParamSetA = { |
| {0xB, 0xA, 0xF, 0x5, 0x0, 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7, |
| 0xD, 0x4} |
| , |
| {0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8, 0xC, 0x4, 0x5, 0xF, 0x3, |
| 0xB, 0xE} |
| , |
| {0x3, 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8, 0xF, |
| 0xE, 0x6} |
| , |
| {0xB, 0x5, 0x1, 0x9, 0x8, 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7, |
| 0xA, 0x6} |
| , |
| {0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0, 0x2, 0xB, 0x4, 0xF, 0x8, |
| 0x5, 0x6} |
| , |
| {0xE, 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0, 0x7, |
| 0x1, 0x9} |
| , |
| {0x3, 0x7, 0xE, 0x9, 0x8, 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4, |
| 0xD, 0x1} |
| , |
| {0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA, 0x4, 0xE, 0xF, 0xC, 0x0, |
| 0xD, 0x5} |
| }; |
| |
| /* 1.2.643.2.2.31.2 */ |
| gost_subst_block Gost28147_CryptoProParamSetB = { |
| {0x0, 0x4, 0xB, 0xE, 0x8, 0x3, 0x7, 0x1, 0xA, 0x2, 0x9, 0x6, 0xF, 0xD, |
| 0x5, 0xC} |
| , |
| {0x5, 0x2, 0xA, 0xB, 0x9, 0x1, 0xC, 0x3, 0x7, 0x4, 0xD, 0x0, 0x6, 0xF, |
| 0x8, 0xE} |
| , |
| {0x8, 0x3, 0x2, 0x6, 0x4, 0xD, 0xE, 0xB, 0xC, 0x1, 0x7, 0xF, 0xA, 0x0, |
| 0x9, 0x5} |
| , |
| {0x2, 0x7, 0xC, 0xF, 0x9, 0x5, 0xA, 0xB, 0x1, 0x4, 0x0, 0xD, 0x6, 0x8, |
| 0xE, 0x3} |
| , |
| {0x7, 0x5, 0x0, 0xD, 0xB, 0x6, 0x1, 0x2, 0x3, 0xA, 0xC, 0xF, 0x4, 0xE, |
| 0x9, 0x8} |
| , |
| {0xE, 0xC, 0x0, 0xA, 0x9, 0x2, 0xD, 0xB, 0x7, 0x5, 0x8, 0xF, 0x3, 0x6, |
| 0x1, 0x4} |
| , |
| {0x0, 0x1, 0x2, 0xA, 0x4, 0xD, 0x5, 0xC, 0x9, 0x7, 0x3, 0xF, 0xB, 0x8, |
| 0x6, 0xE} |
| , |
| {0x8, 0x4, 0xB, 0x1, 0x3, 0x5, 0x0, 0x9, 0x2, 0xE, 0xA, 0xC, 0xD, 0x6, |
| 0x7, 0xF} |
| }; |
| |
| /* 1.2.643.2.2.31.3 */ |
| gost_subst_block Gost28147_CryptoProParamSetC = { |
| {0x7, 0x4, 0x0, 0x5, 0xA, 0x2, 0xF, 0xE, 0xC, 0x6, 0x1, 0xB, 0xD, 0x9, |
| 0x3, 0x8} |
| , |
| {0xA, 0x9, 0x6, 0x8, 0xD, 0xE, 0x2, 0x0, 0xF, 0x3, 0x5, 0xB, 0x4, 0x1, |
| 0xC, 0x7} |
| , |
| {0xC, 0x9, 0xB, 0x1, 0x8, 0xE, 0x2, 0x4, 0x7, 0x3, 0x6, 0x5, 0xA, 0x0, |
| 0xF, 0xD} |
| , |
| {0x8, 0xD, 0xB, 0x0, 0x4, 0x5, 0x1, 0x2, 0x9, 0x3, 0xC, 0xE, 0x6, 0xF, |
| 0xA, 0x7} |
| , |
| {0x3, 0x6, 0x0, 0x1, 0x5, 0xD, 0xA, 0x8, 0xB, 0x2, 0x9, 0x7, 0xE, 0xF, |
| 0xC, 0x4} |
| , |
| {0x8, 0x2, 0x5, 0x0, 0x4, 0x9, 0xF, 0xA, 0x3, 0x7, 0xC, 0xD, 0x6, 0xE, |
| 0x1, 0xB} |
| , |
| {0x0, 0x1, 0x7, 0xD, 0xB, 0x4, 0x5, 0x2, 0x8, 0xE, 0xF, 0xC, 0x9, 0xA, |
| 0x6, 0x3} |
| , |
| {0x1, 0xB, 0xC, 0x2, 0x9, 0xD, 0x0, 0xF, 0x4, 0x5, 0x8, 0xE, 0xA, 0x7, |
| 0x6, 0x3} |
| }; |
| |
| /* 1.2.643.2.2.31.4 */ |
| gost_subst_block Gost28147_CryptoProParamSetD = { |
| {0x1, 0xA, 0x6, 0x8, 0xF, 0xB, 0x0, 0x4, 0xC, 0x3, 0x5, 0x9, 0x7, 0xD, |
| 0x2, 0xE} |
| , |
| {0x3, 0x0, 0x6, 0xF, 0x1, 0xE, 0x9, 0x2, 0xD, 0x8, 0xC, 0x4, 0xB, 0xA, |
| 0x5, 0x7} |
| , |
| {0x8, 0x0, 0xF, 0x3, 0x2, 0x5, 0xE, 0xB, 0x1, 0xA, 0x4, 0x7, 0xC, 0x9, |
| 0xD, 0x6} |
| , |
| {0x0, 0xC, 0x8, 0x9, 0xD, 0x2, 0xA, 0xB, 0x7, 0x3, 0x6, 0x5, 0x4, 0xE, |
| 0xF, 0x1} |
| , |
| {0x1, 0x5, 0xE, 0xC, 0xA, 0x7, 0x0, 0xD, 0x6, 0x2, 0xB, 0x4, 0x9, 0x3, |
| 0xF, 0x8} |
| , |
| {0x1, 0xC, 0xB, 0x0, 0xF, 0xE, 0x6, 0x5, 0xA, 0xD, 0x4, 0x8, 0x9, 0x3, |
| 0x7, 0x2} |
| , |
| {0xB, 0x6, 0x3, 0x4, 0xC, 0xF, 0xE, 0x2, 0x7, 0xD, 0x8, 0x0, 0x5, 0xA, |
| 0x9, 0x1} |
| , |
| {0xF, 0xC, 0x2, 0xA, 0x6, 0x4, 0x5, 0x0, 0x7, 0x9, 0xE, 0xD, 0x1, 0xB, |
| 0x8, 0x3} |
| }; |
| |
| const byte CryptoProKeyMeshingKey[] = { |
| 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23, |
| 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4, |
| 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12, |
| 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B |
| }; |
| |
| /* Initialization of gost_ctx subst blocks*/ |
| static void kboxinit(gost_ctx * c, const gost_subst_block * b) |
| { |
| int i; |
| |
| for (i = 0; i < 256; i++) { |
| c->k87[i] = (b->k8[i >> 4] << 4 | b->k7[i & 15]) << 24; |
| c->k65[i] = (b->k6[i >> 4] << 4 | b->k5[i & 15]) << 16; |
| c->k43[i] = (b->k4[i >> 4] << 4 | b->k3[i & 15]) << 8; |
| c->k21[i] = b->k2[i >> 4] << 4 | b->k1[i & 15]; |
| |
| } |
| } |
| |
| /* Part of GOST 28147 algorithm moved into separate function */ |
| static word32 f(gost_ctx * c, word32 x) |
| { |
| x = c->k87[x >> 24 & 255] | c->k65[x >> 16 & 255] | |
| c->k43[x >> 8 & 255] | c->k21[x & 255]; |
| /* Rotate left 11 bits */ |
| return x << 11 | x >> (32 - 11); |
| } |
| |
| /* Low-level encryption routine - encrypts one 64 bit block*/ |
| void gostcrypt(gost_ctx * c, const byte * in, byte * out) |
| { |
| register word32 n1, n2; /* As named in the GOST */ |
| n1 = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24); |
| n2 = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24); |
| /* Instead of swapping halves, swap names each round */ |
| |
| n2 ^= f(c, n1 + c->k[0]); |
| n1 ^= f(c, n2 + c->k[1]); |
| n2 ^= f(c, n1 + c->k[2]); |
| n1 ^= f(c, n2 + c->k[3]); |
| n2 ^= f(c, n1 + c->k[4]); |
| n1 ^= f(c, n2 + c->k[5]); |
| n2 ^= f(c, n1 + c->k[6]); |
| n1 ^= f(c, n2 + c->k[7]); |
| |
| n2 ^= f(c, n1 + c->k[0]); |
| n1 ^= f(c, n2 + c->k[1]); |
| n2 ^= f(c, n1 + c->k[2]); |
| n1 ^= f(c, n2 + c->k[3]); |
| n2 ^= f(c, n1 + c->k[4]); |
| n1 ^= f(c, n2 + c->k[5]); |
| n2 ^= f(c, n1 + c->k[6]); |
| n1 ^= f(c, n2 + c->k[7]); |
| |
| n2 ^= f(c, n1 + c->k[0]); |
| n1 ^= f(c, n2 + c->k[1]); |
| n2 ^= f(c, n1 + c->k[2]); |
| n1 ^= f(c, n2 + c->k[3]); |
| n2 ^= f(c, n1 + c->k[4]); |
| n1 ^= f(c, n2 + c->k[5]); |
| n2 ^= f(c, n1 + c->k[6]); |
| n1 ^= f(c, n2 + c->k[7]); |
| |
| n2 ^= f(c, n1 + c->k[7]); |
| n1 ^= f(c, n2 + c->k[6]); |
| n2 ^= f(c, n1 + c->k[5]); |
| n1 ^= f(c, n2 + c->k[4]); |
| n2 ^= f(c, n1 + c->k[3]); |
| n1 ^= f(c, n2 + c->k[2]); |
| n2 ^= f(c, n1 + c->k[1]); |
| n1 ^= f(c, n2 + c->k[0]); |
| |
| out[0] = (byte) (n2 & 0xff); |
| out[1] = (byte) ((n2 >> 8) & 0xff); |
| out[2] = (byte) ((n2 >> 16) & 0xff); |
| out[3] = (byte) (n2 >> 24); |
| out[4] = (byte) (n1 & 0xff); |
| out[5] = (byte) ((n1 >> 8) & 0xff); |
| out[6] = (byte) ((n1 >> 16) & 0xff); |
| out[7] = (byte) (n1 >> 24); |
| } |
| |
| /* Low-level decryption routine. Decrypts one 64-bit block */ |
| void gostdecrypt(gost_ctx * c, const byte * in, byte * out) |
| { |
| register word32 n1, n2; /* As named in the GOST */ |
| n1 = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24); |
| n2 = in[4] | (in[5] << 8) | (in[6] << 16) | (in[7] << 24); |
| |
| n2 ^= f(c, n1 + c->k[0]); |
| n1 ^= f(c, n2 + c->k[1]); |
| n2 ^= f(c, n1 + c->k[2]); |
| n1 ^= f(c, n2 + c->k[3]); |
| n2 ^= f(c, n1 + c->k[4]); |
| n1 ^= f(c, n2 + c->k[5]); |
| n2 ^= f(c, n1 + c->k[6]); |
| n1 ^= f(c, n2 + c->k[7]); |
| |
| n2 ^= f(c, n1 + c->k[7]); |
| n1 ^= f(c, n2 + c->k[6]); |
| n2 ^= f(c, n1 + c->k[5]); |
| n1 ^= f(c, n2 + c->k[4]); |
| n2 ^= f(c, n1 + c->k[3]); |
| n1 ^= f(c, n2 + c->k[2]); |
| n2 ^= f(c, n1 + c->k[1]); |
| n1 ^= f(c, n2 + c->k[0]); |
| |
| n2 ^= f(c, n1 + c->k[7]); |
| n1 ^= f(c, n2 + c->k[6]); |
| n2 ^= f(c, n1 + c->k[5]); |
| n1 ^= f(c, n2 + c->k[4]); |
| n2 ^= f(c, n1 + c->k[3]); |
| n1 ^= f(c, n2 + c->k[2]); |
| n2 ^= f(c, n1 + c->k[1]); |
| n1 ^= f(c, n2 + c->k[0]); |
| |
| n2 ^= f(c, n1 + c->k[7]); |
| n1 ^= f(c, n2 + c->k[6]); |
| n2 ^= f(c, n1 + c->k[5]); |
| n1 ^= f(c, n2 + c->k[4]); |
| n2 ^= f(c, n1 + c->k[3]); |
| n1 ^= f(c, n2 + c->k[2]); |
| n2 ^= f(c, n1 + c->k[1]); |
| n1 ^= f(c, n2 + c->k[0]); |
| |
| out[0] = (byte) (n2 & 0xff); |
| out[1] = (byte) ((n2 >> 8) & 0xff); |
| out[2] = (byte) ((n2 >> 16) & 0xff); |
| out[3] = (byte) (n2 >> 24); |
| out[4] = (byte) (n1 & 0xff); |
| out[5] = (byte) ((n1 >> 8) & 0xff); |
| out[6] = (byte) ((n1 >> 16) & 0xff); |
| out[7] = (byte) (n1 >> 24); |
| } |
| |
| /* Encrypts several blocks in ECB mode */ |
| void gost_enc(gost_ctx * c, const byte * clear, byte * cipher, int blocks) |
| { |
| int i; |
| for (i = 0; i < blocks; i++) { |
| gostcrypt(c, clear, cipher); |
| clear += 8; |
| cipher += 8; |
| } |
| } |
| |
| /* Decrypts several blocks in ECB mode */ |
| void gost_dec(gost_ctx * c, const byte * cipher, byte * clear, int blocks) |
| { |
| int i; |
| for (i = 0; i < blocks; i++) { |
| gostdecrypt(c, cipher, clear); |
| clear += 8; |
| cipher += 8; |
| } |
| } |
| |
| /* Encrypts several full blocks in CFB mode using 8byte IV */ |
| void gost_enc_cfb(gost_ctx * ctx, const byte * iv, const byte * clear, |
| byte * cipher, int blocks) |
| { |
| byte cur_iv[8]; |
| byte gamma[8]; |
| int i, j; |
| const byte *in; |
| byte *out; |
| memcpy(cur_iv, iv, 8); |
| for (i = 0, in = clear, out = cipher; i < blocks; i++, in += 8, out += 8) { |
| gostcrypt(ctx, cur_iv, gamma); |
| for (j = 0; j < 8; j++) { |
| cur_iv[j] = out[j] = in[j] ^ gamma[j]; |
| } |
| } |
| } |
| |
| /* Decrypts several full blocks in CFB mode using 8byte IV */ |
| void gost_dec_cfb(gost_ctx * ctx, const byte * iv, const byte * cipher, |
| byte * clear, int blocks) |
| { |
| byte cur_iv[8]; |
| byte gamma[8]; |
| int i, j; |
| const byte *in; |
| byte *out; |
| memcpy(cur_iv, iv, 8); |
| for (i = 0, in = cipher, out = clear; i < blocks; i++, in += 8, out += 8) { |
| gostcrypt(ctx, cur_iv, gamma); |
| for (j = 0; j < 8; j++) { |
| out[j] = (cur_iv[j] = in[j]) ^ gamma[j]; |
| } |
| } |
| } |
| |
| /* Encrypts one block using specified key */ |
| void gost_enc_with_key(gost_ctx * c, byte * key, byte * inblock, |
| byte * outblock) |
| { |
| gost_key(c, key); |
| gostcrypt(c, inblock, outblock); |
| } |
| |
| /* Set 256 bit key into context */ |
| void gost_key(gost_ctx * c, const byte * k) |
| { |
| int i, j; |
| for (i = 0, j = 0; i < 8; i++, j += 4) { |
| c->k[i] = |
| k[j] | (k[j + 1] << 8) | (k[j + 2] << 16) | (k[j + 3] << 24); |
| } |
| } |
| |
| /* Retrieve 256-bit key from context */ |
| void gost_get_key(gost_ctx * c, byte * k) |
| { |
| int i, j; |
| for (i = 0, j = 0; i < 8; i++, j += 4) { |
| k[j] = (byte) (c->k[i] & 0xFF); |
| k[j + 1] = (byte) ((c->k[i] >> 8) & 0xFF); |
| k[j + 2] = (byte) ((c->k[i] >> 16) & 0xFF); |
| k[j + 3] = (byte) ((c->k[i] >> 24) & 0xFF); |
| } |
| } |
| |
| /* Initalize context. Provides default value for subst_block */ |
| void gost_init(gost_ctx * c, const gost_subst_block * b) |
| { |
| if (!b) { |
| b = &GostR3411_94_TestParamSet; |
| } |
| kboxinit(c, b); |
| } |
| |
| /* Cleans up key from context */ |
| void gost_destroy(gost_ctx * c) |
| { |
| int i; |
| for (i = 0; i < 8; i++) |
| c->k[i] = 0; |
| } |
| |
| /* |
| * Compute GOST 28147 mac block Parameters gost_ctx *c - context initalized |
| * with substitution blocks and key buffer - 8-byte mac state buffer block |
| * 8-byte block to process. |
| */ |
| void mac_block(gost_ctx * c, byte * buffer, const byte * block) |
| { |
| register word32 n1, n2; /* As named in the GOST */ |
| int i; |
| for (i = 0; i < 8; i++) { |
| buffer[i] ^= block[i]; |
| } |
| n1 = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); |
| n2 = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24); |
| /* Instead of swapping halves, swap names each round */ |
| |
| n2 ^= f(c, n1 + c->k[0]); |
| n1 ^= f(c, n2 + c->k[1]); |
| n2 ^= f(c, n1 + c->k[2]); |
| n1 ^= f(c, n2 + c->k[3]); |
| n2 ^= f(c, n1 + c->k[4]); |
| n1 ^= f(c, n2 + c->k[5]); |
| n2 ^= f(c, n1 + c->k[6]); |
| n1 ^= f(c, n2 + c->k[7]); |
| |
| n2 ^= f(c, n1 + c->k[0]); |
| n1 ^= f(c, n2 + c->k[1]); |
| n2 ^= f(c, n1 + c->k[2]); |
| n1 ^= f(c, n2 + c->k[3]); |
| n2 ^= f(c, n1 + c->k[4]); |
| n1 ^= f(c, n2 + c->k[5]); |
| n2 ^= f(c, n1 + c->k[6]); |
| n1 ^= f(c, n2 + c->k[7]); |
| |
| buffer[0] = (byte) (n1 & 0xff); |
| buffer[1] = (byte) ((n1 >> 8) & 0xff); |
| buffer[2] = (byte) ((n1 >> 16) & 0xff); |
| buffer[3] = (byte) (n1 >> 24); |
| buffer[4] = (byte) (n2 & 0xff); |
| buffer[5] = (byte) ((n2 >> 8) & 0xff); |
| buffer[6] = (byte) ((n2 >> 16) & 0xff); |
| buffer[7] = (byte) (n2 >> 24); |
| } |
| |
| /* Get mac with specified number of bits from MAC state buffer */ |
| void get_mac(byte * buffer, int nbits, byte * out) |
| { |
| int nbytes = nbits >> 3; |
| int rembits = nbits & 7; |
| int mask = rembits ? ((1 < rembits) - 1) : 0; |
| int i; |
| for (i = 0; i < nbytes; i++) |
| out[i] = buffer[i]; |
| if (rembits) |
| out[i] = buffer[i] & mask; |
| } |
| |
| /* |
| * Compute mac of specified length (in bits) from data. Context should be |
| * initialized with key and subst blocks |
| */ |
| int gost_mac(gost_ctx * ctx, int mac_len, const unsigned char *data, |
| unsigned int data_len, unsigned char *mac) |
| { |
| byte buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
| byte buf2[8]; |
| unsigned int i; |
| for (i = 0; i + 8 <= data_len; i += 8) |
| mac_block(ctx, buffer, data + i); |
| if (i < data_len) { |
| memset(buf2, 0, 8); |
| memcpy(buf2, data + i, data_len - i); |
| mac_block(ctx, buffer, buf2); |
| i += 8; |
| } |
| if (i == 8) { |
| memset(buf2, 0, 8); |
| mac_block(ctx, buffer, buf2); |
| } |
| get_mac(buffer, mac_len, mac); |
| return 1; |
| } |
| |
| /* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */ |
| int gost_mac_iv(gost_ctx * ctx, int mac_len, const unsigned char *iv, |
| const unsigned char *data, unsigned int data_len, |
| unsigned char *mac) |
| { |
| byte buffer[8]; |
| byte buf2[8]; |
| unsigned int i; |
| memcpy(buffer, iv, 8); |
| for (i = 0; i + 8 <= data_len; i += 8) |
| mac_block(ctx, buffer, data + i); |
| if (i < data_len) { |
| memset(buf2, 0, 8); |
| memcpy(buf2, data + i, data_len - i); |
| mac_block(ctx, buffer, buf2); |
| i += 8; |
| } |
| if (i == 8) { |
| memset(buf2, 0, 8); |
| mac_block(ctx, buffer, buf2); |
| } |
| get_mac(buffer, mac_len, mac); |
| return 1; |
| } |
| |
| /* Implements key meshing algorithm by modifing ctx and IV in place */ |
| void cryptopro_key_meshing(gost_ctx * ctx, unsigned char *iv) |
| { |
| unsigned char newkey[32], newiv[8]; |
| /* Set static keymeshing key */ |
| /* "Decrypt" key with keymeshing key */ |
| gost_dec(ctx, CryptoProKeyMeshingKey, newkey, 4); |
| /* set new key */ |
| gost_key(ctx, newkey); |
| /* Encrypt iv with new key */ |
| gostcrypt(ctx, iv, newiv); |
| memcpy(iv, newiv, 8); |
| } |