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