Coverage Report

Created: 2024-11-21 07:03

/src/libgcrypt/cipher/cipher-poly1305.c
Line
Count
Source (jump to first uncovered line)
1
/* cipher-poly1305.c  -  Poly1305 based AEAD cipher mode, RFC-8439
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 "cipher.h"
28
#include "bufhelp.h"
29
#include "./cipher-internal.h"
30
#include "./poly1305-internal.h"
31
32
33
static inline int
34
poly1305_bytecounter_add (u32 ctr[2], size_t add)
35
0
{
36
0
  int overflow = 0;
37
38
0
  if (sizeof(add) > sizeof(u32))
39
0
    {
40
0
      u32 high_add = ((add >> 31) >> 1) & 0xffffffff;
41
0
      ctr[1] += high_add;
42
0
      if (ctr[1] < high_add)
43
0
        overflow = 1;
44
0
    }
45
46
0
  ctr[0] += add;
47
0
  if (ctr[0] >= add)
48
0
    return overflow;
49
50
0
  ctr[1] += 1;
51
0
  return (ctr[1] < 1) || overflow;
52
0
}
53
54
55
static void
56
poly1305_fill_bytecounts (gcry_cipher_hd_t c)
57
0
{
58
0
  u32 lenbuf[4];
59
60
0
  lenbuf[0] = le_bswap32(c->u_mode.poly1305.aadcount[0]);
61
0
  lenbuf[1] = le_bswap32(c->u_mode.poly1305.aadcount[1]);
62
0
  lenbuf[2] = le_bswap32(c->u_mode.poly1305.datacount[0]);
63
0
  lenbuf[3] = le_bswap32(c->u_mode.poly1305.datacount[1]);
64
0
  _gcry_poly1305_update (&c->u_mode.poly1305.ctx, (byte*)lenbuf,
65
0
       sizeof(lenbuf));
66
67
0
  wipememory(lenbuf, sizeof(lenbuf));
68
0
}
69
70
71
static void
72
poly1305_do_padding (gcry_cipher_hd_t c, u32 ctr[2])
73
0
{
74
0
  static const byte zero_padding_buf[15] = {};
75
0
  u32 padding_count;
76
77
  /* Padding to 16 byte boundary. */
78
0
  if (ctr[0] % 16 > 0)
79
0
    {
80
0
      padding_count = 16 - ctr[0] % 16;
81
82
0
      _gcry_poly1305_update (&c->u_mode.poly1305.ctx, zero_padding_buf,
83
0
           padding_count);
84
0
    }
85
0
}
86
87
88
static void
89
poly1305_aad_finish (gcry_cipher_hd_t c)
90
0
{
91
  /* After AAD, feed padding bytes so we get 16 byte alignment. */
92
0
  poly1305_do_padding (c, c->u_mode.poly1305.aadcount);
93
94
  /* Start of encryption marks end of AAD stream. */
95
0
  c->u_mode.poly1305.aad_finalized = 1;
96
97
0
  c->u_mode.poly1305.datacount[0] = 0;
98
0
  c->u_mode.poly1305.datacount[1] = 0;
99
0
}
100
101
102
static gcry_err_code_t
103
poly1305_set_zeroiv (gcry_cipher_hd_t c)
104
0
{
105
0
  byte zero[8] = { 0, };
106
107
0
  return _gcry_cipher_poly1305_setiv (c, zero, sizeof(zero));
108
0
}
109
110
111
gcry_err_code_t
112
_gcry_cipher_poly1305_authenticate (gcry_cipher_hd_t c,
113
            const byte * aadbuf, size_t aadbuflen)
114
0
{
115
0
  if (c->u_mode.poly1305.bytecount_over_limits)
116
0
    return GPG_ERR_INV_LENGTH;
117
0
  if (c->u_mode.poly1305.aad_finalized)
118
0
    return GPG_ERR_INV_STATE;
119
0
  if (c->marks.tag)
120
0
    return GPG_ERR_INV_STATE;
121
122
0
  if (!c->marks.iv)
123
0
    poly1305_set_zeroiv(c);
124
125
0
  if (poly1305_bytecounter_add(c->u_mode.poly1305.aadcount, aadbuflen))
126
0
    {
127
0
      c->u_mode.poly1305.bytecount_over_limits = 1;
128
0
      return GPG_ERR_INV_LENGTH;
129
0
    }
130
131
0
  _gcry_poly1305_update (&c->u_mode.poly1305.ctx, aadbuf, aadbuflen);
132
133
0
  return 0;
134
0
}
135
136
137
gcry_err_code_t
138
_gcry_cipher_poly1305_encrypt (gcry_cipher_hd_t c,
139
             byte *outbuf, size_t outbuflen,
140
             const byte *inbuf, size_t inbuflen)
141
0
{
142
0
  gcry_err_code_t err;
143
144
0
  if (outbuflen < inbuflen)
145
0
    return GPG_ERR_BUFFER_TOO_SHORT;
146
0
  if (c->marks.tag)
147
0
    return GPG_ERR_INV_STATE;
148
0
  if (c->u_mode.poly1305.bytecount_over_limits)
149
0
    return GPG_ERR_INV_LENGTH;
150
151
0
  if (!c->marks.iv)
152
0
    {
153
0
      err = poly1305_set_zeroiv(c);
154
0
      if (err)
155
0
        return err;
156
0
    }
157
158
0
  if (!c->u_mode.poly1305.aad_finalized)
159
0
    poly1305_aad_finish(c);
160
161
0
  if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen))
162
0
    {
163
0
      c->u_mode.poly1305.bytecount_over_limits = 1;
164
0
      return GPG_ERR_INV_LENGTH;
165
0
    }
166
167
0
#ifdef USE_CHACHA20
168
0
  if (LIKELY(inbuflen > 0) && LIKELY(c->spec->algo == GCRY_CIPHER_CHACHA20))
169
0
    {
170
0
      return _gcry_chacha20_poly1305_encrypt (c, outbuf, inbuf, inbuflen);
171
0
    }
172
0
#endif
173
174
0
  while (inbuflen)
175
0
    {
176
0
      size_t currlen = inbuflen;
177
178
      /* Since checksumming is done after encryption, process input in 24KiB
179
       * chunks to keep data loaded in L1 cache for checksumming.  However
180
       * only do splitting if input is large enough so that last chunks does
181
       * not end up being short. */
182
0
      if (currlen > 32 * 1024)
183
0
  currlen = 24 * 1024;
184
185
0
      c->spec->stencrypt(&c->context.c, outbuf, (byte*)inbuf, currlen);
186
187
0
      _gcry_poly1305_update (&c->u_mode.poly1305.ctx, outbuf, currlen);
188
189
0
      outbuf += currlen;
190
0
      inbuf += currlen;
191
0
      outbuflen -= currlen;
192
0
      inbuflen -= currlen;
193
0
    }
194
195
0
  return 0;
196
0
}
197
198
199
gcry_err_code_t
200
_gcry_cipher_poly1305_decrypt (gcry_cipher_hd_t c,
201
             byte *outbuf, size_t outbuflen,
202
             const byte *inbuf, size_t inbuflen)
203
0
{
204
0
  gcry_err_code_t err;
205
206
0
  if (outbuflen < inbuflen)
207
0
    return GPG_ERR_BUFFER_TOO_SHORT;
208
0
  if (c->marks.tag)
209
0
    return GPG_ERR_INV_STATE;
210
0
  if (c->u_mode.poly1305.bytecount_over_limits)
211
0
    return GPG_ERR_INV_LENGTH;
212
213
0
  if (!c->marks.iv)
214
0
    {
215
0
      err = poly1305_set_zeroiv(c);
216
0
      if (err)
217
0
        return err;
218
0
    }
219
220
0
  if (!c->u_mode.poly1305.aad_finalized)
221
0
    poly1305_aad_finish(c);
222
223
0
  if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen))
224
0
    {
225
0
      c->u_mode.poly1305.bytecount_over_limits = 1;
226
0
      return GPG_ERR_INV_LENGTH;
227
0
    }
228
229
0
#ifdef USE_CHACHA20
230
0
  if (LIKELY(inbuflen > 0) && LIKELY(c->spec->algo == GCRY_CIPHER_CHACHA20))
231
0
    {
232
0
      return _gcry_chacha20_poly1305_decrypt (c, outbuf, inbuf, inbuflen);
233
0
    }
234
0
#endif
235
236
0
  while (inbuflen)
237
0
    {
238
0
      size_t currlen = inbuflen;
239
240
      /* Since checksumming is done before decryption, process input in 24KiB
241
       * chunks to keep data loaded in L1 cache for decryption.  However only
242
       * do splitting if input is large enough so that last chunks does not
243
       * end up being short. */
244
0
      if (currlen > 32 * 1024)
245
0
  currlen = 24 * 1024;
246
247
0
      _gcry_poly1305_update (&c->u_mode.poly1305.ctx, inbuf, currlen);
248
249
0
      c->spec->stdecrypt(&c->context.c, outbuf, (byte*)inbuf, currlen);
250
251
0
      outbuf += currlen;
252
0
      inbuf += currlen;
253
0
      outbuflen -= currlen;
254
0
      inbuflen -= currlen;
255
0
    }
256
257
0
  return 0;
258
0
}
259
260
261
static gcry_err_code_t
262
_gcry_cipher_poly1305_tag (gcry_cipher_hd_t c,
263
         byte * outbuf, size_t outbuflen, int check)
264
0
{
265
0
  gcry_err_code_t err;
266
267
0
  if (outbuflen < POLY1305_TAGLEN)
268
0
    return GPG_ERR_BUFFER_TOO_SHORT;
269
0
  if (c->u_mode.poly1305.bytecount_over_limits)
270
0
    return GPG_ERR_INV_LENGTH;
271
272
0
  if (!c->marks.iv)
273
0
    {
274
0
      err = poly1305_set_zeroiv(c);
275
0
      if (err)
276
0
        return err;
277
0
    }
278
279
0
  if (!c->u_mode.poly1305.aad_finalized)
280
0
    poly1305_aad_finish(c);
281
282
0
  if (!c->marks.tag)
283
0
    {
284
      /* After data, feed padding bytes so we get 16 byte alignment. */
285
0
      poly1305_do_padding (c, c->u_mode.poly1305.datacount);
286
287
      /* Write byte counts to poly1305. */
288
0
      poly1305_fill_bytecounts(c);
289
290
0
      _gcry_poly1305_finish(&c->u_mode.poly1305.ctx, c->u_iv.iv);
291
292
0
      c->marks.tag = 1;
293
0
    }
294
295
0
  if (!check)
296
0
    {
297
0
      memcpy (outbuf, c->u_iv.iv, POLY1305_TAGLEN);
298
0
    }
299
0
  else
300
0
    {
301
      /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
302
       * and thus we need to compare its length first.  */
303
0
      if (outbuflen != POLY1305_TAGLEN
304
0
          || !buf_eq_const (outbuf, c->u_iv.iv, POLY1305_TAGLEN))
305
0
        return GPG_ERR_CHECKSUM;
306
0
    }
307
308
0
  return 0;
309
0
}
310
311
312
gcry_err_code_t
313
_gcry_cipher_poly1305_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
314
                          size_t taglen)
315
0
{
316
0
  return _gcry_cipher_poly1305_tag (c, outtag, taglen, 0);
317
0
}
318
319
gcry_err_code_t
320
_gcry_cipher_poly1305_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
321
                            size_t taglen)
322
0
{
323
0
  return _gcry_cipher_poly1305_tag (c, (unsigned char *) intag, taglen, 1);
324
0
}
325
326
327
void
328
_gcry_cipher_poly1305_setkey (gcry_cipher_hd_t c)
329
0
{
330
0
  c->u_mode.poly1305.aadcount[0] = 0;
331
0
  c->u_mode.poly1305.aadcount[1] = 0;
332
333
0
  c->u_mode.poly1305.datacount[0] = 0;
334
0
  c->u_mode.poly1305.datacount[1] = 0;
335
336
0
  c->u_mode.poly1305.bytecount_over_limits = 0;
337
0
  c->u_mode.poly1305.aad_finalized = 0;
338
0
  c->marks.tag = 0;
339
0
  c->marks.iv = 0;
340
0
}
341
342
343
gcry_err_code_t
344
_gcry_cipher_poly1305_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
345
0
{
346
0
  byte tmpbuf[64]; /* size of ChaCha20 block */
347
0
  gcry_err_code_t err;
348
349
  /* IV must be 96-bits */
350
0
  if (!iv && ivlen != (96 / 8))
351
0
    return GPG_ERR_INV_ARG;
352
353
0
  memset(&c->u_mode.poly1305.ctx, 0, sizeof(c->u_mode.poly1305.ctx));
354
355
0
  c->u_mode.poly1305.aadcount[0] = 0;
356
0
  c->u_mode.poly1305.aadcount[1] = 0;
357
358
0
  c->u_mode.poly1305.datacount[0] = 0;
359
0
  c->u_mode.poly1305.datacount[1] = 0;
360
361
0
  c->u_mode.poly1305.bytecount_over_limits = 0;
362
0
  c->u_mode.poly1305.aad_finalized = 0;
363
0
  c->marks.tag = 0;
364
0
  c->marks.iv = 0;
365
366
  /* Set up IV for stream cipher. */
367
0
  c->spec->setiv (&c->context.c, iv, ivlen);
368
369
  /* Get the first block from ChaCha20. */
370
0
  memset(tmpbuf, 0, sizeof(tmpbuf));
371
0
  c->spec->stencrypt(&c->context.c, tmpbuf, tmpbuf, sizeof(tmpbuf));
372
373
  /* Use the first 32-bytes as Poly1305 key. */
374
0
  err = _gcry_poly1305_init (&c->u_mode.poly1305.ctx, tmpbuf, POLY1305_KEYLEN);
375
376
0
  wipememory(tmpbuf, sizeof(tmpbuf));
377
378
0
  if (err)
379
0
    return err;
380
381
0
  c->marks.iv = 1;
382
0
  return 0;
383
0
}