Coverage Report

Created: 2022-12-08 06:10

/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
  if (LIKELY(inbuflen > 0) && LIKELY(c->spec->algo == GCRY_CIPHER_CHACHA20))
168
0
    {
169
0
      return _gcry_chacha20_poly1305_encrypt (c, outbuf, inbuf, inbuflen);
170
0
    }
171
172
0
  while (inbuflen)
173
0
    {
174
0
      size_t currlen = inbuflen;
175
176
      /* Since checksumming is done after encryption, process input in 24KiB
177
       * chunks to keep data loaded in L1 cache for checksumming.  However
178
       * only do splitting if input is large enough so that last chunks does
179
       * not end up being short. */
180
0
      if (currlen > 32 * 1024)
181
0
  currlen = 24 * 1024;
182
183
0
      c->spec->stencrypt(&c->context.c, outbuf, (byte*)inbuf, currlen);
184
185
0
      _gcry_poly1305_update (&c->u_mode.poly1305.ctx, outbuf, currlen);
186
187
0
      outbuf += currlen;
188
0
      inbuf += currlen;
189
0
      outbuflen -= currlen;
190
0
      inbuflen -= currlen;
191
0
    }
192
193
0
  return 0;
194
0
}
195
196
197
gcry_err_code_t
198
_gcry_cipher_poly1305_decrypt (gcry_cipher_hd_t c,
199
             byte *outbuf, size_t outbuflen,
200
             const byte *inbuf, size_t inbuflen)
201
0
{
202
0
  gcry_err_code_t err;
203
204
0
  if (outbuflen < inbuflen)
205
0
    return GPG_ERR_BUFFER_TOO_SHORT;
206
0
  if (c->marks.tag)
207
0
    return GPG_ERR_INV_STATE;
208
0
  if (c->u_mode.poly1305.bytecount_over_limits)
209
0
    return GPG_ERR_INV_LENGTH;
210
211
0
  if (!c->marks.iv)
212
0
    {
213
0
      err = poly1305_set_zeroiv(c);
214
0
      if (err)
215
0
        return err;
216
0
    }
217
218
0
  if (!c->u_mode.poly1305.aad_finalized)
219
0
    poly1305_aad_finish(c);
220
221
0
  if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen))
222
0
    {
223
0
      c->u_mode.poly1305.bytecount_over_limits = 1;
224
0
      return GPG_ERR_INV_LENGTH;
225
0
    }
226
227
0
  if (LIKELY(inbuflen > 0) && LIKELY(c->spec->algo == GCRY_CIPHER_CHACHA20))
228
0
    {
229
0
      return _gcry_chacha20_poly1305_decrypt (c, outbuf, inbuf, inbuflen);
230
0
    }
231
232
0
  while (inbuflen)
233
0
    {
234
0
      size_t currlen = inbuflen;
235
236
      /* Since checksumming is done before decryption, process input in 24KiB
237
       * chunks to keep data loaded in L1 cache for decryption.  However only
238
       * do splitting if input is large enough so that last chunks does not
239
       * end up being short. */
240
0
      if (currlen > 32 * 1024)
241
0
  currlen = 24 * 1024;
242
243
0
      _gcry_poly1305_update (&c->u_mode.poly1305.ctx, inbuf, currlen);
244
245
0
      c->spec->stdecrypt(&c->context.c, outbuf, (byte*)inbuf, currlen);
246
247
0
      outbuf += currlen;
248
0
      inbuf += currlen;
249
0
      outbuflen -= currlen;
250
0
      inbuflen -= currlen;
251
0
    }
252
253
0
  return 0;
254
0
}
255
256
257
static gcry_err_code_t
258
_gcry_cipher_poly1305_tag (gcry_cipher_hd_t c,
259
         byte * outbuf, size_t outbuflen, int check)
260
0
{
261
0
  gcry_err_code_t err;
262
263
0
  if (outbuflen < POLY1305_TAGLEN)
264
0
    return GPG_ERR_BUFFER_TOO_SHORT;
265
0
  if (c->u_mode.poly1305.bytecount_over_limits)
266
0
    return GPG_ERR_INV_LENGTH;
267
268
0
  if (!c->marks.iv)
269
0
    {
270
0
      err = poly1305_set_zeroiv(c);
271
0
      if (err)
272
0
        return err;
273
0
    }
274
275
0
  if (!c->u_mode.poly1305.aad_finalized)
276
0
    poly1305_aad_finish(c);
277
278
0
  if (!c->marks.tag)
279
0
    {
280
      /* After data, feed padding bytes so we get 16 byte alignment. */
281
0
      poly1305_do_padding (c, c->u_mode.poly1305.datacount);
282
283
      /* Write byte counts to poly1305. */
284
0
      poly1305_fill_bytecounts(c);
285
286
0
      _gcry_poly1305_finish(&c->u_mode.poly1305.ctx, c->u_iv.iv);
287
288
0
      c->marks.tag = 1;
289
0
    }
290
291
0
  if (!check)
292
0
    {
293
0
      memcpy (outbuf, c->u_iv.iv, POLY1305_TAGLEN);
294
0
    }
295
0
  else
296
0
    {
297
      /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
298
       * and thus we need to compare its length first.  */
299
0
      if (outbuflen != POLY1305_TAGLEN
300
0
          || !buf_eq_const (outbuf, c->u_iv.iv, POLY1305_TAGLEN))
301
0
        return GPG_ERR_CHECKSUM;
302
0
    }
303
304
0
  return 0;
305
0
}
306
307
308
gcry_err_code_t
309
_gcry_cipher_poly1305_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
310
                          size_t taglen)
311
0
{
312
0
  return _gcry_cipher_poly1305_tag (c, outtag, taglen, 0);
313
0
}
314
315
gcry_err_code_t
316
_gcry_cipher_poly1305_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
317
                            size_t taglen)
318
0
{
319
0
  return _gcry_cipher_poly1305_tag (c, (unsigned char *) intag, taglen, 1);
320
0
}
321
322
323
void
324
_gcry_cipher_poly1305_setkey (gcry_cipher_hd_t c)
325
0
{
326
0
  c->u_mode.poly1305.aadcount[0] = 0;
327
0
  c->u_mode.poly1305.aadcount[1] = 0;
328
329
0
  c->u_mode.poly1305.datacount[0] = 0;
330
0
  c->u_mode.poly1305.datacount[1] = 0;
331
332
0
  c->u_mode.poly1305.bytecount_over_limits = 0;
333
0
  c->u_mode.poly1305.aad_finalized = 0;
334
0
  c->marks.tag = 0;
335
0
  c->marks.iv = 0;
336
0
}
337
338
339
gcry_err_code_t
340
_gcry_cipher_poly1305_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
341
0
{
342
0
  byte tmpbuf[64]; /* size of ChaCha20 block */
343
0
  gcry_err_code_t err;
344
345
  /* IV must be 96-bits */
346
0
  if (!iv && ivlen != (96 / 8))
347
0
    return GPG_ERR_INV_ARG;
348
349
0
  memset(&c->u_mode.poly1305.ctx, 0, sizeof(c->u_mode.poly1305.ctx));
350
351
0
  c->u_mode.poly1305.aadcount[0] = 0;
352
0
  c->u_mode.poly1305.aadcount[1] = 0;
353
354
0
  c->u_mode.poly1305.datacount[0] = 0;
355
0
  c->u_mode.poly1305.datacount[1] = 0;
356
357
0
  c->u_mode.poly1305.bytecount_over_limits = 0;
358
0
  c->u_mode.poly1305.aad_finalized = 0;
359
0
  c->marks.tag = 0;
360
0
  c->marks.iv = 0;
361
362
  /* Set up IV for stream cipher. */
363
0
  c->spec->setiv (&c->context.c, iv, ivlen);
364
365
  /* Get the first block from ChaCha20. */
366
0
  memset(tmpbuf, 0, sizeof(tmpbuf));
367
0
  c->spec->stencrypt(&c->context.c, tmpbuf, tmpbuf, sizeof(tmpbuf));
368
369
  /* Use the first 32-bytes as Poly1305 key. */
370
0
  err = _gcry_poly1305_init (&c->u_mode.poly1305.ctx, tmpbuf, POLY1305_KEYLEN);
371
372
0
  wipememory(tmpbuf, sizeof(tmpbuf));
373
374
0
  if (err)
375
0
    return err;
376
377
0
  c->marks.iv = 1;
378
0
  return 0;
379
0
}