xref: /dragonfly/crypto/libressl/crypto/gost/gost2814789.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1 /* $OpenBSD: gost2814789.c,v 1.7 2021/11/09 18:40:21 bcook Exp $ */
2 /*
3  * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
4  * Copyright (c) 2005-2006 Cryptocom LTD
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. All advertising materials mentioning features or use of this
19  *    software must display the following acknowledgment:
20  *    "This product includes software developed by the OpenSSL Project
21  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22  *
23  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24  *    endorse or promote products derived from this software without
25  *    prior written permission. For written permission, please contact
26  *    openssl-core@openssl.org.
27  *
28  * 5. Products derived from this software may not be called "OpenSSL"
29  *    nor may "OpenSSL" appear in their names without prior written
30  *    permission of the OpenSSL Project.
31  *
32  * 6. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by the OpenSSL Project
35  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48  * OF THE POSSIBILITY OF SUCH DAMAGE.
49  * ====================================================================
50  */
51 
52 #include <endian.h>
53 #include <string.h>
54 
55 #include <openssl/opensslconf.h>
56 
57 #ifndef OPENSSL_NO_GOST
58 #include <openssl/objects.h>
59 #include <openssl/gost.h>
60 
61 #include "gost_locl.h"
62 
63 static inline unsigned int
f(const GOST2814789_KEY * c,unsigned int x)64 f(const GOST2814789_KEY *c, unsigned int x)
65 {
66           return  c->k87[(x>>24) & 255] | c->k65[(x>>16) & 255]|
67                     c->k43[(x>> 8) & 255] | c->k21[(x    ) & 255];
68 }
69 
70 void
Gost2814789_encrypt(const unsigned char * in,unsigned char * out,const GOST2814789_KEY * key)71 Gost2814789_encrypt(const unsigned char *in, unsigned char *out,
72     const GOST2814789_KEY *key)
73 {
74           unsigned int n1, n2; /* As named in the GOST */
75 
76           c2l(in, n1);
77           c2l(in, n2);
78 
79           /* Instead of swapping halves, swap names each round */
80           n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
81           n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
82           n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
83           n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
84 
85           n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
86           n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
87           n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
88           n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
89 
90           n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
91           n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
92           n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
93           n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
94 
95           n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
96           n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
97           n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
98           n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
99 
100           l2c(n2, out);
101           l2c(n1, out);
102 }
103 
104 void
Gost2814789_decrypt(const unsigned char * in,unsigned char * out,const GOST2814789_KEY * key)105 Gost2814789_decrypt(const unsigned char *in, unsigned char *out,
106     const GOST2814789_KEY *key)
107 {
108           unsigned int n1, n2; /* As named in the GOST */
109 
110           c2l(in, n1);
111           c2l(in, n2);
112 
113           /* Instead of swapping halves, swap names each round */
114           n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
115           n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
116           n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
117           n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
118 
119           n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
120           n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
121           n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
122           n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
123 
124           n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
125           n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
126           n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
127           n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
128 
129           n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
130           n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
131           n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
132           n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
133 
134           l2c(n2, out);
135           l2c(n1, out);
136 }
137 
138 static void
Gost2814789_mac(const unsigned char * in,unsigned char * mac,GOST2814789_KEY * key)139 Gost2814789_mac(const unsigned char *in, unsigned char *mac,
140     GOST2814789_KEY *key)
141 {
142           unsigned int n1, n2; /* As named in the GOST */
143           unsigned char *p;
144           int i;
145 
146           for (i = 0; i < 8; i++)
147                     mac[i] ^= in[i];
148 
149           p = mac;
150           c2l(p, n1);
151           c2l(p, n2);
152 
153           /* Instead of swapping halves, swap names each round */
154           n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
155           n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
156           n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
157           n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
158 
159           n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
160           n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
161           n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
162           n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
163 
164           p = mac;
165           l2c(n1, p);
166           l2c(n2, p);
167 }
168 
169 void
Gost2814789_ecb_encrypt(const unsigned char * in,unsigned char * out,GOST2814789_KEY * key,const int enc)170 Gost2814789_ecb_encrypt(const unsigned char *in, unsigned char *out,
171     GOST2814789_KEY *key, const int enc)
172 {
173           if (key->key_meshing && key->count == 1024) {
174                     Gost2814789_cryptopro_key_mesh(key);
175                     key->count = 0;
176           }
177 
178           if (enc)
179                     Gost2814789_encrypt(in, out, key);
180           else
181                     Gost2814789_decrypt(in, out, key);
182 }
183 
184 static inline void
Gost2814789_encrypt_mesh(unsigned char * iv,GOST2814789_KEY * key)185 Gost2814789_encrypt_mesh(unsigned char *iv, GOST2814789_KEY *key)
186 {
187           if (key->key_meshing && key->count == 1024) {
188                     Gost2814789_cryptopro_key_mesh(key);
189                     Gost2814789_encrypt(iv, iv, key);
190                     key->count = 0;
191           }
192           Gost2814789_encrypt(iv, iv, key);
193           key->count += 8;
194 }
195 
196 static inline void
Gost2814789_mac_mesh(const unsigned char * data,unsigned char * mac,GOST2814789_KEY * key)197 Gost2814789_mac_mesh(const unsigned char *data, unsigned char *mac,
198     GOST2814789_KEY *key)
199 {
200           if (key->key_meshing && key->count == 1024) {
201                     Gost2814789_cryptopro_key_mesh(key);
202                     key->count = 0;
203           }
204           Gost2814789_mac(data, mac, key);
205           key->count += 8;
206 }
207 
208 void
Gost2814789_cfb64_encrypt(const unsigned char * in,unsigned char * out,size_t len,GOST2814789_KEY * key,unsigned char * ivec,int * num,const int enc)209 Gost2814789_cfb64_encrypt(const unsigned char *in, unsigned char *out,
210     size_t len, GOST2814789_KEY *key, unsigned char *ivec, int *num,
211     const int enc)
212 {
213           unsigned int n;
214           size_t l = 0;
215 
216           n = *num;
217 
218           if (enc) {
219 #if !defined(OPENSSL_SMALL_FOOTPRINT)
220                     if (8 % sizeof(size_t) == 0) do { /* always true actually */
221                               while (n && len) {
222                                         *(out++) = ivec[n] ^= *(in++);
223                                         --len;
224                                         n = (n + 1) % 8;
225                               }
226 #ifdef __STRICT_ALIGNMENT
227                               if (((size_t)in | (size_t)out | (size_t)ivec) %
228                                   sizeof(size_t) != 0)
229                                         break;
230 #endif
231                               while (len >= 8) {
232                                         Gost2814789_encrypt_mesh(ivec, key);
233                                         for (; n < 8; n += sizeof(size_t)) {
234                                                   *(size_t*)(out + n) =
235                                                   *(size_t*)(ivec + n) ^=
236                                                       *(size_t*)(in + n);
237                                         }
238                                         len -= 8;
239                                         out += 8;
240                                         in  += 8;
241                                         n = 0;
242                               }
243                               if (len) {
244                                         Gost2814789_encrypt_mesh(ivec, key);
245                                         while (len--) {
246                                                   out[n] = ivec[n] ^= in[n];
247                                                   ++n;
248                                         }
249                               }
250                               *num = n;
251                               return;
252                     } while (0);
253                     /* the rest would be commonly eliminated by x86* compiler */
254 #endif
255                     while (l<len) {
256                               if (n == 0) {
257                                         Gost2814789_encrypt_mesh(ivec, key);
258                               }
259                               out[l] = ivec[n] ^= in[l];
260                               ++l;
261                               n = (n + 1) % 8;
262                     }
263                     *num = n;
264           } else {
265 #if !defined(OPENSSL_SMALL_FOOTPRINT)
266                     if (8 % sizeof(size_t) == 0) do { /* always true actually */
267                               while (n && len) {
268                                         unsigned char c;
269 
270                                         *(out++) = ivec[n] ^ (c = *(in++));
271                                         ivec[n] = c;
272                                         --len;
273                                         n = (n + 1) % 8;
274                               }
275 #ifdef __STRICT_ALIGNMENT
276                               if (((size_t)in | (size_t)out | (size_t)ivec) %
277                                   sizeof(size_t) != 0)
278                                         break;
279 #endif
280                               while (len >= 8) {
281                                         Gost2814789_encrypt_mesh(ivec, key);
282                                         for (; n < 8; n += sizeof(size_t)) {
283                                                   size_t t = *(size_t*)(in + n);
284                                                   *(size_t*)(out + n) =
285                                                       *(size_t*)(ivec + n) ^ t;
286                                                   *(size_t*)(ivec + n) = t;
287                                         }
288                                         len -= 8;
289                                         out += 8;
290                                         in  += 8;
291                                         n = 0;
292                               }
293                               if (len) {
294                                         Gost2814789_encrypt_mesh(ivec, key);
295                                         while (len--) {
296                                                   unsigned char c;
297 
298                                                   out[n] = ivec[n] ^ (c = in[n]);
299                                                   ivec[n] = c;
300                                                   ++n;
301                                         }
302                               }
303                               *num = n;
304                               return;
305                     } while (0);
306                     /* the rest would be commonly eliminated by x86* compiler */
307 #endif
308                     while (l < len) {
309                               unsigned char c;
310 
311                               if (n == 0) {
312                                         Gost2814789_encrypt_mesh(ivec, key);
313                               }
314                               out[l] = ivec[n] ^ (c = in[l]); ivec[n] = c;
315                               ++l;
316                               n = (n + 1) % 8;
317                     }
318                     *num = n;
319           }
320 }
321 
322 static inline void
Gost2814789_cnt_next(unsigned char * ivec,unsigned char * out,GOST2814789_KEY * key)323 Gost2814789_cnt_next(unsigned char *ivec, unsigned char *out,
324     GOST2814789_KEY *key)
325 {
326           unsigned char *p = ivec, *p2 = ivec;
327           unsigned int val, val2;
328 
329           if (key->count == 0)
330                     Gost2814789_encrypt(ivec, ivec, key);
331 
332           if (key->key_meshing && key->count == 1024) {
333                     Gost2814789_cryptopro_key_mesh(key);
334                     Gost2814789_encrypt(ivec, ivec, key);
335                     key->count = 0;
336           }
337 
338           c2l(p, val);
339           val2 = val + 0x01010101;
340           l2c(val2, p2);
341 
342           c2l(p, val);
343           val2 = val + 0x01010104;
344           if (val > val2) /* overflow */
345                     val2++;
346           l2c(val2, p2);
347 
348           Gost2814789_encrypt(ivec, out, key);
349           key->count += 8;
350 }
351 
352 void
Gost2814789_cnt_encrypt(const unsigned char * in,unsigned char * out,size_t len,GOST2814789_KEY * key,unsigned char * ivec,unsigned char * cnt_buf,int * num)353 Gost2814789_cnt_encrypt(const unsigned char *in, unsigned char *out, size_t len,
354     GOST2814789_KEY *key, unsigned char *ivec, unsigned char *cnt_buf, int *num)
355 {
356           unsigned int n;
357           size_t l = 0;
358 
359           n = *num;
360 
361 #if !defined(OPENSSL_SMALL_FOOTPRINT)
362           if (8 % sizeof(size_t) == 0) do { /* always true actually */
363                     while (n && len) {
364                               *(out++) = *(in++) ^ cnt_buf[n];
365                               --len;
366                               n = (n + 1) % 8;
367                     }
368 
369 #ifdef __STRICT_ALIGNMENT
370                     if (((size_t)in | (size_t)out | (size_t)ivec) %
371                         sizeof(size_t) != 0)
372                               break;
373 #endif
374                     while (len >= 8) {
375                               Gost2814789_cnt_next(ivec, cnt_buf, key);
376                               for (; n < 8; n += sizeof(size_t))
377                                         *(size_t *)(out + n) = *(size_t *)(in + n) ^
378                                             *(size_t *)(cnt_buf + n);
379                               len -= 8;
380                               out += 8;
381                               in  += 8;
382                               n = 0;
383                     }
384                     if (len) {
385                               Gost2814789_cnt_next(ivec, cnt_buf, key);
386                               while (len--) {
387                                         out[n] = in[n] ^ cnt_buf[n];
388                                         ++n;
389                               }
390                     }
391                     *num = n;
392                     return;
393           } while(0);
394           /* the rest would be commonly eliminated by x86* compiler */
395 #endif
396           while (l < len) {
397                     if (n==0)
398                               Gost2814789_cnt_next(ivec, cnt_buf, key);
399                     out[l] = in[l] ^ cnt_buf[n];
400                     ++l;
401                     n = (n + 1) % 8;
402           }
403 
404           *num=n;
405 }
406 
407 int
GOST2814789IMIT_Init(GOST2814789IMIT_CTX * c,int nid)408 GOST2814789IMIT_Init(GOST2814789IMIT_CTX *c, int nid)
409 {
410           c->Nl = c->Nh = c->num = 0;
411           memset(c->mac, 0, 8);
412           return Gost2814789_set_sbox(&c->cipher, nid);
413 }
414 
415 static void
GOST2814789IMIT_block_data_order(GOST2814789IMIT_CTX * ctx,const unsigned char * p,size_t num)416 GOST2814789IMIT_block_data_order(GOST2814789IMIT_CTX *ctx,
417     const unsigned char *p, size_t num)
418 {
419           int i;
420 
421           for (i = 0; i < num; i++) {
422                     Gost2814789_mac_mesh(p, ctx->mac, &ctx->cipher);
423                     p += 8;
424           }
425 }
426 
427 #define DATA_ORDER_IS_LITTLE_ENDIAN
428 
429 #define HASH_CBLOCK GOST2814789IMIT_CBLOCK
430 #define HASH_LONG   GOST2814789IMIT_LONG
431 #define HASH_CTX    GOST2814789IMIT_CTX
432 #define HASH_UPDATE GOST2814789IMIT_Update
433 #define HASH_TRANSFORM        GOST2814789IMIT_Transform
434 #define HASH_NO_FINAL         1
435 #define HASH_BLOCK_DATA_ORDER GOST2814789IMIT_block_data_order
436 
437 #include "md32_common.h"
438 
439 int
GOST2814789IMIT_Final(unsigned char * md,GOST2814789IMIT_CTX * c)440 GOST2814789IMIT_Final(unsigned char *md, GOST2814789IMIT_CTX *c)
441 {
442           if (c->num) {
443                     memset(c->data + c->num, 0, 8 - c->num);
444                     Gost2814789_mac_mesh(c->data, c->mac, &c->cipher);
445           }
446           if (c->Nl <= 8 * 8 && c->Nl > 0 && c->Nh == 0) {
447                     memset(c->data, 0, 8);
448                     Gost2814789_mac_mesh(c->data, c->mac, &c->cipher);
449           }
450           memcpy(md, c->mac, 4);
451           return 1;
452 }
453 
454 unsigned char *
GOST2814789IMIT(const unsigned char * d,size_t n,unsigned char * md,int nid,const unsigned char * key,const unsigned char * iv)455 GOST2814789IMIT(const unsigned char *d, size_t n, unsigned char *md, int nid,
456     const unsigned char *key, const unsigned char *iv)
457 {
458           GOST2814789IMIT_CTX c;
459           static unsigned char m[GOST2814789IMIT_LENGTH];
460 
461           if (md == NULL)
462                     md = m;
463           GOST2814789IMIT_Init(&c, nid);
464           memcpy(c.mac, iv, 8);
465           Gost2814789_set_key(&c.cipher, key, 256);
466           GOST2814789IMIT_Update(&c, d, n);
467           GOST2814789IMIT_Final(md, &c);
468           explicit_bzero(&c, sizeof(c));
469           return (md);
470 }
471 
472 #endif
473