2b6201bfd408001c9c147dfea0dfd54f6e79d40d
[openssl.git] / engines / ccgost / gost89.c
1 /**********************************************************************
2  *                        gost89.c                                    *
3  *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *          Implementation of GOST 28147-89 encryption algorithm      *
7  *            No OpenSSL libraries required to compile and use        *
8  *                              this code                             *
9  **********************************************************************/ 
10 #include <string.h>
11 #include "gost89.h"
12 /*-
13    Substitution blocks from RFC 4357 
14    
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.
18   
19
20 */
21
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}
32         };  
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}
43         } ;
44
45 /* Test paramset from GOST 28147 */
46 gost_subst_block Gost28147_TestParamSet =
47         {
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}
56         };
57
58
59
60
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}
71         };
72 /* 1.2.643.2.2.31.2 */
73 gost_subst_block Gost28147_CryptoProParamSetB= 
74         {
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}
83         };
84 /* 1.2.643.2.2.31.3 */
85 gost_subst_block Gost28147_CryptoProParamSetC= 
86         {
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}
95         };
96
97 /* 1.2.643.2.2.31.4 */ 
98 gost_subst_block Gost28147_CryptoProParamSetD=
99         {
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}
108         };
109
110
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
116         };      
117 /* Initialization of gost_ctx subst blocks*/
118 static void kboxinit(gost_ctx *c, const gost_subst_block *b)
119         { 
120         int i; 
121         
122         for (i = 0; i < 256; i++)
123                 {
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];
128
129                 }
130         }
131
132 /* Part of GOST 28147 algorithm moved into separate function */
133 static word32 f(gost_ctx *c,word32 x) 
134         {
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);
139         }
140 /* Low-level encryption routine - encrypts one 64 bit block*/
141 void gostcrypt(gost_ctx *c, const byte *in, byte *out)
142         { 
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 */ 
147          
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]); 
152   
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]);
157                                
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]);
162                                
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]);
167  
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);
172         } 
173 /* Low-level decryption routine. Decrypts one 64-bit block */
174 void gostdecrypt(gost_ctx *c, const byte *in,byte *out)
175         { 
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); 
179         
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]); 
184         
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]);
189         
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]);
194         
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]);
199
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);
204         } 
205
206 /* Encrypts several blocks in ECB mode */
207 void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
208         { 
209         int i; 
210         for(i=0;i<blocks;i++)
211                 { 
212                 gostcrypt(c,clear,cipher); 
213                 clear+=8;
214                 cipher+=8;
215                 }
216         }
217 /* Decrypts several blocks in ECB mode */
218 void gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks)
219         { 
220         int i; 
221         for(i=0;i<blocks;i++)
222                 { 
223                 gostdecrypt(c,cipher,clear); 
224                 clear+=8; 
225                 cipher+=8;
226                 }
227         }
228
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)
231         {
232         byte cur_iv[8];
233         byte gamma[8];
234         int i,j;
235         const byte *in;
236         byte *out;
237         memcpy(cur_iv,iv,8);
238         for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8)
239                 {
240                 gostcrypt(ctx,cur_iv,gamma);
241                 for (j=0;j<8;j++)
242                         {
243                         cur_iv[j]=out[j]=in[j]^gamma[j];
244                         }
245                 }       
246         }       
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)
249         {
250         byte cur_iv[8];
251         byte gamma[8];
252         int i,j;
253         const byte *in;
254         byte *out;
255         memcpy(cur_iv,iv,8);
256         for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8)
257                 {
258                 gostcrypt(ctx,cur_iv,gamma);
259                 for (j=0;j<8;j++)
260                         {
261                         out[j]=(cur_iv[j]=in[j])^gamma[j];
262                         }
263                 }       
264         }       
265
266 /* Encrypts one block using specified key */
267 void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock) 
268         {
269         gost_key(c,key);
270         gostcrypt(c,inblock,outblock);
271         }
272
273 /* Set 256 bit  key into context */
274 void gost_key(gost_ctx *c, const byte *k) 
275         { 
276         int i,j; 
277         for(i=0,j=0;i<8;i++,j+=4)
278                 {
279                 c->k[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|((word32)k[j+3]<<24);
280                 }               
281         } 
282
283 /* Retrieve 256-bit key from context */
284 void gost_get_key(gost_ctx *c, byte *k) 
285         {
286         int i,j; 
287         for(i=0,j=0;i<8;i++,j+=4)
288                 {
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);
293                 }               
294         }
295
296 /* Initalize context. Provides default value for subst_block */
297 void gost_init(gost_ctx *c, const gost_subst_block *b)
298         {       
299         if(!b)
300                 {
301                 b=&GostR3411_94_TestParamSet;
302                 }       
303         kboxinit(c,b); 
304         }
305
306 /* Cleans up key from context */
307 void gost_destroy(gost_ctx *c)
308         { 
309         int i; for(i=0;i<8;i++) c->k[i]=0; 
310         } 
311
312 /* Compute GOST 28147 mac block 
313  * 
314  * Parameters
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.
318  * */
319 void mac_block(gost_ctx *c,byte *buffer,const  byte *block)
320         {
321         register word32 n1, n2; /* As named in the GOST */ 
322         int i;
323         for (i=0; i<8; i++)
324                 {
325                 buffer[i]^=block[i];
326                 }         
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 */ 
330          
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]); 
335   
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]);
340
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);
345         }
346
347 /* Get mac with specified number of bits from MAC state buffer */
348 void get_mac(byte *buffer,int nbits,byte *out)
349         {
350         int nbytes= nbits >> 3;
351         int rembits = nbits & 7;
352         int mask =rembits?((1<rembits)-1):0;
353         int i;
354         for (i=0;i<nbytes;i++) out[i]=buffer[i];
355         if (rembits) out[i]=buffer[i]&mask;
356         }       
357
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) 
362         {
363         byte buffer[8]={0,0,0,0,0,0,0,0};
364         byte buf2[8];
365         unsigned int i;
366         for (i=0;i+8<=data_len;i+=8) 
367                 mac_block(ctx,buffer,data+i);
368         if (i<data_len)
369                 {
370                 memset(buf2,0,8);
371                 memcpy(buf2,data+i,data_len-i);
372                 mac_block(ctx,buffer,buf2);
373                 i+=8;
374                 }
375         if (i==8)
376                 {
377                 memset(buf2,0,8);
378                 mac_block(ctx,buffer,buf2);
379                 }
380         get_mac(buffer,mac_len,mac);
381         return 1;
382         }
383
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) 
387         {
388         byte buffer[8];
389         byte buf2[8];
390         unsigned int i;
391         memcpy (buffer,iv,8);
392         for (i=0;i+8<=data_len;i+=8) 
393                 mac_block(ctx,buffer,data+i);
394         if (i<data_len)
395                 {
396                 memset(buf2,0,8);
397                 memcpy(buf2,data+i,data_len-i);
398                 mac_block(ctx,buffer,buf2);
399                 i+=8;
400                 }       
401         if (i==8)
402                 {
403                 memset(buf2,0,8);
404                 mac_block(ctx,buffer,buf2);
405                 }
406         get_mac(buffer,mac_len,mac);
407         return 1;
408         }
409
410 /* Implements key meshing algorithm by modifing ctx and IV in place */
411 void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv)
412         {
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);
417         /* set new key */
418         gost_key(ctx,newkey);
419         /* Encrypt iv with new key */
420         gostcrypt(ctx,iv,newiv);
421         memcpy(iv,newiv,8);
422         }