Line data Source code
1 : /* gostr3411-94.c - GOST R 34.11-94 hash function
2 : * Copyright (C) 2012 Free Software Foundation, Inc.
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 :
21 : #include <config.h>
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 :
26 : #include "g10lib.h"
27 : #include "bithelp.h"
28 : #include "bufhelp.h"
29 : #include "cipher.h"
30 : #include "hash-common.h"
31 :
32 : #include "gost.h"
33 :
34 : #define max(a, b) (((a) > (b)) ? (a) : (b))
35 :
36 : typedef struct {
37 : gcry_md_block_ctx_t bctx;
38 : GOST28147_context hd;
39 : union {
40 : u32 h[8];
41 : byte result[32];
42 : };
43 : u32 sigma[8];
44 : u32 len;
45 : int cryptopro;
46 : } GOSTR3411_CONTEXT;
47 :
48 : static unsigned int
49 : transform (void *c, const unsigned char *data, size_t nblks);
50 :
51 : static void
52 0 : gost3411_init (void *context, unsigned int flags)
53 : {
54 0 : GOSTR3411_CONTEXT *hd = context;
55 :
56 : (void)flags;
57 :
58 0 : memset (&hd->hd, 0, sizeof(hd->hd));
59 0 : memset (hd->h, 0, 32);
60 0 : memset (hd->sigma, 0, 32);
61 :
62 0 : hd->bctx.nblocks = 0;
63 0 : hd->bctx.count = 0;
64 0 : hd->bctx.blocksize = 32;
65 0 : hd->bctx.bwrite = transform;
66 0 : hd->cryptopro = 0;
67 0 : }
68 :
69 : static void
70 0 : gost3411_cp_init (void *context, unsigned int flags)
71 : {
72 0 : GOSTR3411_CONTEXT *hd = context;
73 0 : gost3411_init (context, flags);
74 0 : hd->cryptopro = 1;
75 0 : }
76 :
77 : static void
78 0 : do_p (u32 *p, u32 *u, u32 *v)
79 : {
80 : int k;
81 : u32 t[8];
82 :
83 0 : for (k = 0; k < 8; k++)
84 0 : t[k] = u[k] ^ v[k];
85 :
86 0 : for (k = 0; k < 4; k++)
87 : {
88 0 : p[k+0] = ((t[0] >> (8*k)) & 0xff) << 0 |
89 0 : ((t[2] >> (8*k)) & 0xff) << 8 |
90 0 : ((t[4] >> (8*k)) & 0xff) << 16 |
91 0 : ((t[6] >> (8*k)) & 0xff) << 24;
92 0 : p[k+4] = ((t[1] >> (8*k)) & 0xff) << 0 |
93 0 : ((t[3] >> (8*k)) & 0xff) << 8 |
94 0 : ((t[5] >> (8*k)) & 0xff) << 16 |
95 0 : ((t[7] >> (8*k)) & 0xff) << 24;
96 : }
97 0 : }
98 :
99 : static void
100 0 : do_a (u32 *u)
101 : {
102 : u32 t[2];
103 : int i;
104 0 : memcpy(t, u, 2*4);
105 0 : for (i = 0; i < 6; i++)
106 0 : u[i] = u[i+2];
107 0 : u[6] = u[0] ^ t[0];
108 0 : u[7] = u[1] ^ t[1];
109 0 : }
110 : /* apply do_a twice: 1 2 3 4 -> 3 4 1^2 2^3 */
111 : static void
112 0 : do_a2 (u32 *u)
113 : {
114 : u32 t[4];
115 : int i;
116 0 : memcpy (t, u, 16);
117 0 : memcpy (u, u + 4, 16);
118 0 : for (i = 0; i < 2; i++)
119 : {
120 0 : u[4+i] = t[i] ^ t[i + 2];
121 0 : u[6+i] = u[i] ^ t[i + 2];
122 : }
123 0 : }
124 :
125 : static void
126 0 : do_apply_c2 (u32 *u)
127 : {
128 0 : u[ 0] ^= 0xff00ff00;
129 0 : u[ 1] ^= 0xff00ff00;
130 0 : u[ 2] ^= 0x00ff00ff;
131 0 : u[ 3] ^= 0x00ff00ff;
132 0 : u[ 4] ^= 0x00ffff00;
133 0 : u[ 5] ^= 0xff0000ff;
134 0 : u[ 6] ^= 0x000000ff;
135 0 : u[ 7] ^= 0xff00ffff;
136 0 : }
137 :
138 : #define do_chi_step12(e) \
139 : e[6] ^= ((e[6] >> 16) ^ e[7] ^ (e[7] >> 16) ^ e[4] ^ (e[5] >>16)) & 0xffff;
140 :
141 : #define do_chi_step13(e) \
142 : e[6] ^= ((e[7] ^ (e[7] >> 16) ^ e[0] ^ (e[4] >> 16) ^ e[6]) & 0xffff) << 16;
143 :
144 : #define do_chi_doublestep(e, i) \
145 : e[i] ^= (e[i] >> 16) ^ (e[(i+1)%8] << 16) ^ e[(i+1)%8] ^ (e[(i+1)%8] >> 16) ^ (e[(i+2)%8] << 16) ^ e[(i+6)%8] ^ (e[(i+7)%8] >> 16); \
146 : e[i] ^= (e[i] << 16);
147 :
148 : static void
149 0 : do_chi_submix12 (u32 *e, u32 *x)
150 : {
151 0 : e[6] ^= x[0];
152 0 : e[7] ^= x[1];
153 0 : e[0] ^= x[2];
154 0 : e[1] ^= x[3];
155 0 : e[2] ^= x[4];
156 0 : e[3] ^= x[5];
157 0 : e[4] ^= x[6];
158 0 : e[5] ^= x[7];
159 0 : }
160 :
161 : static void
162 0 : do_chi_submix13 (u32 *e, u32 *x)
163 : {
164 0 : e[6] ^= (x[0] << 16) | (x[7] >> 16);
165 0 : e[7] ^= (x[1] << 16) | (x[0] >> 16);
166 0 : e[0] ^= (x[2] << 16) | (x[1] >> 16);
167 0 : e[1] ^= (x[3] << 16) | (x[2] >> 16);
168 0 : e[2] ^= (x[4] << 16) | (x[3] >> 16);
169 0 : e[3] ^= (x[5] << 16) | (x[4] >> 16);
170 0 : e[4] ^= (x[6] << 16) | (x[5] >> 16);
171 0 : e[5] ^= (x[7] << 16) | (x[6] >> 16);
172 0 : }
173 :
174 : static void
175 0 : do_add (u32 *s, u32 *a)
176 : {
177 0 : u32 carry = 0;
178 : int i;
179 :
180 0 : for (i = 0; i < 8; i++)
181 : {
182 0 : u32 op = carry + a[i];
183 0 : s[i] += op;
184 0 : carry = (a[i] > op) || (op > s[i]);
185 : }
186 0 : }
187 :
188 : static unsigned int
189 0 : do_hash_step (GOSTR3411_CONTEXT *hd, u32 *h, u32 *m)
190 : {
191 : u32 u[8], v[8];
192 : u32 s[8];
193 : u32 k[8];
194 : unsigned int burn;
195 : int i;
196 :
197 0 : memcpy (u, h, 32);
198 0 : memcpy (v, m, 32);
199 :
200 0 : for (i = 0; i < 4; i++) {
201 0 : do_p (k, u, v);
202 :
203 0 : burn = _gcry_gost_enc_data (&hd->hd, k, &s[2*i], &s[2*i+1], h[2*i], h[2*i+1], hd->cryptopro);
204 :
205 0 : do_a (u);
206 0 : if (i == 1)
207 0 : do_apply_c2 (u);
208 0 : do_a2 (v);
209 : }
210 :
211 0 : for (i = 0; i < 5; i++)
212 : {
213 0 : do_chi_doublestep (s, 0);
214 0 : do_chi_doublestep (s, 1);
215 0 : do_chi_doublestep (s, 2);
216 0 : do_chi_doublestep (s, 3);
217 0 : do_chi_doublestep (s, 4);
218 : /* That is in total 12 + 1 + 61 = 74 = 16 * 4 + 10 rounds */
219 0 : if (i == 4)
220 0 : break;
221 0 : do_chi_doublestep (s, 5);
222 0 : if (i == 0)
223 0 : do_chi_submix12(s, m);
224 0 : do_chi_step12 (s);
225 0 : if (i == 0)
226 0 : do_chi_submix13(s, h);
227 0 : do_chi_step13 (s);
228 0 : do_chi_doublestep (s, 7);
229 : }
230 :
231 0 : memcpy (h, s+5, 12);
232 0 : memcpy (h+3, s, 20);
233 :
234 : return /* burn_stack */ 4 * sizeof(void*) /* func call (ret addr + args) */ +
235 0 : 4 * 32 + 2 * sizeof(int) /* stack */ +
236 : max(burn /* _gcry_gost_enc_one */,
237 : sizeof(void*) * 2 /* do_a2 call */ +
238 : 16 + sizeof(int) /* do_a2 stack */ );
239 : }
240 :
241 : static unsigned int
242 0 : transform_blk (void *ctx, const unsigned char *data)
243 : {
244 0 : GOSTR3411_CONTEXT *hd = ctx;
245 : u32 m[8];
246 : unsigned int burn;
247 : int i;
248 :
249 0 : for (i = 0; i < 8; i++)
250 0 : m[i] = buf_get_le32(data + i*4);
251 0 : burn = do_hash_step (hd, hd->h, m);
252 0 : do_add (hd->sigma, m);
253 :
254 0 : return /* burn_stack */ burn + 3 * sizeof(void*) + 32 + 2 * sizeof(void*);
255 : }
256 :
257 :
258 : static unsigned int
259 0 : transform ( void *c, const unsigned char *data, size_t nblks )
260 : {
261 : unsigned int burn;
262 :
263 : do
264 : {
265 0 : burn = transform_blk (c, data);
266 0 : data += 32;
267 : }
268 0 : while (--nblks);
269 :
270 0 : return burn;
271 : }
272 :
273 :
274 : /*
275 : The routine finally terminates the computation and returns the
276 : digest. The handle is prepared for a new cycle, but adding bytes
277 : to the handle will the destroy the returned buffer. Returns: 32
278 : bytes with the message the digest. */
279 : static void
280 0 : gost3411_final (void *context)
281 : {
282 0 : GOSTR3411_CONTEXT *hd = context;
283 0 : size_t padlen = 0;
284 : u32 l[8];
285 : int i;
286 : MD_NBLOCKS_TYPE nblocks;
287 :
288 0 : if (hd->bctx.count > 0)
289 : {
290 0 : padlen = 32 - hd->bctx.count;
291 0 : memset (hd->bctx.buf + hd->bctx.count, 0, padlen);
292 0 : hd->bctx.count += padlen;
293 0 : _gcry_md_block_write (hd, NULL, 0); /* flush */;
294 : }
295 :
296 0 : if (hd->bctx.count != 0)
297 0 : return; /* Something went wrong */
298 :
299 0 : memset (l, 0, 32);
300 :
301 0 : nblocks = hd->bctx.nblocks;
302 0 : if (padlen)
303 : {
304 0 : nblocks --;
305 0 : l[0] = 256 - padlen * 8;
306 : }
307 0 : l[0] |= nblocks << 8;
308 0 : nblocks >>= 24;
309 :
310 0 : for (i = 1; i < 8 && nblocks != 0; i++)
311 : {
312 0 : l[i] = nblocks;
313 0 : nblocks >>= 24;
314 : }
315 :
316 0 : do_hash_step (hd, hd->h, l);
317 0 : do_hash_step (hd, hd->h, hd->sigma);
318 0 : for (i = 0; i < 8; i++)
319 0 : hd->h[i] = le_bswap32(hd->h[i]);
320 : }
321 :
322 : static byte *
323 0 : gost3411_read (void *context)
324 : {
325 0 : GOSTR3411_CONTEXT *hd = context;
326 :
327 0 : return hd->result;
328 : }
329 :
330 : static unsigned char asn[6] = /* Object ID is 1.2.643.2.2.3 */
331 : { 0x2a, 0x85, 0x03, 0x02, 0x02, 0x03 };
332 :
333 : static gcry_md_oid_spec_t oid_spec_gostr3411[] =
334 : {
335 : /* iso.member-body.ru.rans.cryptopro.3 (gostR3411-94-with-gostR3410-2001) */
336 : { "1.2.643.2.2.3" },
337 : /* iso.member-body.ru.rans.cryptopro.9 (gostR3411-94) */
338 : { "1.2.643.2.2.9" },
339 : {NULL},
340 : };
341 :
342 : gcry_md_spec_t _gcry_digest_spec_gost3411_94 =
343 : {
344 : GCRY_MD_GOSTR3411_94, {0, 0},
345 : "GOSTR3411_94", NULL, 0, NULL, 32,
346 : gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read, NULL,
347 : sizeof (GOSTR3411_CONTEXT)
348 : };
349 : gcry_md_spec_t _gcry_digest_spec_gost3411_cp =
350 : {
351 : GCRY_MD_GOSTR3411_CP, {0, 0},
352 : "GOSTR3411_CP", asn, DIM (asn), oid_spec_gostr3411, 32,
353 : gost3411_cp_init, _gcry_md_block_write, gost3411_final, gost3411_read, NULL,
354 : sizeof (GOSTR3411_CONTEXT)
355 : };
|