bufhelp: use one-byte aligned type for unaligned memory accesses
[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_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   c->spec->stencrypt(&c->context.c, outbuf, (byte*)inbuf, inbuflen);
168
169   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, outbuf, inbuflen);
170
171   return 0;
172 }
173
174
175 gcry_err_code_t
176 _gcry_cipher_poly1305_decrypt (gcry_cipher_hd_t c,
177                                byte *outbuf, size_t outbuflen,
178                                const byte *inbuf, size_t inbuflen)
179 {
180   gcry_err_code_t err;
181
182   if (outbuflen < inbuflen)
183     return GPG_ERR_BUFFER_TOO_SHORT;
184   if (c->marks.tag)
185     return GPG_ERR_INV_STATE;
186   if (c->u_mode.poly1305.bytecount_over_limits)
187     return GPG_ERR_INV_LENGTH;
188
189   if (!c->marks.iv)
190     {
191       err = poly1305_set_zeroiv(c);
192       if (err)
193         return err;
194     }
195
196   if (!c->u_mode.poly1305.aad_finalized)
197     poly1305_aad_finish(c);
198
199   if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen))
200     {
201       c->u_mode.poly1305.bytecount_over_limits = 1;
202       return GPG_ERR_INV_LENGTH;
203     }
204
205   _gcry_poly1305_update (&c->u_mode.poly1305.ctx, inbuf, inbuflen);
206
207   c->spec->stdecrypt(&c->context.c, outbuf, (byte*)inbuf, inbuflen);
208   return 0;
209 }
210
211
212 static gcry_err_code_t
213 _gcry_cipher_poly1305_tag (gcry_cipher_hd_t c,
214                            byte * outbuf, size_t outbuflen, int check)
215 {
216   gcry_err_code_t err;
217
218   if (outbuflen < GCRY_GCM_BLOCK_LEN)
219     return GPG_ERR_BUFFER_TOO_SHORT;
220   if (c->u_mode.poly1305.bytecount_over_limits)
221     return GPG_ERR_INV_LENGTH;
222
223   if (!c->marks.iv)
224     {
225       err = poly1305_set_zeroiv(c);
226       if (err)
227         return err;
228     }
229
230   if (!c->u_mode.poly1305.aad_finalized)
231     poly1305_aad_finish(c);
232
233   if (!c->marks.tag)
234     {
235       /* After data, feed padding bytes so we get 16 byte alignment. */
236       poly1305_do_padding (c, c->u_mode.poly1305.datacount);
237
238       /* Write byte counts to poly1305. */
239       poly1305_fill_bytecounts(c);
240
241       _gcry_poly1305_finish(&c->u_mode.poly1305.ctx, c->u_iv.iv);
242
243       c->marks.tag = 1;
244     }
245
246   if (check)
247     return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ?
248            GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
249
250   memcpy (outbuf, c->u_iv.iv, outbuflen);
251   return GPG_ERR_NO_ERROR;
252 }
253
254
255 gcry_err_code_t
256 _gcry_cipher_poly1305_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
257                           size_t taglen)
258 {
259   return _gcry_cipher_poly1305_tag (c, outtag, taglen, 0);
260 }
261
262 gcry_err_code_t
263 _gcry_cipher_poly1305_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
264                             size_t taglen)
265 {
266   return _gcry_cipher_poly1305_tag (c, (unsigned char *) intag, taglen, 1);
267 }
268
269
270 void
271 _gcry_cipher_poly1305_setkey (gcry_cipher_hd_t c)
272 {
273   c->u_mode.poly1305.aadcount[0] = 0;
274   c->u_mode.poly1305.aadcount[1] = 0;
275
276   c->u_mode.poly1305.datacount[0] = 0;
277   c->u_mode.poly1305.datacount[1] = 0;
278
279   c->u_mode.poly1305.bytecount_over_limits = 0;
280   c->u_mode.poly1305.aad_finalized = 0;
281   c->marks.tag = 0;
282   c->marks.iv = 0;
283 }
284
285
286 gcry_err_code_t
287 _gcry_cipher_poly1305_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
288 {
289   byte tmpbuf[64]; /* size of ChaCha20 block */
290   gcry_err_code_t err;
291
292   /* IV must be 96-bits */
293   if (!iv && ivlen != (96 / 8))
294     return GPG_ERR_INV_ARG;
295
296   memset(&c->u_mode.poly1305.ctx, 0, sizeof(c->u_mode.poly1305.ctx));
297
298   c->u_mode.poly1305.aadcount[0] = 0;
299   c->u_mode.poly1305.aadcount[1] = 0;
300
301   c->u_mode.poly1305.datacount[0] = 0;
302   c->u_mode.poly1305.datacount[1] = 0;
303
304   c->u_mode.poly1305.bytecount_over_limits = 0;
305   c->u_mode.poly1305.aad_finalized = 0;
306   c->marks.tag = 0;
307   c->marks.iv = 0;
308
309   /* Set up IV for stream cipher. */
310   c->spec->setiv (&c->context.c, iv, ivlen);
311
312   /* Get the first block from ChaCha20. */
313   memset(tmpbuf, 0, sizeof(tmpbuf));
314   c->spec->stencrypt(&c->context.c, tmpbuf, tmpbuf, sizeof(tmpbuf));
315
316   /* Use the first 32-bytes as Poly1305 key. */
317   err = _gcry_poly1305_init (&c->u_mode.poly1305.ctx, tmpbuf, POLY1305_KEYLEN);
318
319   wipememory(tmpbuf, sizeof(tmpbuf));
320
321   if (err)
322     return err;
323
324   c->marks.iv = 1;
325   return 0;
326 }