Coverage Report

Created: 2022-12-08 06:10

/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
    }
87
88
0
  err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo,
89
0
            GCRY_CIPHER_MODE_ECB, flags);
90
0
  if (err)
91
0
    goto err_free;
92
93
0
  return 0;
94
95
0
err_free:
96
0
  xfree(h->u.poly1305mac.ctx);
97
0
  return err;
98
0
}
99
100
101
static void
102
poly1305mac_close (gcry_mac_hd_t h)
103
0
{
104
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
105
106
0
  if (h->spec->algo != GCRY_MAC_POLY1305)
107
0
    _gcry_cipher_close (mac_ctx->hd);
108
109
0
  xfree(mac_ctx);
110
0
}
111
112
113
static gcry_err_code_t
114
poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
115
0
{
116
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
117
0
  size_t block_keylen = keylen - 16;
118
119
  /* Need at least 16 + 1 byte key. */
120
0
  if (keylen <= 16)
121
0
    return GPG_ERR_INV_KEYLEN;
122
123
  /* For Poly1305-AES, first part of key is passed to Poly1305 as is. */
124
0
  memcpy (mac_ctx->key, key + block_keylen, 16);
125
126
  /* Remaining part is used as key for the block cipher. */
127
0
  return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen);
128
0
}
129
130
131
static gcry_err_code_t
132
poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
133
0
{
134
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
135
0
  gcry_err_code_t err;
136
137
0
  memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
138
0
  memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
139
0
  memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
140
141
0
  mac_ctx->marks.key_set = 0;
142
0
  mac_ctx->marks.nonce_set = 0;
143
0
  mac_ctx->marks.tag = 0;
144
145
0
  if (h->spec->algo != GCRY_MAC_POLY1305)
146
0
    {
147
0
      err = poly1305mac_prepare_key (h, key, keylen);
148
0
      if (err)
149
0
        return err;
150
151
      /* Poly1305-AES/etc also need nonce. */
152
0
      mac_ctx->marks.key_set = 1;
153
0
      mac_ctx->marks.nonce_set = 0;
154
0
    }
155
0
  else
156
0
    {
157
      /* For plain Poly1305, key is the nonce and setup is complete now. */
158
159
0
      if (keylen != POLY1305_KEYLEN)
160
0
        return GPG_ERR_INV_KEYLEN;
161
162
0
      memcpy (mac_ctx->key, key, keylen);
163
164
0
      err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
165
0
      if (err)
166
0
        {
167
0
          memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
168
0
          return err;
169
0
        }
170
171
0
      mac_ctx->marks.key_set = 1;
172
0
      mac_ctx->marks.nonce_set = 1;
173
0
    }
174
175
0
  return 0;
176
0
}
177
178
179
static gcry_err_code_t
180
poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
181
0
{
182
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
183
0
  gcry_err_code_t err;
184
185
0
  if (h->spec->algo == GCRY_MAC_POLY1305)
186
0
    return GPG_ERR_INV_ARG;
187
188
0
  if (ivlen != 16)
189
0
    return GPG_ERR_INV_ARG;
190
191
0
  if (!mac_ctx->marks.key_set)
192
0
    return 0;
193
194
0
  memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
195
0
  memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
196
0
  mac_ctx->marks.nonce_set = 0;
197
0
  mac_ctx->marks.tag = 0;
198
199
  /* Prepare second part of the poly1305 key. */
200
201
0
  err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16);
202
0
  if (err)
203
0
    return err;
204
205
0
  err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
206
0
  if (err)
207
0
    return err;
208
209
0
  mac_ctx->marks.nonce_set = 1;
210
0
  return 0;
211
0
}
212
213
214
static gcry_err_code_t
215
poly1305mac_reset (gcry_mac_hd_t h)
216
0
{
217
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
218
219
0
  if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
220
0
    return GPG_ERR_INV_STATE;
221
222
0
  memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
223
0
  memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
224
225
0
  mac_ctx->marks.key_set = 1;
226
0
  mac_ctx->marks.nonce_set = 1;
227
0
  mac_ctx->marks.tag = 0;
228
229
0
  return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
230
0
}
231
232
233
static gcry_err_code_t
234
poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
235
0
{
236
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
237
238
0
  if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set ||
239
0
      mac_ctx->marks.tag)
240
0
    return GPG_ERR_INV_STATE;
241
242
0
  _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen);
243
0
  return 0;
244
0
}
245
246
247
static gcry_err_code_t
248
poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen)
249
0
{
250
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
251
252
0
  if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
253
0
    return GPG_ERR_INV_STATE;
254
255
0
  if (!mac_ctx->marks.tag)
256
0
    {
257
0
      _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag);
258
259
0
      memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
260
0
      mac_ctx->marks.tag = 1;
261
0
    }
262
263
0
  if (*outlen == 0)
264
0
    return 0;
265
266
0
  if (*outlen <= POLY1305_TAGLEN)
267
0
    buf_cpy (outbuf, mac_ctx->tag, *outlen);
268
0
  else
269
0
    {
270
0
      buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN);
271
0
      *outlen = POLY1305_TAGLEN;
272
0
    }
273
274
0
  return 0;
275
0
}
276
277
278
static gcry_err_code_t
279
poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
280
0
{
281
0
  struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
282
0
  gcry_err_code_t err;
283
0
  size_t outlen = 0;
284
285
  /* Check and finalize tag. */
286
0
  err = poly1305mac_read(h, NULL, &outlen);
287
0
  if (err)
288
0
    return err;
289
290
0
  if (buflen > POLY1305_TAGLEN)
291
0
    return GPG_ERR_INV_LENGTH;
292
293
0
  return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM;
294
0
}
295
296
297
static unsigned int
298
poly1305mac_get_maclen (int algo)
299
0
{
300
0
  (void)algo;
301
302
0
  return POLY1305_TAGLEN;
303
0
}
304
305
306
static unsigned int
307
poly1305mac_get_keylen (int algo)
308
0
{
309
0
  (void)algo;
310
311
0
  return POLY1305_KEYLEN;
312
0
}
313
314
315
static gcry_mac_spec_ops_t poly1305mac_ops = {
316
  poly1305mac_open,
317
  poly1305mac_close,
318
  poly1305mac_setkey,
319
  poly1305mac_setiv,
320
  poly1305mac_reset,
321
  poly1305mac_write,
322
  poly1305mac_read,
323
  poly1305mac_verify,
324
  poly1305mac_get_maclen,
325
  poly1305mac_get_keylen,
326
  NULL,
327
  NULL,
328
};
329
330
331
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = {
332
  GCRY_MAC_POLY1305, {0, 0}, "POLY1305",
333
  &poly1305mac_ops
334
};
335
#if USE_AES
336
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = {
337
  GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES",
338
  &poly1305mac_ops
339
};
340
#endif
341
#if USE_CAMELLIA
342
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = {
343
  GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA",
344
  &poly1305mac_ops
345
};
346
#endif
347
#if USE_TWOFISH
348
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = {
349
  GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH",
350
  &poly1305mac_ops
351
};
352
#endif
353
#if USE_SERPENT
354
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = {
355
  GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT",
356
  &poly1305mac_ops
357
};
358
#endif
359
#if USE_SEED
360
const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = {
361
  GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED",
362
  &poly1305mac_ops
363
};
364
#endif