Coverage Report

Created: 2022-12-08 06:10

/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
  };