Updated version of gost engine.
[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 /* Substitution blocks from RFC 4357 
13    
14    Note: our implementation of gost 28147-89 algorithm 
15    uses S-box matrix rotated 90 degrees counterclockwise, relative to 
16    examples given in RFC.
17   
18
19 */
20
21 /* Substitution blocks from test examples for GOST R 34.11-94*/
22 gost_subst_block GostR3411_94_TestParamSet = {
23         {0X1,0XF,0XD,0X0,0X5,0X7,0XA,0X4,0X9,0X2,0X3,0XE,0X6,0XB,0X8,0XC},
24         {0XD,0XB,0X4,0X1,0X3,0XF,0X5,0X9,0X0,0XA,0XE,0X7,0X6,0X8,0X2,0XC},
25         {0X4,0XB,0XA,0X0,0X7,0X2,0X1,0XD,0X3,0X6,0X8,0X5,0X9,0XC,0XF,0XE},
26         {0X6,0XC,0X7,0X1,0X5,0XF,0XD,0X8,0X4,0XA,0X9,0XE,0X0,0X3,0XB,0X2},
27         {0X7,0XD,0XA,0X1,0X0,0X8,0X9,0XF,0XE,0X4,0X6,0XC,0XB,0X2,0X5,0X3},
28         {0X5,0X8,0X1,0XD,0XA,0X3,0X4,0X2,0XE,0XF,0XC,0X7,0X6,0X0,0X9,0XB},
29         {0XE,0XB,0X4,0XC,0X6,0XD,0XF,0XA,0X2,0X3,0X8,0X1,0X0,0X7,0X5,0X9},
30         {0X4,0XA,0X9,0X2,0XD,0X8,0X0,0XE,0X6,0XB,0X1,0XC,0X7,0XF,0X5,0X3}
31         };  
32 /* Substitution blocks for hash function 1.2.643.2.9.1.6.1  */
33 gost_subst_block GostR3411_94_CryptoProParamSet= {
34         {0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC},
35         {0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB},
36         {0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3},
37         {0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5},
38         {0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3},
39         {0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD},
40         {0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8},
41         {0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF}
42         } ;
43
44 /* Test paramset from GOST 28147 */
45 gost_subst_block Gost28147_TestParamSet =
46         {
47         {0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8},
48         {0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD},
49         {0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4},
50         {0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4},
51         {0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8},
52         {0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB},
53         {0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5},
54         {0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6}
55         };
56
57
58
59
60 /* 1.2.643.2.2.31.1 */
61 gost_subst_block Gost28147_CryptoProParamSetA= {
62         {0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4},
63         {0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE},
64         {0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6},
65         {0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6},
66         {0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6},
67         {0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9},
68         {0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1},
69         {0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5}
70         };
71 /* 1.2.643.2.2.31.2 */
72 gost_subst_block Gost28147_CryptoProParamSetB= 
73         {
74         {0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC},
75         {0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE},
76         {0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5},
77         {0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3},
78         {0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8},
79         {0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4},
80         {0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE},
81         {0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF}
82         };
83 /* 1.2.643.2.2.31.3 */
84 gost_subst_block Gost28147_CryptoProParamSetC= 
85         {
86         {0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8},
87         {0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7},
88         {0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD},
89         {0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7},
90         {0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4},
91         {0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB},
92         {0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3},
93         {0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3}
94         };
95
96 /* 1.2.643.2.2.31.4 */ 
97 gost_subst_block Gost28147_CryptoProParamSetD=
98         {
99         {0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE},
100         {0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7},
101         {0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6},
102         {0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1},
103         {0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8},
104         {0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2},
105         {0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1},
106         {0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3}
107         };
108
109
110 const byte CryptoProKeyMeshingKey[]={
111         0x69, 0x00, 0x72, 0x22,   0x64, 0xC9, 0x04, 0x23,
112     0x8D, 0x3A, 0xDB, 0x96,   0x46, 0xE9, 0x2A, 0xC4,
113     0x18, 0xFE, 0xAC, 0x94,   0x00, 0xED, 0x07, 0x12,
114     0xC0, 0x86, 0xDC, 0xC2,   0xEF, 0x4C, 0xA9, 0x2B
115         };      
116 /* Initialization of gost_ctx subst blocks*/
117 void kboxinit(gost_ctx *c, const gost_subst_block *b)
118         { 
119         int i; 
120         
121         for (i = 0; i < 256; i++)
122                 {
123                 c->k87[i] = (b->k8[i>>4] <<4 | b->k7 [i &15])<<24;
124                 c->k65[i] = (b->k6[i>>4] << 4 | b->k5 [i &15])<<16;
125                 c->k43[i] = (b->k4[i>>4] <<4  | b->k3 [i &15])<<8;
126                 c->k21[i] = b->k2[i>>4] <<4  | b->k1 [i &15];
127
128                 }
129         }
130
131 /* Part of GOST 28147 algorithm moved into separate function */
132 static word32 f(gost_ctx *c,word32 x) 
133         {
134         x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]| 
135                 c->k43[x>> 8 & 255] | c->k21[x & 255]; 
136         /* Rotate left 11 bits */ 
137         return x<<11 | x>>(32-11);
138         }
139 /* Low-level encryption routine - encrypts one 64 bit block*/
140 void gostcrypt(gost_ctx *c, const byte *in, byte *out)
141         { 
142         register word32 n1, n2; /* As named in the GOST */ 
143         n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); 
144         n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24); 
145         /* Instead of swapping halves, swap names each round */ 
146          
147         n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); 
148         n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); 
149         n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); 
150         n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); 
151   
152         n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
153         n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
154         n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
155         n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
156                                
157         n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
158         n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
159         n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
160         n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
161                                
162         n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
163         n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
164         n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
165         n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
166  
167         out[0] = (n2&0xff);  out[1] = (n2>>8)&0xff; out[2]=(n2>>16)&0xff; out[3]=n2>>24; 
168         out[4] = (n1&0xff);  out[5] = (n1>>8)&0xff; out[6]=(n1>>16)&0xff; out[7]=n1>>24;
169         } 
170 /* Low-level decryption routine. Decrypts one 64-bit block */
171 void gostdecrypt(gost_ctx *c, const byte *in,byte *out)
172         { 
173         register word32 n1, n2; /* As named in the GOST */ 
174         n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); 
175         n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24); 
176         
177         n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); 
178         n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); 
179         n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
180         n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); 
181         
182         n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
183         n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
184         n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
185         n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
186         
187         n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
188         n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
189         n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
190         n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
191         
192         n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
193         n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
194         n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
195         n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
196         out[0] = (n2&0xff);  out[1] = (n2>>8)&0xff; out[2]=(n2>>16)&0xff; out[3]=n2>>24;
197         out[4] = (n1&0xff);  out[5] = (n1>>8)&0xff; out[6]=(n1>>16)&0xff; out[7]=n1>>24;
198         } 
199
200 /* Encrypts several blocks in ECB mode */
201 void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
202         { 
203         int i; 
204         for(i=0;i<blocks;i++)
205                 { 
206                 gostcrypt(c,clear,cipher); 
207                 clear+=8;
208                 cipher+=8;
209                 }
210         }
211 /* Decrypts several blocks in ECB mode */
212 void gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks)
213         { 
214         int i; 
215         for(i=0;i<blocks;i++)
216                 { 
217                 gostdecrypt(c,cipher,clear); 
218                 clear+=8; 
219                 cipher+=8;
220                 }
221         }
222
223 /* Encrypts several full blocks in CFB mode using 8byte IV */
224 void gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher, int blocks)
225         {
226         byte cur_iv[8];
227         byte gamma[8];
228         int i,j;
229         const byte *in;
230         byte *out;
231         memcpy(cur_iv,iv,8);
232         for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8)
233                 {
234                 gostcrypt(ctx,cur_iv,gamma);
235                 for (j=0;j<8;j++)
236                         {
237                         cur_iv[j]=out[j]=in[j]^gamma[j];
238                         }
239                 }       
240         }       
241 /* Decrypts several full blocks in CFB mode using 8byte IV */
242 void gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,  int blocks)
243         {
244         byte cur_iv[8];
245         byte gamma[8];
246         int i,j;
247         const byte *in;
248         byte *out;
249         memcpy(cur_iv,iv,8);
250         for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8)
251                 {
252                 gostcrypt(ctx,cur_iv,gamma);
253                 for (j=0;j<8;j++)
254                         {
255                         out[j]=(cur_iv[j]=in[j])^gamma[j];
256                         }
257                 }       
258         }       
259
260 /* Encrypts one block using specified key */
261 void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock) 
262         {
263         gost_key(c,key);
264         gostcrypt(c,inblock,outblock);
265         }
266
267 /* Set 256 bit  key into context */
268 void gost_key(gost_ctx *c, const byte *k) 
269         { 
270         int i,j; 
271         for(i=0,j=0;i<8;i++,j+=4)
272                 {
273                 c->k[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|(k[j+3]<<24);
274                 }               
275         } 
276
277 /* Retrieve 256-bit key from context */
278 void gost_get_key(gost_ctx *c, byte *k) 
279         {
280         int i,j; 
281         for(i=0,j=0;i<8;i++,j+=4)
282                 {
283                 k[j]=c->k[i]& 0xFF;
284                 k[j+1]=(c->k[i]>>8 )&0xFF;
285                 k[j+2]=(c->k[i]>>16) &0xFF;
286                 k[j+3]=(c->k[i]>>24) &0xFF;
287                 }               
288         }
289
290 /* Initalize context. Provides default value for subst_block */
291 void gost_init(gost_ctx *c, const gost_subst_block *b)
292         {       
293         if(!b)
294                 {
295                 b=&GostR3411_94_TestParamSet;
296                 }       
297         kboxinit(c,b); 
298         }
299
300 /* Cleans up key from context */
301 void gost_destroy(gost_ctx *c)
302         { 
303         int i; for(i=0;i<8;i++) c->k[i]=0; 
304         } 
305
306 /* Compute GOST 28147 mac block 
307  * 
308  * Parameters
309  *   gost_ctx *c - context initalized with substitution blocks and key
310  *   buffer - 8-byte mac state buffer
311  *   block 8-byte block to process.
312  * */
313 void mac_block(gost_ctx *c,byte *buffer,const  byte *block)
314         {
315         register word32 n1, n2; /* As named in the GOST */ 
316         int i;
317         for (i=0; i<8; i++)
318                 {
319                 buffer[i]^=block[i];
320                 }         
321         n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|(buffer[3]<<24); 
322         n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24); 
323         /* Instead of swapping halves, swap names each round */ 
324          
325         n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); 
326         n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); 
327         n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); 
328         n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); 
329   
330         n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
331         n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
332         n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
333         n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
334
335         buffer[0] = (n1&0xff);  buffer[1] = (n1>>8)&0xff; buffer[2]=(n1>>16)&0xff; buffer[3]=n1>>24;
336         buffer[4] = (n2&0xff);  buffer[5] = (n2>>8)&0xff; buffer[6]=(n2>>16)&0xff; buffer[7]=n2>>24;
337         }
338
339 /* Get mac with specified number of bits from MAC state buffer */
340 void get_mac(byte *buffer,int nbits,byte *out)
341         {
342         int nbytes= nbits >> 3;
343         int rembits = nbits & 7;
344         int mask =rembits?((1<rembits)-1):0;
345         int i;
346         for (i=0;i<nbytes;i++) out[i]=buffer[i];
347         if (rembits) out[i]=buffer[i]&mask;
348         }       
349
350 /* Compute mac of specified length (in bits) from data. 
351  * Context should be initialized with key and subst blocks */
352 int gost_mac(gost_ctx *ctx,int mac_len,const unsigned char *data,
353         unsigned int data_len,unsigned char *mac) 
354         {
355         byte buffer[8]={0,0,0,0,0,0,0,0};
356         byte buf2[8];
357         int i;
358         for (i=0;i+8<=data_len;i+=8) 
359                 mac_block(ctx,buffer,data+i);
360         if (i<data_len)
361                 {
362                 memset(buf2,0,8);
363                 memcpy(buf2,data+i,data_len-i);
364                 mac_block(ctx,buffer,buf2);
365                 }       
366         get_mac(buffer,mac_len,mac);
367         return 1;
368         }
369
370 /* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
371 int gost_mac_iv(gost_ctx *ctx,int mac_len,const unsigned char *iv,const unsigned char *data,
372         unsigned int data_len,unsigned char *mac) 
373         {
374         byte buffer[8];
375         byte buf2[8];
376         int i;
377         memcpy (buffer,iv,8);
378         for (i=0;i+8<=data_len;i+=8) 
379                 mac_block(ctx,buffer,data+i);
380         if (i<data_len)
381                 {
382                 memset(buf2,0,8);
383                 memcpy(buf2,data+i,data_len-i);
384                 mac_block(ctx,buffer,buf2);
385                 }       
386         get_mac(buffer,mac_len,mac);
387         return 1;
388         }
389
390 /* Implements key meshing algorithm by modifing ctx and IV in place */
391 void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv)
392         {
393         unsigned char newkey[32],newiv[8];
394         /* Set static keymeshing key */
395         /* "Decrypt" key with keymeshing key */
396         gost_dec(ctx,CryptoProKeyMeshingKey,newkey,4);
397         /* set new key */
398         gost_key(ctx,newkey);
399         /* Encrypt iv with new key */
400         gostcrypt(ctx,iv,newiv);
401         memcpy(iv,newiv,8);
402         }