mac: Fix gcry_mac_close to allow for a NULL handle.
[libgcrypt.git] / cipher / cipher-poly1305.c
1 /* cipher-pol1305.c  -  Poly1305 based AEAD cipher mode
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_bytecount (gcry_cipher_hd_t c)
57 {
58   u32 lenbuf[2];
59
60   lenbuf[0] = le_bswap32(c->u_mode.poly1305.bytecount[0]);
61   lenbuf[1] = le_bswap32(c->u_mode.poly1305.bytecount[1]);
62   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, (byte*)lenbuf,
63                          sizeof(lenbuf));
64
65   wipememory(lenbuf, sizeof(lenbuf));
66 }
67
68
69 static void
70 poly1305_aad_finish (gcry_cipher_hd_t c)
71 {
72   /* Start of encryption marks end of AAD stream. */
73   poly1305_fill_bytecount(c);
74
75   c->u_mode.poly1305.aad_finalized = 1;
76
77   c->u_mode.poly1305.bytecount[0] = 0;
78   c->u_mode.poly1305.bytecount[1] = 0;
79 }
80
81
82 static gcry_err_code_t
83 poly1305_set_zeroiv (gcry_cipher_hd_t c)
84 {
85   byte zero[8] = { 0, };
86
87   return _gcry_cipher_poly1305_setiv (c, zero, sizeof(zero));
88 }
89
90
91 gcry_err_code_t
92 _gcry_cipher_poly1305_authenticate (gcry_cipher_hd_t c,
93                                     const byte * aadbuf, size_t aadbuflen)
94 {
95   if (c->u_mode.poly1305.bytecount_over_limits)
96     return GPG_ERR_INV_LENGTH;
97   if (c->u_mode.poly1305.aad_finalized)
98     return GPG_ERR_INV_STATE;
99   if (c->marks.tag)
100     return GPG_ERR_INV_STATE;
101
102   if (!c->marks.iv)
103     poly1305_set_zeroiv(c);
104
105   if (poly1305_bytecounter_add(c->u_mode.poly1305.bytecount, aadbuflen))
106     {
107       c->u_mode.poly1305.bytecount_over_limits = 1;
108       return GPG_ERR_INV_LENGTH;
109     }
110
111   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, aadbuf, aadbuflen);
112
113   return 0;
114 }
115
116
117 gcry_err_code_t
118 _gcry_cipher_poly1305_encrypt (gcry_cipher_hd_t c,
119                                byte *outbuf, size_t outbuflen,
120                                const byte *inbuf, size_t inbuflen)
121 {
122   gcry_err_code_t err;
123
124   if (outbuflen < inbuflen)
125     return GPG_ERR_BUFFER_TOO_SHORT;
126   if (c->marks.tag)
127     return GPG_ERR_INV_STATE;
128   if (c->u_mode.poly1305.bytecount_over_limits)
129     return GPG_ERR_INV_LENGTH;
130
131   if (!c->marks.iv)
132     {
133       err = poly1305_set_zeroiv(c);
134       if (err)
135         return err;
136     }
137
138   if (!c->u_mode.poly1305.aad_finalized)
139     poly1305_aad_finish(c);
140
141   if (poly1305_bytecounter_add(c->u_mode.poly1305.bytecount, inbuflen))
142     {
143       c->u_mode.poly1305.bytecount_over_limits = 1;
144       return GPG_ERR_INV_LENGTH;
145     }
146
147   c->spec->stencrypt(&c->context.c, outbuf, (byte*)inbuf, inbuflen);
148
149   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, outbuf, inbuflen);
150
151   return 0;
152 }
153
154
155 gcry_err_code_t
156 _gcry_cipher_poly1305_decrypt (gcry_cipher_hd_t c,
157                                byte *outbuf, size_t outbuflen,
158                                const byte *inbuf, size_t inbuflen)
159 {
160   gcry_err_code_t err;
161
162   if (outbuflen < inbuflen)
163     return GPG_ERR_BUFFER_TOO_SHORT;
164   if (c->marks.tag)
165     return GPG_ERR_INV_STATE;
166   if (c->u_mode.poly1305.bytecount_over_limits)
167     return GPG_ERR_INV_LENGTH;
168
169   if (!c->marks.iv)
170     {
171       err = poly1305_set_zeroiv(c);
172       if (err)
173         return err;
174     }
175
176   if (!c->u_mode.poly1305.aad_finalized)
177     poly1305_aad_finish(c);
178
179   if (poly1305_bytecounter_add(c->u_mode.poly1305.bytecount, inbuflen))
180     {
181       c->u_mode.poly1305.bytecount_over_limits = 1;
182       return GPG_ERR_INV_LENGTH;
183     }
184
185   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, inbuf, inbuflen);
186
187   c->spec->stdecrypt(&c->context.c, outbuf, (byte*)inbuf, inbuflen);
188   return 0;
189 }
190
191
192 static gcry_err_code_t
193 _gcry_cipher_poly1305_tag (gcry_cipher_hd_t c,
194                            byte * outbuf, size_t outbuflen, int check)
195 {
196   gcry_err_code_t err;
197
198   if (outbuflen < GCRY_GCM_BLOCK_LEN)
199     return GPG_ERR_BUFFER_TOO_SHORT;
200   if (c->u_mode.poly1305.bytecount_over_limits)
201     return GPG_ERR_INV_LENGTH;
202
203   if (!c->marks.iv)
204     {
205       err = poly1305_set_zeroiv(c);
206       if (err)
207         return err;
208     }
209
210   if (!c->u_mode.poly1305.aad_finalized)
211     poly1305_aad_finish(c);
212
213   if (!c->marks.tag)
214     {
215       /* Write data-length to poly1305. */
216       poly1305_fill_bytecount(c);
217
218       _gcry_poly1305_finish(&c->u_mode.poly1305.ctx, c->u_iv.iv);
219
220       c->marks.tag = 1;
221     }
222
223   if (check)
224     return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ?
225            GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
226
227   memcpy (outbuf, c->u_iv.iv, outbuflen);
228   return GPG_ERR_NO_ERROR;
229 }
230
231
232 gcry_err_code_t
233 _gcry_cipher_poly1305_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
234                           size_t taglen)
235 {
236   return _gcry_cipher_poly1305_tag (c, outtag, taglen, 0);
237 }
238
239 gcry_err_code_t
240 _gcry_cipher_poly1305_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
241                             size_t taglen)
242 {
243   return _gcry_cipher_poly1305_tag (c, (unsigned char *) intag, taglen, 1);
244 }
245
246
247 void
248 _gcry_cipher_poly1305_setkey (gcry_cipher_hd_t c)
249 {
250   c->u_mode.poly1305.bytecount[0] = 0;
251   c->u_mode.poly1305.bytecount[1] = 0;
252
253   c->u_mode.poly1305.bytecount_over_limits = 0;
254   c->u_mode.poly1305.aad_finalized = 0;
255   c->marks.tag = 0;
256   c->marks.iv = 0;
257 }
258
259
260 gcry_err_code_t
261 _gcry_cipher_poly1305_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
262 {
263   byte tmpbuf[64]; /* size of ChaCha20/Salsa20 block */
264   gcry_err_code_t err;
265
266   if (!iv && ivlen > 0)
267     return GPG_ERR_INV_ARG;
268
269   memset(&c->u_mode.poly1305.ctx, 0, sizeof(c->u_mode.poly1305.ctx));
270
271   c->u_mode.poly1305.bytecount[0] = 0;
272   c->u_mode.poly1305.bytecount[1] = 0;
273
274   c->u_mode.poly1305.bytecount_over_limits = 0;
275   c->u_mode.poly1305.aad_finalized = 0;
276   c->marks.tag = 0;
277   c->marks.iv = 0;
278
279   /* Set up IV for stream cipher. */
280   c->spec->setiv (&c->context.c, iv, ivlen);
281
282   /* Get the first block from ChaCha20/Salsa20. */
283   memset(tmpbuf, 0, sizeof(tmpbuf));
284   c->spec->stencrypt(&c->context.c, tmpbuf, tmpbuf, sizeof(tmpbuf));
285
286   /* Use the first 32-bytes as Poly1305 key. */
287   err = _gcry_poly1305_init (&c->u_mode.poly1305.ctx, tmpbuf, POLY1305_KEYLEN);
288
289   wipememory(tmpbuf, sizeof(tmpbuf));
290
291   if (err)
292     return err;
293
294   c->marks.iv = 1;
295   return 0;
296 }