/src/libgcrypt/cipher/gost28147.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* gost28147.c - GOST 28147-89 implementation for Libgcrypt |
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 | | /* GOST 28147-89 defines several modes of encryption: |
21 | | * - ECB which should be used only for key transfer |
22 | | * - CFB mode |
23 | | * - OFB-like mode with additional transformation on keystream |
24 | | * RFC 5830 names this 'counter encryption' mode |
25 | | * Original GOST text uses the term 'gammirovanie' |
26 | | * - MAC mode ('imitovstavka') |
27 | | * |
28 | | * This implementation handles ECB and CFB modes via usual libgcrypt handling. |
29 | | * OFB-like modes are unsupported. |
30 | | */ |
31 | | |
32 | | #include <config.h> |
33 | | #include "types.h" |
34 | | #include "g10lib.h" |
35 | | #include "cipher.h" |
36 | | #include "mac-internal.h" |
37 | | #include "bufhelp.h" |
38 | | #include "cipher-internal.h" |
39 | | |
40 | | #include "gost.h" |
41 | | #include "gost-sb.h" |
42 | | |
43 | | static void |
44 | | gost_do_set_sbox (GOST28147_context *ctx, unsigned int index) |
45 | 0 | { |
46 | 0 | ctx->sbox = gost_oid_map[index].sbox; |
47 | 0 | ctx->mesh_limit = gost_oid_map[index].keymeshing ? 1024 : 0; |
48 | 0 | } |
49 | | |
50 | | static gcry_err_code_t |
51 | | gost_setkey (void *c, const byte *key, unsigned keylen, |
52 | | cipher_bulk_ops_t *bulk_ops) |
53 | 0 | { |
54 | 0 | int i; |
55 | 0 | GOST28147_context *ctx = c; |
56 | |
|
57 | 0 | (void)bulk_ops; |
58 | |
|
59 | 0 | if (keylen != 256 / 8) |
60 | 0 | return GPG_ERR_INV_KEYLEN; |
61 | | |
62 | 0 | if (!ctx->sbox) |
63 | 0 | gost_do_set_sbox (ctx, 0); |
64 | |
|
65 | 0 | for (i = 0; i < 8; i++) |
66 | 0 | { |
67 | 0 | ctx->key[i] = buf_get_le32(&key[4*i]); |
68 | 0 | } |
69 | |
|
70 | 0 | ctx->mesh_counter = 0; |
71 | |
|
72 | 0 | return GPG_ERR_NO_ERROR; |
73 | 0 | } |
74 | | |
75 | | static inline u32 |
76 | | gost_val (u32 subkey, u32 cm1, const u32 *sbox) |
77 | 0 | { |
78 | 0 | cm1 += subkey; |
79 | 0 | cm1 = sbox[0*256 + ((cm1 >> 0) & 0xff)] | |
80 | 0 | sbox[1*256 + ((cm1 >> 8) & 0xff)] | |
81 | 0 | sbox[2*256 + ((cm1 >> 16) & 0xff)] | |
82 | 0 | sbox[3*256 + ((cm1 >> 24) & 0xff)]; |
83 | 0 | return cm1; |
84 | 0 | } |
85 | | |
86 | | static unsigned int |
87 | | _gost_encrypt_data (const u32 *sbox, const u32 *key, u32 *o1, u32 *o2, u32 n1, u32 n2) |
88 | 0 | { |
89 | 0 | n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); |
90 | 0 | n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); |
91 | 0 | n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); |
92 | 0 | n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); |
93 | |
|
94 | 0 | n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); |
95 | 0 | n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); |
96 | 0 | n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); |
97 | 0 | n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); |
98 | |
|
99 | 0 | n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); |
100 | 0 | n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); |
101 | 0 | n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); |
102 | 0 | n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); |
103 | |
|
104 | 0 | n2 ^= gost_val (key[7], n1, sbox); n1 ^= gost_val (key[6], n2, sbox); |
105 | 0 | n2 ^= gost_val (key[5], n1, sbox); n1 ^= gost_val (key[4], n2, sbox); |
106 | 0 | n2 ^= gost_val (key[3], n1, sbox); n1 ^= gost_val (key[2], n2, sbox); |
107 | 0 | n2 ^= gost_val (key[1], n1, sbox); n1 ^= gost_val (key[0], n2, sbox); |
108 | |
|
109 | 0 | *o1 = n2; |
110 | 0 | *o2 = n1; |
111 | |
|
112 | 0 | return /* burn_stack */ 4*sizeof(void*) /* func call */ + |
113 | 0 | 3*sizeof(void*) /* stack */ + |
114 | 0 | 4*sizeof(void*) /* gost_val call */; |
115 | 0 | } |
116 | | |
117 | | static unsigned int |
118 | | gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf) |
119 | 0 | { |
120 | 0 | GOST28147_context *ctx = c; |
121 | 0 | u32 n1, n2; |
122 | 0 | unsigned int burn; |
123 | |
|
124 | 0 | n1 = buf_get_le32 (inbuf); |
125 | 0 | n2 = buf_get_le32 (inbuf+4); |
126 | |
|
127 | 0 | burn = _gost_encrypt_data(ctx->sbox, ctx->key, &n1, &n2, n1, n2); |
128 | |
|
129 | 0 | buf_put_le32 (outbuf+0, n1); |
130 | 0 | buf_put_le32 (outbuf+4, n2); |
131 | |
|
132 | 0 | return /* burn_stack */ burn + 6*sizeof(void*) /* func call */; |
133 | 0 | } |
134 | | |
135 | | unsigned int _gcry_gost_enc_data (const u32 *key, |
136 | | u32 *o1, u32 *o2, u32 n1, u32 n2, int cryptopro) |
137 | 0 | { |
138 | 0 | const u32 *sbox; |
139 | 0 | if (cryptopro) |
140 | 0 | sbox = sbox_CryptoPro_3411; |
141 | 0 | else |
142 | 0 | sbox = sbox_test_3411; |
143 | 0 | return _gost_encrypt_data (sbox, key, o1, o2, n1, n2) + 7 * sizeof(void *); |
144 | 0 | } |
145 | | |
146 | | static unsigned int |
147 | | gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf) |
148 | 0 | { |
149 | 0 | GOST28147_context *ctx = c; |
150 | 0 | u32 n1, n2; |
151 | 0 | const u32 *sbox = ctx->sbox; |
152 | |
|
153 | 0 | n1 = buf_get_le32 (inbuf); |
154 | 0 | n2 = buf_get_le32 (inbuf+4); |
155 | |
|
156 | 0 | n2 ^= gost_val (ctx->key[0], n1, sbox); n1 ^= gost_val (ctx->key[1], n2, sbox); |
157 | 0 | n2 ^= gost_val (ctx->key[2], n1, sbox); n1 ^= gost_val (ctx->key[3], n2, sbox); |
158 | 0 | n2 ^= gost_val (ctx->key[4], n1, sbox); n1 ^= gost_val (ctx->key[5], n2, sbox); |
159 | 0 | n2 ^= gost_val (ctx->key[6], n1, sbox); n1 ^= gost_val (ctx->key[7], n2, sbox); |
160 | |
|
161 | 0 | n2 ^= gost_val (ctx->key[7], n1, sbox); n1 ^= gost_val (ctx->key[6], n2, sbox); |
162 | 0 | n2 ^= gost_val (ctx->key[5], n1, sbox); n1 ^= gost_val (ctx->key[4], n2, sbox); |
163 | 0 | n2 ^= gost_val (ctx->key[3], n1, sbox); n1 ^= gost_val (ctx->key[2], n2, sbox); |
164 | 0 | n2 ^= gost_val (ctx->key[1], n1, sbox); n1 ^= gost_val (ctx->key[0], n2, sbox); |
165 | |
|
166 | 0 | n2 ^= gost_val (ctx->key[7], n1, sbox); n1 ^= gost_val (ctx->key[6], n2, sbox); |
167 | 0 | n2 ^= gost_val (ctx->key[5], n1, sbox); n1 ^= gost_val (ctx->key[4], n2, sbox); |
168 | 0 | n2 ^= gost_val (ctx->key[3], n1, sbox); n1 ^= gost_val (ctx->key[2], n2, sbox); |
169 | 0 | n2 ^= gost_val (ctx->key[1], n1, sbox); n1 ^= gost_val (ctx->key[0], n2, sbox); |
170 | |
|
171 | 0 | n2 ^= gost_val (ctx->key[7], n1, sbox); n1 ^= gost_val (ctx->key[6], n2, sbox); |
172 | 0 | n2 ^= gost_val (ctx->key[5], n1, sbox); n1 ^= gost_val (ctx->key[4], n2, sbox); |
173 | 0 | n2 ^= gost_val (ctx->key[3], n1, sbox); n1 ^= gost_val (ctx->key[2], n2, sbox); |
174 | 0 | n2 ^= gost_val (ctx->key[1], n1, sbox); n1 ^= gost_val (ctx->key[0], n2, sbox); |
175 | |
|
176 | 0 | buf_put_le32 (outbuf+0, n2); |
177 | 0 | buf_put_le32 (outbuf+4, n1); |
178 | |
|
179 | 0 | return /* burn_stack */ 4*sizeof(void*) /* func call */ + |
180 | 0 | 3*sizeof(void*) /* stack */ + |
181 | 0 | 4*sizeof(void*) /* gost_val call */; |
182 | 0 | } |
183 | | |
184 | | static gpg_err_code_t |
185 | | gost_set_sbox (GOST28147_context *ctx, const char *oid) |
186 | 0 | { |
187 | 0 | int i; |
188 | |
|
189 | 0 | for (i = 0; gost_oid_map[i].oid; i++) |
190 | 0 | { |
191 | 0 | if (!strcmp(gost_oid_map[i].oid, oid)) |
192 | 0 | { |
193 | 0 | gost_do_set_sbox (ctx, i); |
194 | 0 | return 0; |
195 | 0 | } |
196 | 0 | } |
197 | 0 | return GPG_ERR_VALUE_NOT_FOUND; |
198 | 0 | } |
199 | | |
200 | | static gpg_err_code_t |
201 | | gost_set_extra_info (void *c, int what, const void *buffer, size_t buflen) |
202 | 0 | { |
203 | 0 | GOST28147_context *ctx = c; |
204 | 0 | gpg_err_code_t ec = 0; |
205 | |
|
206 | 0 | (void)buffer; |
207 | 0 | (void)buflen; |
208 | |
|
209 | 0 | switch (what) |
210 | 0 | { |
211 | 0 | case GCRYCTL_SET_SBOX: |
212 | 0 | ec = gost_set_sbox (ctx, buffer); |
213 | 0 | break; |
214 | | |
215 | 0 | default: |
216 | 0 | ec = GPG_ERR_INV_OP; |
217 | 0 | break; |
218 | 0 | } |
219 | 0 | return ec; |
220 | 0 | } |
221 | | |
222 | | static const byte CryptoProKeyMeshingKey[] = { |
223 | | 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23, |
224 | | 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4, |
225 | | 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12, |
226 | | 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B |
227 | | }; |
228 | | |
229 | | /* Implements key meshing algorithm by modifing ctx and returning new IV. |
230 | | Thanks to Dmitry Belyavskiy. */ |
231 | | static void |
232 | | cryptopro_key_meshing (GOST28147_context *ctx) |
233 | 0 | { |
234 | 0 | unsigned char newkey[32]; |
235 | 0 | unsigned int i; |
236 | | |
237 | | /* "Decrypt" the static keymeshing key */ |
238 | 0 | for (i = 0; i < 4; i++) |
239 | 0 | { |
240 | 0 | gost_decrypt_block (ctx, newkey + i*8, CryptoProKeyMeshingKey + i*8); |
241 | 0 | } |
242 | | |
243 | | /* Set new key */ |
244 | 0 | for (i = 0; i < 8; i++) |
245 | 0 | { |
246 | 0 | ctx->key[i] = buf_get_le32(&newkey[4*i]); |
247 | 0 | } |
248 | |
|
249 | 0 | ctx->mesh_counter = 0; |
250 | 0 | } |
251 | | |
252 | | static unsigned int |
253 | | gost_encrypt_block_mesh (void *c, byte *outbuf, const byte *inbuf) |
254 | 0 | { |
255 | 0 | GOST28147_context *ctx = c; |
256 | 0 | u32 n1, n2; |
257 | 0 | unsigned int burn; |
258 | |
|
259 | 0 | n1 = buf_get_le32 (inbuf); |
260 | 0 | n2 = buf_get_le32 (inbuf+4); |
261 | |
|
262 | 0 | if (ctx->mesh_limit && (ctx->mesh_counter == ctx->mesh_limit)) |
263 | 0 | { |
264 | 0 | cryptopro_key_meshing (ctx); |
265 | | /* Yes, encrypt twice: once for KeyMeshing procedure per RFC 4357, |
266 | | * once for block encryption */ |
267 | 0 | _gost_encrypt_data(ctx->sbox, ctx->key, &n1, &n2, n1, n2); |
268 | 0 | } |
269 | |
|
270 | 0 | burn = _gost_encrypt_data(ctx->sbox, ctx->key, &n1, &n2, n1, n2); |
271 | |
|
272 | 0 | ctx->mesh_counter += 8; |
273 | |
|
274 | 0 | buf_put_le32 (outbuf+0, n1); |
275 | 0 | buf_put_le32 (outbuf+4, n2); |
276 | |
|
277 | 0 | return /* burn_stack */ burn + 6*sizeof(void*) /* func call */; |
278 | 0 | } |
279 | | |
280 | | static const gcry_cipher_oid_spec_t oids_gost28147_mesh[] = |
281 | | { |
282 | | { "1.2.643.2.2.21", GCRY_CIPHER_MODE_CFB }, |
283 | | /* { "1.2.643.2.2.31.0", GCRY_CIPHER_MODE_CNTGOST }, */ |
284 | | { "1.2.643.2.2.31.1", GCRY_CIPHER_MODE_CFB }, |
285 | | { "1.2.643.2.2.31.2", GCRY_CIPHER_MODE_CFB }, |
286 | | { "1.2.643.2.2.31.3", GCRY_CIPHER_MODE_CFB }, |
287 | | { "1.2.643.2.2.31.4", GCRY_CIPHER_MODE_CFB }, |
288 | | { NULL } |
289 | | }; |
290 | | |
291 | | gcry_cipher_spec_t _gcry_cipher_spec_gost28147 = |
292 | | { |
293 | | GCRY_CIPHER_GOST28147, {0, 0}, |
294 | | "GOST28147", NULL, NULL, 8, 256, |
295 | | sizeof (GOST28147_context), |
296 | | gost_setkey, |
297 | | gost_encrypt_block, |
298 | | gost_decrypt_block, |
299 | | NULL, NULL, NULL, gost_set_extra_info, |
300 | | }; |
301 | | |
302 | | /* Meshing is used only for CFB, so no need to have separate |
303 | | * gost_decrypt_block_mesh. |
304 | | * Moreover key meshing is specified as encrypting the block (IV). Decrypting |
305 | | * it afterwards would be meaningless. */ |
306 | | gcry_cipher_spec_t _gcry_cipher_spec_gost28147_mesh = |
307 | | { |
308 | | GCRY_CIPHER_GOST28147_MESH, {0, 0}, |
309 | | "GOST28147_MESH", NULL, oids_gost28147_mesh, 8, 256, |
310 | | sizeof (GOST28147_context), |
311 | | gost_setkey, |
312 | | gost_encrypt_block_mesh, |
313 | | gost_decrypt_block, |
314 | | NULL, NULL, NULL, gost_set_extra_info, |
315 | | }; |
316 | | |
317 | | static gcry_err_code_t |
318 | | gost_imit_open (gcry_mac_hd_t h) |
319 | 0 | { |
320 | 0 | memset(&h->u.imit, 0, sizeof(h->u.imit)); |
321 | 0 | return 0; |
322 | 0 | } |
323 | | |
324 | | static void |
325 | | gost_imit_close (gcry_mac_hd_t h) |
326 | 0 | { |
327 | 0 | (void) h; |
328 | 0 | } |
329 | | |
330 | | static gcry_err_code_t |
331 | | gost_imit_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) |
332 | 0 | { |
333 | 0 | int i; |
334 | |
|
335 | 0 | if (keylen != 256 / 8) |
336 | 0 | return GPG_ERR_INV_KEYLEN; |
337 | | |
338 | 0 | if (!h->u.imit.ctx.sbox) |
339 | 0 | h->u.imit.ctx.sbox = sbox_CryptoPro_A; |
340 | |
|
341 | 0 | for (i = 0; i < 8; i++) |
342 | 0 | { |
343 | 0 | h->u.imit.ctx.key[i] = buf_get_le32(&key[4*i]); |
344 | 0 | } |
345 | |
|
346 | 0 | return 0; |
347 | 0 | } |
348 | | |
349 | | static gcry_err_code_t |
350 | | gost_imit_setiv (gcry_mac_hd_t h, |
351 | | const unsigned char *iv, |
352 | | size_t ivlen) |
353 | 0 | { |
354 | 0 | if (ivlen != 8) |
355 | 0 | return GPG_ERR_INV_LENGTH; |
356 | | |
357 | 0 | h->u.imit.n1 = buf_get_le32 (iv + 0); |
358 | 0 | h->u.imit.n2 = buf_get_le32 (iv + 4); |
359 | |
|
360 | 0 | return 0; |
361 | 0 | } |
362 | | |
363 | | static gcry_err_code_t |
364 | | gost_imit_reset (gcry_mac_hd_t h) |
365 | 0 | { |
366 | 0 | h->u.imit.n1 = h->u.imit.n2 = 0; |
367 | 0 | h->u.imit.unused = 0; |
368 | 0 | return 0; |
369 | 0 | } |
370 | | |
371 | | static unsigned int |
372 | | _gost_imit_block (const u32 *sbox, const u32 *key, u32 *o1, u32 *o2, u32 n1, u32 n2) |
373 | 0 | { |
374 | 0 | n1 ^= *o1; |
375 | 0 | n2 ^= *o2; |
376 | |
|
377 | 0 | n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); |
378 | 0 | n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); |
379 | 0 | n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); |
380 | 0 | n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); |
381 | |
|
382 | 0 | n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); |
383 | 0 | n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); |
384 | 0 | n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); |
385 | 0 | n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); |
386 | |
|
387 | 0 | *o1 = n1; |
388 | 0 | *o2 = n2; |
389 | |
|
390 | 0 | return /* burn_stack */ 4*sizeof(void*) /* func call */ + |
391 | 0 | 3*sizeof(void*) /* stack */ + |
392 | 0 | 4*sizeof(void*) /* gost_val call */; |
393 | 0 | } |
394 | | |
395 | | static inline unsigned int |
396 | | gost_imit_block (GOST28147_context *ctx, u32 *n1, u32 *n2, const unsigned char *buf) |
397 | 0 | { |
398 | 0 | if (ctx->mesh_limit && (ctx->mesh_counter == ctx->mesh_limit)) |
399 | 0 | cryptopro_key_meshing (ctx); |
400 | |
|
401 | 0 | return _gost_imit_block (ctx->sbox, ctx->key, |
402 | 0 | n1, n2, |
403 | 0 | buf_get_le32 (buf+0), |
404 | 0 | buf_get_le32 (buf+4)); |
405 | 0 | } |
406 | | |
407 | | static gcry_err_code_t |
408 | | gost_imit_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) |
409 | 0 | { |
410 | 0 | const int blocksize = 8; |
411 | 0 | unsigned int burn = 0; |
412 | 0 | if (!buflen || !buf) |
413 | 0 | return GPG_ERR_NO_ERROR; |
414 | | |
415 | 0 | if (h->u.imit.unused) |
416 | 0 | { |
417 | 0 | for (; buflen && h->u.imit.unused < blocksize; buflen --) |
418 | 0 | h->u.imit.lastiv[h->u.imit.unused++] = *buf++; |
419 | |
|
420 | 0 | if (h->u.imit.unused < blocksize) |
421 | 0 | return GPG_ERR_NO_ERROR; |
422 | | |
423 | 0 | h->u.imit.count ++; |
424 | 0 | burn = gost_imit_block (&h->u.imit.ctx, |
425 | 0 | &h->u.imit.n1, &h->u.imit.n2, |
426 | 0 | h->u.imit.lastiv); |
427 | |
|
428 | 0 | h->u.imit.unused = 0; |
429 | 0 | } |
430 | | |
431 | 0 | while (buflen >= blocksize) |
432 | 0 | { |
433 | 0 | h->u.imit.count ++; |
434 | 0 | burn = gost_imit_block (&h->u.imit.ctx, |
435 | 0 | &h->u.imit.n1, &h->u.imit.n2, |
436 | 0 | buf); |
437 | 0 | buf += blocksize; |
438 | 0 | buflen -= blocksize; |
439 | 0 | } |
440 | |
|
441 | 0 | for (; buflen; buflen--) |
442 | 0 | h->u.imit.lastiv[h->u.imit.unused++] = *buf++; |
443 | |
|
444 | 0 | _gcry_burn_stack (burn); |
445 | |
|
446 | 0 | return GPG_ERR_NO_ERROR; |
447 | 0 | } |
448 | | |
449 | | static void |
450 | | gost_imit_finish (gcry_mac_hd_t h) |
451 | 0 | { |
452 | 0 | static const unsigned char zero[8] = {0}; |
453 | | |
454 | | /* Fill till full block */ |
455 | 0 | if (h->u.imit.unused) |
456 | 0 | gost_imit_write(h, zero, 8 - h->u.imit.unused); |
457 | |
|
458 | 0 | if (h->u.imit.count == 1) |
459 | 0 | gost_imit_write(h, zero, 8); |
460 | 0 | } |
461 | | |
462 | | static gcry_err_code_t |
463 | | gost_imit_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) |
464 | 0 | { |
465 | 0 | unsigned int dlen = 8; |
466 | 0 | unsigned char digest[8]; |
467 | |
|
468 | 0 | gost_imit_finish (h); |
469 | |
|
470 | 0 | buf_put_le32 (digest+0, h->u.imit.n1); |
471 | 0 | buf_put_le32 (digest+4, h->u.imit.n2); |
472 | |
|
473 | 0 | if (*outlen <= dlen) |
474 | 0 | buf_cpy (outbuf, digest, *outlen); |
475 | 0 | else |
476 | 0 | { |
477 | 0 | buf_cpy (outbuf, digest, dlen); |
478 | 0 | *outlen = dlen; |
479 | 0 | } |
480 | 0 | return 0; |
481 | 0 | } |
482 | | |
483 | | static gcry_err_code_t |
484 | | gost_imit_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) |
485 | 0 | { |
486 | 0 | unsigned char tbuf[8]; |
487 | |
|
488 | 0 | gost_imit_finish (h); |
489 | |
|
490 | 0 | buf_put_le32 (tbuf+0, h->u.imit.n1); |
491 | 0 | buf_put_le32 (tbuf+4, h->u.imit.n2); |
492 | |
|
493 | 0 | return buf_eq_const(tbuf, buf, buflen) ? |
494 | 0 | GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; |
495 | 0 | } |
496 | | |
497 | | static unsigned int |
498 | | gost_imit_get_maclen (int algo) |
499 | 0 | { |
500 | 0 | (void) algo; |
501 | 0 | return 4; /* or 8 */ |
502 | 0 | } |
503 | | |
504 | | |
505 | | static unsigned int |
506 | | gost_imit_get_keylen (int algo) |
507 | 0 | { |
508 | 0 | (void) algo; |
509 | 0 | return 256 / 8; |
510 | 0 | } |
511 | | |
512 | | static gpg_err_code_t |
513 | | gost_imit_set_extra_info (gcry_mac_hd_t hd, int what, const void *buffer, size_t buflen) |
514 | 0 | { |
515 | 0 | gpg_err_code_t ec = 0; |
516 | |
|
517 | 0 | (void)buffer; |
518 | 0 | (void)buflen; |
519 | |
|
520 | 0 | switch (what) |
521 | 0 | { |
522 | 0 | case GCRYCTL_SET_SBOX: |
523 | 0 | ec = gost_set_sbox (&hd->u.imit.ctx, buffer); |
524 | 0 | break; |
525 | | |
526 | 0 | default: |
527 | 0 | ec = GPG_ERR_INV_OP; |
528 | 0 | break; |
529 | 0 | } |
530 | 0 | return ec; |
531 | 0 | } |
532 | | |
533 | | |
534 | | static gcry_mac_spec_ops_t gost_imit_ops = { |
535 | | gost_imit_open, |
536 | | gost_imit_close, |
537 | | gost_imit_setkey, |
538 | | gost_imit_setiv, |
539 | | gost_imit_reset, |
540 | | gost_imit_write, |
541 | | gost_imit_read, |
542 | | gost_imit_verify, |
543 | | gost_imit_get_maclen, |
544 | | gost_imit_get_keylen, |
545 | | gost_imit_set_extra_info, |
546 | | NULL |
547 | | }; |
548 | | |
549 | | const gcry_mac_spec_t _gcry_mac_type_spec_gost28147_imit = |
550 | | { |
551 | | GCRY_MAC_GOST28147_IMIT, {0, 0}, "GOST28147_IMIT", |
552 | | &gost_imit_ops |
553 | | }; |