Coverage Report

Created: 2024-11-21 07:03

/src/libgcrypt/cipher/mac-poly1305.c
Line
Count
Source (jump to first uncovered line)
1
/* mac-poly1305.c  -  Poly1305 based MACs
2
 * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
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
#include <config.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <errno.h>
25
26
#include "g10lib.h"
27
#include "mac-internal.h"
28
#include "poly1305-internal.h"
29
30
31
struct poly1305mac_context_s {
32
  poly1305_context_t ctx;
33
  gcry_cipher_hd_t hd;
34
  struct {
35
    unsigned int key_set:1;
36
    unsigned int nonce_set:1;
37
    unsigned int tag:1;
38
  } marks;
39
  byte tag[POLY1305_TAGLEN];
40
  byte key[POLY1305_KEYLEN];
41
};
42
43
44
static gcry_err_code_t
45
poly1305mac_open (gcry_mac_hd_t h)
46
0
{
47
0
  struct poly1305mac_context_s *mac_ctx;
48
0
  int secure = (h->magic == CTX_MAC_MAGIC_SECURE);
49
0
  unsigned int flags = (secure ? GCRY_CIPHER_SECURE : 0);
50
0
  gcry_err_code_t err;
51
0
  int cipher_algo;
52
53
0
  if (secure)
54
0
    mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx));
55
0
  else
56
0
    mac_ctx = xtrycalloc (1, sizeof(*mac_ctx));
57
58
0
  if (!mac_ctx)
59
0
    return gpg_err_code_from_syserror ();
60
61
0
  h->u.poly1305mac.ctx = mac_ctx;
62
63
0
  switch (h->spec->algo)
64
0
    {
65
0
    default:
66
      /* already checked. */
67
0
    case GCRY_MAC_POLY1305:
68
      /* plain Poly1305. */
69
0
      cipher_algo = -1;
70
0
      return 0;
71
0
    case GCRY_MAC_POLY1305_AES:
72
0
      cipher_algo = GCRY_CIPHER_AES;
73
0
      break;
74
0
    case GCRY_MAC_POLY1305_CAMELLIA:
75
0
      cipher_algo = GCRY_CIPHER_CAMELLIA128;
76
0
      break;
77
0
    case GCRY_MAC_POLY1305_TWOFISH:
78
0
      cipher_algo = GCRY_CIPHER_TWOFISH;
79
0
      break;
80
0
    case GCRY_MAC_POLY1305_SERPENT:
81
0
      cipher_algo = GCRY_CIPHER_SERPENT128;
82
0
      break;
83
0
    case GCRY_MAC_POLY1305_SEED:
84
0
      cipher_algo = GCRY_CIPHER_SEED;
85
0
      break;
86
0
    case GCRY_MAC_POLY1305_SM4:
87
0
      cipher_algo = GCRY_CIPHER_SM4;
88
0
      break;
89
0
    case GCRY_MAC_POLY1305_ARIA:
90
0
      cipher_algo = GCRY_CIPHER_ARIA128;
91
0
      break;
92
0
    }
93
94
0
  err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo,
95
0
            GCRY_CIPHER_MODE_ECB, flags);
96
0
  if (err)
97
0
    goto err_free;
98
99
0
  return 0;
100
101
0
err_free:
102
0
  xfree(h->u.poly1305mac.ctx);
103
0
  return err;
104
0
}
105
106
107
static void
108
poly1305mac_close (gcry_mac_hd_t h)
109
0
{
110
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
111
112
0
  if (h->spec->algo != GCRY_MAC_POLY1305)
113
0
    _gcry_cipher_close (mac_ctx->hd);
114
115
0
  xfree(mac_ctx);
116
0
}
117
118
119
static gcry_err_code_t
120
poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
121
0
{
122
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
123
0
  size_t block_keylen = keylen - 16;
124
125
  /* Need at least 16 + 1 byte key. */
126
0
  if (keylen <= 16)
127
0
    return GPG_ERR_INV_KEYLEN;
128
129
  /* For Poly1305-AES, first part of key is passed to Poly1305 as is. */
130
0
  memcpy (mac_ctx->key, key + block_keylen, 16);
131
132
  /* Remaining part is used as key for the block cipher. */
133
0
  return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen);
134
0
}
135
136
137
static gcry_err_code_t
138
poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
139
0
{
140
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
141
0
  gcry_err_code_t err;
142
143
0
  memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
144
0
  memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
145
0
  memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
146
147
0
  mac_ctx->marks.key_set = 0;
148
0
  mac_ctx->marks.nonce_set = 0;
149
0
  mac_ctx->marks.tag = 0;
150
151
0
  if (h->spec->algo != GCRY_MAC_POLY1305)
152
0
    {
153
0
      err = poly1305mac_prepare_key (h, key, keylen);
154
0
      if (err)
155
0
        return err;
156
157
      /* Poly1305-AES/etc also need nonce. */
158
0
      mac_ctx->marks.key_set = 1;
159
0
      mac_ctx->marks.nonce_set = 0;
160
0
    }
161
0
  else
162
0
    {
163
      /* For plain Poly1305, key is the nonce and setup is complete now. */
164
165
0
      if (keylen != POLY1305_KEYLEN)
166
0
        return GPG_ERR_INV_KEYLEN;
167
168
0
      memcpy (mac_ctx->key, key, keylen);
169
170
0
      err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
171
0
      if (err)
172
0
        {
173
0
          memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
174
0
          return err;
175
0
        }
176
177
0
      mac_ctx->marks.key_set = 1;
178
0
      mac_ctx->marks.nonce_set = 1;
179
0
    }
180
181
0
  return 0;
182
0
}
183
184
185
static gcry_err_code_t
186
poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
187
0
{
188
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
189
0
  gcry_err_code_t err;
190
191
0
  if (h->spec->algo == GCRY_MAC_POLY1305)
192
0
    return GPG_ERR_INV_ARG;
193
194
0
  if (ivlen != 16)
195
0
    return GPG_ERR_INV_ARG;
196
197
0
  if (!mac_ctx->marks.key_set)
198
0
    return 0;
199
200
0
  memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
201
0
  memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
202
0
  mac_ctx->marks.nonce_set = 0;
203
0
  mac_ctx->marks.tag = 0;
204
205
  /* Prepare second part of the poly1305 key. */
206
207
0
  err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16);
208
0
  if (err)
209
0
    return err;
210
211
0
  err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
212
0
  if (err)
213
0
    return err;
214
215
0
  mac_ctx->marks.nonce_set = 1;
216
0
  return 0;
217
0
}
218
219
220
static gcry_err_code_t
221
poly1305mac_reset (gcry_mac_hd_t h)
222
0
{
223
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
224
225
0
  if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
226
0
    return GPG_ERR_INV_STATE;
227
228
0
  memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
229
0
  memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
230
231
0
  mac_ctx->marks.key_set = 1;
232
0
  mac_ctx->marks.nonce_set = 1;
233
0
  mac_ctx->marks.tag = 0;
234
235
0
  return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
236
0
}
237
238
239
static gcry_err_code_t
240
poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
241
0
{
242
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
243
244
0
  if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set ||
245
0
      mac_ctx->marks.tag)
246
0
    return GPG_ERR_INV_STATE;
247
248
0
  _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen);
249
0
  return 0;
250
0
}
251
252
253
static gcry_err_code_t
254
poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen)
255
0
{
256
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
257
258
0
  if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
259
0
    return GPG_ERR_INV_STATE;
260
261
0
  if (!mac_ctx->marks.tag)
262
0
    {
263
0
      _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag);
264
265
0
      memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
266
0
      mac_ctx->marks.tag = 1;
267
0
    }
268
269
0
  if (*outlen == 0)
270
0
    return 0;
271
272
0
  if (*outlen <= POLY1305_TAGLEN)
273
0
    buf_cpy (outbuf, mac_ctx->tag, *outlen);
274
0
  else
275
0
    {
276
0
      buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN);
277
0
      *outlen = POLY1305_TAGLEN;
278
0
    }
279
280
0
  return 0;
281
0
}
282
283
284
static gcry_err_code_t
285
poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
286
0
{
287
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
288
0
  gcry_err_code_t err;
289
0
  size_t outlen = 0;
290
291
  /* Check and finalize tag. */
292
0
  err = poly1305mac_read(h, NULL, &outlen);
293
0
  if (err)
294
0
    return err;
295
296
0
  if (buflen > POLY1305_TAGLEN)
297
0
    return GPG_ERR_INV_LENGTH;
298
299
0
  return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM;
300
0
}
301
302
303
static unsigned int
304
poly1305mac_get_maclen (int algo)
305
0
{
306
0
  (void)algo;
307
308
0
  return POLY1305_TAGLEN;
309
0
}
310
311
312
static unsigned int
313
poly1305mac_get_keylen (int algo)
314
0
{
315
0
  (void)algo;
316
317
0
  return POLY1305_KEYLEN;
318
0
}
319
320
321
static gcry_mac_spec_ops_t poly1305mac_ops = {
322
  poly1305mac_open,
323
  poly1305mac_close,
324
  poly1305mac_setkey,
325
  poly1305mac_setiv,
326
  poly1305mac_reset,
327
  poly1305mac_write,
328
  poly1305mac_read,
329
  poly1305mac_verify,
330
  poly1305mac_get_maclen,
331
  poly1305mac_get_keylen,
332
  NULL,
333
  NULL,
334
};
335
336
337
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = {
338
  GCRY_MAC_POLY1305, {0, 0}, "POLY1305",
339
  &poly1305mac_ops
340
};
341
#if USE_AES
342
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = {
343
  GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES",
344
  &poly1305mac_ops
345
};
346
#endif
347
#if USE_CAMELLIA
348
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = {
349
  GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA",
350
  &poly1305mac_ops
351
};
352
#endif
353
#if USE_TWOFISH
354
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = {
355
  GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH",
356
  &poly1305mac_ops
357
};
358
#endif
359
#if USE_SERPENT
360
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = {
361
  GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT",
362
  &poly1305mac_ops
363
};
364
#endif
365
#if USE_SEED
366
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = {
367
  GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED",
368
  &poly1305mac_ops
369
};
370
#endif
371
#if USE_SM4
372
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_sm4 = {
373
  GCRY_MAC_POLY1305_SM4, {0, 0}, "POLY1305_SM4",
374
  &poly1305mac_ops
375
};
376
#endif
377
#if USE_ARIA
378
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aria = {
379
  GCRY_MAC_POLY1305_ARIA, {0, 0}, "POLY1305_ARIA",
380
  &poly1305mac_ops
381
};
382
#endif