Process CCM/EAX/GCM/Poly1305 AEAD cipher modes input in 24 KiB chucks
[libgcrypt.git] / cipher / cipher-eax.c
1 /* cipher-eax.c  -  EAX implementation
2  * Copyright (C) 2018 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
31
32 gcry_err_code_t
33 _gcry_cipher_eax_encrypt (gcry_cipher_hd_t c,
34                           byte *outbuf, size_t outbuflen,
35                           const byte *inbuf, size_t inbuflen)
36 {
37   gcry_err_code_t err;
38
39   if (outbuflen < inbuflen)
40     return GPG_ERR_BUFFER_TOO_SHORT;
41   if (c->marks.tag)
42     return GPG_ERR_INV_STATE;
43
44   if (!c->marks.iv)
45     {
46       err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
47       if (err != 0)
48         return err;
49     }
50
51   while (inbuflen)
52     {
53       size_t currlen = inbuflen;
54
55       /* Since checksumming is done after encryption, process input in 24KiB
56        * chunks to keep data loaded in L1 cache for checksumming. */
57       if (currlen > 24 * 1024)
58         currlen = 24 * 1024;
59
60       err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen);
61       if (err != 0)
62         return err;
63
64       err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, outbuf,
65                               currlen);
66       if (err != 0)
67         return err;
68
69       outbuf += currlen;
70       inbuf += currlen;
71       outbuflen -= currlen;
72       inbuflen -= currlen;
73     }
74
75   return 0;
76 }
77
78
79 gcry_err_code_t
80 _gcry_cipher_eax_decrypt (gcry_cipher_hd_t c,
81                           byte *outbuf, size_t outbuflen,
82                           const byte *inbuf, size_t inbuflen)
83 {
84   gcry_err_code_t err;
85
86   if (outbuflen < inbuflen)
87     return GPG_ERR_BUFFER_TOO_SHORT;
88   if (c->marks.tag)
89     return GPG_ERR_INV_STATE;
90
91   if (!c->marks.iv)
92     {
93       err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
94       if (err != 0)
95         return err;
96     }
97
98   while (inbuflen)
99     {
100       size_t currlen = inbuflen;
101
102       /* Since checksumming is done before decryption, process input in 24KiB
103        * chunks to keep data loaded in L1 cache for decryption. */
104       if (currlen > 24 * 1024)
105         currlen = 24 * 1024;
106
107       err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, inbuf,
108                               currlen);
109       if (err != 0)
110         return err;
111
112       err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen);
113       if (err != 0)
114         return err;
115
116       outbuf += currlen;
117       inbuf += currlen;
118       outbuflen -= currlen;
119       inbuflen -= currlen;
120     }
121
122   return 0;
123 }
124
125
126 gcry_err_code_t
127 _gcry_cipher_eax_authenticate (gcry_cipher_hd_t c,
128                                const byte * aadbuf, size_t aadbuflen)
129 {
130   gcry_err_code_t err;
131
132   if (c->marks.tag)
133     return GPG_ERR_INV_STATE;
134
135   if (!c->marks.iv)
136     {
137       err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
138       if (err != 0)
139         return err;
140     }
141
142   return _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, aadbuf, aadbuflen);
143 }
144
145
146 gcry_err_code_t
147 _gcry_cipher_eax_setkey (gcry_cipher_hd_t c)
148 {
149   gcry_err_code_t err;
150
151   err = _gcry_cmac_generate_subkeys (c, &c->u_mode.eax.cmac_header);
152   if (err != 0)
153     return err;
154
155   buf_cpy (c->u_mode.eax.cmac_ciphertext.subkeys,
156            c->u_mode.eax.cmac_header.subkeys,
157            sizeof(c->u_mode.eax.cmac_header.subkeys));
158
159   return 0;
160 }
161
162
163 gcry_err_code_t
164 _gcry_cipher_eax_set_nonce (gcry_cipher_hd_t c, const byte *nonce,
165                             size_t noncelen)
166 {
167   gcry_cmac_context_t nonce_cmac;
168   unsigned char initbuf[MAX_BLOCKSIZE];
169   gcry_err_code_t err;
170
171   c->marks.iv = 0;
172   c->marks.tag = 0;
173
174   _gcry_cmac_reset (&c->u_mode.eax.cmac_header);
175   _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext);
176
177   /* Calculate nonce CMAC */
178
179   memset(&nonce_cmac, 0, sizeof(nonce_cmac));
180   memset(&initbuf, 0, sizeof(initbuf));
181
182   buf_cpy (&nonce_cmac.subkeys, c->u_mode.eax.cmac_header.subkeys,
183            sizeof(c->u_mode.eax.cmac_header.subkeys));
184
185   err = _gcry_cmac_write (c, &nonce_cmac, initbuf, c->spec->blocksize);
186   if (err != 0)
187     return err;
188
189   if (noncelen != 0)
190     {
191       err = _gcry_cmac_write (c, &nonce_cmac, nonce, noncelen);
192       if (err != 0)
193         return err;
194     }
195
196   err = _gcry_cmac_final (c, &nonce_cmac);
197   if (err != 0)
198     return err;
199
200   cipher_block_cpy (c->u_iv.iv, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE);
201   cipher_block_cpy (c->u_ctr.ctr, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE);
202
203   wipememory (&nonce_cmac, sizeof(nonce_cmac));
204
205   /* Prepare header CMAC */
206
207   initbuf[c->spec->blocksize - 1] = 1;
208   err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, initbuf,
209                           c->spec->blocksize);
210   if (err != 0)
211     return err;
212
213   /* Prepare ciphertext CMAC */
214
215   initbuf[c->spec->blocksize - 1] = 2;
216   err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, initbuf,
217                           c->spec->blocksize);
218   if (err != 0)
219     return err;
220
221   c->marks.iv = 1;
222   c->marks.tag = 0;
223
224   return 0;
225 }
226
227
228 static gcry_err_code_t
229 _gcry_cipher_eax_tag (gcry_cipher_hd_t c,
230                       byte *outbuf, size_t outbuflen, int check)
231 {
232   gcry_err_code_t err;
233
234   if (!c->marks.tag)
235     {
236       err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_header);
237       if (err != 0)
238         return err;
239
240       err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_ciphertext);
241       if (err != 0)
242         return err;
243
244       cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_header.u_iv.iv,
245                           MAX_BLOCKSIZE);
246       cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_ciphertext.u_iv.iv,
247                           MAX_BLOCKSIZE);
248
249       _gcry_cmac_reset (&c->u_mode.eax.cmac_header);
250       _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext);
251
252       c->marks.tag = 1;
253     }
254
255   if (!check)
256     {
257       if (outbuflen > c->spec->blocksize)
258         outbuflen = c->spec->blocksize;
259
260       /* NB: We already checked that OUTBUF is large enough to hold
261        * the result or has valid truncated length.  */
262       memcpy (outbuf, c->u_iv.iv, outbuflen);
263     }
264   else
265     {
266       /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
267        * and thus we need to compare its length first.  */
268       if (!(outbuflen <= c->spec->blocksize)
269           || !buf_eq_const (outbuf, c->u_iv.iv, outbuflen))
270         return GPG_ERR_CHECKSUM;
271     }
272
273   return 0;
274 }
275
276
277 gcry_err_code_t
278 _gcry_cipher_eax_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
279                           size_t taglen)
280 {
281   return _gcry_cipher_eax_tag (c, outtag, taglen, 0);
282 }
283
284 gcry_err_code_t
285 _gcry_cipher_eax_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
286                             size_t taglen)
287 {
288   return _gcry_cipher_eax_tag (c, (unsigned char *) intag, taglen, 1);
289 }