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