1 /* $OpenBSD: gost2814789.c,v 1.6 2020/09/12 02:45:05 inoguchi 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 <machine/endian.h>
53 
54 #include <string.h>
55 
56 #include <openssl/opensslconf.h>
57 
58 #ifndef OPENSSL_NO_GOST
59 #include <openssl/objects.h>
60 #include <openssl/gost.h>
61 
62 #include "gost_locl.h"
63 
64 static inline unsigned int
65 f(const GOST2814789_KEY *c, unsigned int x)
66 {
67 	return  c->k87[(x>>24) & 255] | c->k65[(x>>16) & 255]|
68 		c->k43[(x>> 8) & 255] | c->k21[(x    ) & 255];
69 }
70 
71 void
72 Gost2814789_encrypt(const unsigned char *in, unsigned char *out,
73     const GOST2814789_KEY *key)
74 {
75 	unsigned int n1, n2; /* As named in the GOST */
76 
77 	c2l(in, n1);
78 	c2l(in, n2);
79 
80 	/* Instead of swapping halves, swap names each round */
81 	n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
82 	n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
83 	n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
84 	n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
85 
86 	n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
87 	n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
88 	n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
89 	n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
90 
91 	n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
92 	n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
93 	n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
94 	n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
95 
96 	n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
97 	n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
98 	n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
99 	n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
100 
101 	l2c(n2, out);
102 	l2c(n1, out);
103 }
104 
105 void
106 Gost2814789_decrypt(const unsigned char *in, unsigned char *out,
107     const GOST2814789_KEY *key)
108 {
109 	unsigned int n1, n2; /* As named in the GOST */
110 
111 	c2l(in, n1);
112 	c2l(in, n2);
113 
114 	/* Instead of swapping halves, swap names each round */
115 	n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
116 	n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
117 	n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
118 	n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
119 
120 	n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
121 	n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
122 	n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
123 	n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
124 
125 	n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
126 	n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
127 	n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
128 	n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
129 
130 	n2 ^= f(key, n1 + key->key[7]); n1 ^= f(key, n2 + key->key[6]);
131 	n2 ^= f(key, n1 + key->key[5]); n1 ^= f(key, n2 + key->key[4]);
132 	n2 ^= f(key, n1 + key->key[3]); n1 ^= f(key, n2 + key->key[2]);
133 	n2 ^= f(key, n1 + key->key[1]); n1 ^= f(key, n2 + key->key[0]);
134 
135 	l2c(n2, out);
136 	l2c(n1, out);
137 }
138 
139 static void
140 Gost2814789_mac(const unsigned char *in, unsigned char *mac,
141     GOST2814789_KEY *key)
142 {
143 	unsigned int n1, n2; /* As named in the GOST */
144 	unsigned char *p;
145 	int i;
146 
147 	for (i = 0; i < 8; i++)
148 		mac[i] ^= in[i];
149 
150 	p = mac;
151 	c2l(p, n1);
152 	c2l(p, n2);
153 
154 	/* Instead of swapping halves, swap names each round */
155 	n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
156 	n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
157 	n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
158 	n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
159 
160 	n2 ^= f(key, n1 + key->key[0]); n1 ^= f(key, n2 + key->key[1]);
161 	n2 ^= f(key, n1 + key->key[2]); n1 ^= f(key, n2 + key->key[3]);
162 	n2 ^= f(key, n1 + key->key[4]); n1 ^= f(key, n2 + key->key[5]);
163 	n2 ^= f(key, n1 + key->key[6]); n1 ^= f(key, n2 + key->key[7]);
164 
165 	p = mac;
166 	l2c(n1, p);
167 	l2c(n2, p);
168 }
169 
170 void
171 Gost2814789_ecb_encrypt(const unsigned char *in, unsigned char *out,
172     GOST2814789_KEY *key, const int enc)
173 {
174 	if (key->key_meshing && key->count == 1024) {
175 		Gost2814789_cryptopro_key_mesh(key);
176 		key->count = 0;
177 	}
178 
179 	if (enc)
180 		Gost2814789_encrypt(in, out, key);
181 	else
182 		Gost2814789_decrypt(in, out, key);
183 }
184 
185 static inline void
186 Gost2814789_encrypt_mesh(unsigned char *iv, GOST2814789_KEY *key)
187 {
188 	if (key->key_meshing && key->count == 1024) {
189 		Gost2814789_cryptopro_key_mesh(key);
190 		Gost2814789_encrypt(iv, iv, key);
191 		key->count = 0;
192 	}
193 	Gost2814789_encrypt(iv, iv, key);
194 	key->count += 8;
195 }
196 
197 static inline void
198 Gost2814789_mac_mesh(const unsigned char *data, unsigned char *mac,
199     GOST2814789_KEY *key)
200 {
201 	if (key->key_meshing && key->count == 1024) {
202 		Gost2814789_cryptopro_key_mesh(key);
203 		key->count = 0;
204 	}
205 	Gost2814789_mac(data, mac, key);
206 	key->count += 8;
207 }
208 
209 void
210 Gost2814789_cfb64_encrypt(const unsigned char *in, unsigned char *out,
211     size_t len, GOST2814789_KEY *key, unsigned char *ivec, int *num,
212     const int enc)
213 {
214 	unsigned int n;
215 	size_t l = 0;
216 
217 	n = *num;
218 
219 	if (enc) {
220 #if !defined(OPENSSL_SMALL_FOOTPRINT)
221 		if (8 % sizeof(size_t) == 0) do { /* always true actually */
222 			while (n && len) {
223 				*(out++) = ivec[n] ^= *(in++);
224 				--len;
225 				n = (n + 1) % 8;
226 			}
227 #ifdef __STRICT_ALIGNMENT
228 			if (((size_t)in | (size_t)out | (size_t)ivec) %
229 			    sizeof(size_t) != 0)
230 				break;
231 #endif
232 			while (len >= 8) {
233 				Gost2814789_encrypt_mesh(ivec, key);
234 				for (; n < 8; n += sizeof(size_t)) {
235 					*(size_t*)(out + n) =
236 					*(size_t*)(ivec + n) ^=
237 					    *(size_t*)(in + n);
238 				}
239 				len -= 8;
240 				out += 8;
241 				in  += 8;
242 				n = 0;
243 			}
244 			if (len) {
245 				Gost2814789_encrypt_mesh(ivec, key);
246 				while (len--) {
247 					out[n] = ivec[n] ^= in[n];
248 					++n;
249 				}
250 			}
251 			*num = n;
252 			return;
253 		} while (0);
254 		/* the rest would be commonly eliminated by x86* compiler */
255 #endif
256 		while (l<len) {
257 			if (n == 0) {
258 				Gost2814789_encrypt_mesh(ivec, key);
259 			}
260 			out[l] = ivec[n] ^= in[l];
261 			++l;
262 			n = (n + 1) % 8;
263 		}
264 		*num = n;
265 	} else {
266 #if !defined(OPENSSL_SMALL_FOOTPRINT)
267 		if (8 % sizeof(size_t) == 0) do { /* always true actually */
268 			while (n && len) {
269 				unsigned char c;
270 
271 				*(out++) = ivec[n] ^ (c = *(in++));
272 				ivec[n] = c;
273 				--len;
274 				n = (n + 1) % 8;
275  			}
276 #ifdef __STRICT_ALIGNMENT
277 			if (((size_t)in | (size_t)out | (size_t)ivec) %
278 			    sizeof(size_t) != 0)
279 				break;
280 #endif
281 			while (len >= 8) {
282 				Gost2814789_encrypt_mesh(ivec, key);
283 				for (; n < 8; n += sizeof(size_t)) {
284 					size_t t = *(size_t*)(in + n);
285 					*(size_t*)(out + n) =
286 					    *(size_t*)(ivec + n) ^ t;
287 					*(size_t*)(ivec + n) = t;
288 				}
289 				len -= 8;
290 				out += 8;
291 				in  += 8;
292 				n = 0;
293 			}
294 			if (len) {
295 				Gost2814789_encrypt_mesh(ivec, key);
296 				while (len--) {
297 					unsigned char c;
298 
299 					out[n] = ivec[n] ^ (c = in[n]);
300 					ivec[n] = c;
301 					++n;
302 				}
303  			}
304 			*num = n;
305 			return;
306 		} while (0);
307 		/* the rest would be commonly eliminated by x86* compiler */
308 #endif
309 		while (l < len) {
310 			unsigned char c;
311 
312 			if (n == 0) {
313 				Gost2814789_encrypt_mesh(ivec, key);
314 			}
315 			out[l] = ivec[n] ^ (c = in[l]); ivec[n] = c;
316 			++l;
317 			n = (n + 1) % 8;
318 		}
319 		*num = n;
320 	}
321 }
322 
323 static inline void
324 Gost2814789_cnt_next(unsigned char *ivec, unsigned char *out,
325     GOST2814789_KEY *key)
326 {
327 	unsigned char *p = ivec, *p2 = ivec;
328 	unsigned int val, val2;
329 
330 	if (key->count == 0)
331 		Gost2814789_encrypt(ivec, ivec, key);
332 
333 	if (key->key_meshing && key->count == 1024) {
334 		Gost2814789_cryptopro_key_mesh(key);
335 		Gost2814789_encrypt(ivec, ivec, key);
336 		key->count = 0;
337 	}
338 
339 	c2l(p, val);
340 	val2 = val + 0x01010101;
341 	l2c(val2, p2);
342 
343 	c2l(p, val);
344 	val2 = val + 0x01010104;
345 	if (val > val2) /* overflow */
346 		val2++;
347 	l2c(val2, p2);
348 
349 	Gost2814789_encrypt(ivec, out, key);
350 	key->count += 8;
351 }
352 
353 void
354 Gost2814789_cnt_encrypt(const unsigned char *in, unsigned char *out, size_t len,
355     GOST2814789_KEY *key, unsigned char *ivec, unsigned char *cnt_buf, int *num)
356 {
357 	unsigned int n;
358 	size_t l = 0;
359 
360 	n = *num;
361 
362 #if !defined(OPENSSL_SMALL_FOOTPRINT)
363 	if (8 % sizeof(size_t) == 0) do { /* always true actually */
364 		while (n && len) {
365 			*(out++) = *(in++) ^ cnt_buf[n];
366 			--len;
367 			n = (n + 1) % 8;
368 		}
369 
370 #ifdef __STRICT_ALIGNMENT
371 		if (((size_t)in | (size_t)out | (size_t)ivec) %
372 		    sizeof(size_t) != 0)
373 			break;
374 #endif
375 		while (len >= 8) {
376 			Gost2814789_cnt_next(ivec, cnt_buf, key);
377 			for (; n < 8; n += sizeof(size_t))
378 				*(size_t *)(out + n) = *(size_t *)(in + n) ^
379 				    *(size_t *)(cnt_buf + n);
380 			len -= 8;
381 			out += 8;
382 			in  += 8;
383 			n = 0;
384 		}
385 		if (len) {
386 			Gost2814789_cnt_next(ivec, cnt_buf, key);
387 			while (len--) {
388 				out[n] = in[n] ^ cnt_buf[n];
389 				++n;
390 			}
391 		}
392 		*num = n;
393 		return;
394 	} while(0);
395 	/* the rest would be commonly eliminated by x86* compiler */
396 #endif
397 	while (l < len) {
398 		if (n==0)
399 			Gost2814789_cnt_next(ivec, cnt_buf, key);
400 		out[l] = in[l] ^ cnt_buf[n];
401 		++l;
402 		n = (n + 1) % 8;
403 	}
404 
405 	*num=n;
406 }
407 
408 int
409 GOST2814789IMIT_Init(GOST2814789IMIT_CTX *c, int nid)
410 {
411 	c->Nl = c->Nh = c->num = 0;
412 	memset(c->mac, 0, 8);
413 	return Gost2814789_set_sbox(&c->cipher, nid);
414 }
415 
416 static void
417 GOST2814789IMIT_block_data_order(GOST2814789IMIT_CTX *ctx,
418     const unsigned char *p, size_t num)
419 {
420 	int i;
421 
422 	for (i = 0; i < num; i++) {
423 		Gost2814789_mac_mesh(p, ctx->mac, &ctx->cipher);
424 		p += 8;
425 	}
426 }
427 
428 #define DATA_ORDER_IS_LITTLE_ENDIAN
429 
430 #define HASH_CBLOCK	GOST2814789IMIT_CBLOCK
431 #define HASH_LONG	GOST2814789IMIT_LONG
432 #define HASH_CTX	GOST2814789IMIT_CTX
433 #define HASH_UPDATE	GOST2814789IMIT_Update
434 #define HASH_TRANSFORM	GOST2814789IMIT_Transform
435 #define HASH_NO_FINAL	1
436 #define HASH_BLOCK_DATA_ORDER	GOST2814789IMIT_block_data_order
437 
438 #include "md32_common.h"
439 
440 int
441 GOST2814789IMIT_Final(unsigned char *md, GOST2814789IMIT_CTX *c)
442 {
443 	if (c->num) {
444 		memset(c->data + c->num, 0, 8 - c->num);
445 		Gost2814789_mac_mesh(c->data, c->mac, &c->cipher);
446 	}
447 	if (c->Nl <= 8 * 8 && c->Nl > 0 && c->Nh == 0) {
448 		memset(c->data, 0, 8);
449 		Gost2814789_mac_mesh(c->data, c->mac, &c->cipher);
450 	}
451 	memcpy(md, c->mac, 4);
452 	return 1;
453 }
454 
455 unsigned char *
456 GOST2814789IMIT(const unsigned char *d, size_t n, unsigned char *md, int nid,
457     const unsigned char *key, const unsigned char *iv)
458 {
459 	GOST2814789IMIT_CTX c;
460 	static unsigned char m[GOST2814789IMIT_LENGTH];
461 
462 	if (md == NULL)
463 		md = m;
464 	GOST2814789IMIT_Init(&c, nid);
465 	memcpy(c.mac, iv, 8);
466 	Gost2814789_set_key(&c.cipher, key, 256);
467 	GOST2814789IMIT_Update(&c, d, n);
468 	GOST2814789IMIT_Final(md, &c);
469 	explicit_bzero(&c, sizeof(c));
470 	return (md);
471 }
472 
473 #endif
474