gpg: First take on PKT_ENCRYPTED_AEAD.
[gnupg.git] / g10 / cipher-aead.c
1 /* cipher-aead.c - Enciphering filter for AEAD modes
2  * Copyright (C) 2018 Werner koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: GPL-3.0+
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "gpg.h"
28 #include "../common/status.h"
29 #include "../common/iobuf.h"
30 #include "../common/util.h"
31 #include "filter.h"
32 #include "packet.h"
33 #include "options.h"
34 #include "main.h"
35
36 /* The size of the buffer we allocate to encrypt the data.  This must
37  * be a multiple of the OCB blocksize (16 byte).  */
38 #define AEAD_ENC_BUFFER_SIZE (64*1024)
39
40
41 /* Wrapper around iobuf_write to make sure that a proper error code is
42  * always returned.  */
43 static gpg_error_t
44 my_iobuf_write (iobuf_t a, const void *buffer, size_t buflen)
45 {
46   if (iobuf_write (a, buffer, buflen))
47     {
48       gpg_error_t err = iobuf_error (a);
49       if (!err || !gpg_err_code (err)) /* (The latter should never happen) */
50         err = gpg_error (GPG_ERR_EIO);
51       return err;
52     }
53   return 0;
54 }
55
56
57 /* Set the additional data for the current chunk.  If FINAL is set the
58  * final AEAD chunk is processed.  */
59 static gpg_error_t
60 set_additional_data (cipher_filter_context_t *cfx, int final)
61 {
62   unsigned char ad[21];
63
64   ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD);
65   ad[1] = 1;
66   ad[2] = cfx->dek->algo;
67   ad[3] = cfx->dek->use_aead;
68   ad[4] = cfx->chunkbyte;
69   ad[5] = cfx->chunkindex >> 56;
70   ad[6] = cfx->chunkindex >> 48;
71   ad[7] = cfx->chunkindex >> 40;
72   ad[8] = cfx->chunkindex >> 32;
73   ad[9] = cfx->chunkindex >> 24;
74   ad[10]= cfx->chunkindex >> 16;
75   ad[11]= cfx->chunkindex >>  8;
76   ad[12]= cfx->chunkindex;
77   if (final)
78     {
79       ad[13] = cfx->total >> 56;
80       ad[14] = cfx->total >> 48;
81       ad[15] = cfx->total >> 40;
82       ad[16] = cfx->total >> 32;
83       ad[17] = cfx->total >> 24;
84       ad[18] = cfx->total >> 16;
85       ad[19] = cfx->total >>  8;
86       ad[20] = cfx->total;
87     }
88   log_printhex (ad, final? 21 : 13, "authdata:");
89   return gcry_cipher_authenticate (cfx->cipher_hd, ad, final? 21 : 13);
90 }
91
92
93 /* Set the nonce.  This also reset the encryption machinery so that
94  * the handle can be used for a new chunk.  */
95 static gpg_error_t
96 set_nonce (cipher_filter_context_t *cfx)
97 {
98   unsigned char nonce[16];
99   int i;
100
101   switch (cfx->dek->use_aead)
102     {
103     case AEAD_ALGO_OCB:
104       memcpy (nonce, cfx->startiv, 15);
105       i = 7;
106       break;
107
108     case AEAD_ALGO_EAX:
109       memcpy (nonce, cfx->startiv, 16);
110       i = 8;
111       break;
112
113     default:
114       BUG ();
115     }
116
117   nonce[i++] ^= cfx->chunkindex >> 56;
118   nonce[i++] ^= cfx->chunkindex >> 48;
119   nonce[i++] ^= cfx->chunkindex >> 40;
120   nonce[i++] ^= cfx->chunkindex >> 32;
121   nonce[i++] ^= cfx->chunkindex >> 24;
122   nonce[i++] ^= cfx->chunkindex >> 16;
123   nonce[i++] ^= cfx->chunkindex >>  8;
124   nonce[i++] ^= cfx->chunkindex;
125
126   log_printhex (nonce, 15, "nonce:");
127   return gcry_cipher_setiv (cfx->cipher_hd, nonce, i);
128 }
129
130
131 static gpg_error_t
132 write_header (cipher_filter_context_t *cfx, iobuf_t a)
133 {
134   gpg_error_t err;
135   PACKET pkt;
136   PKT_encrypted ed;
137   unsigned int blocksize;
138   unsigned int startivlen;
139   enum gcry_cipher_modes ciphermode;
140
141   log_assert (cfx->dek->use_aead);
142
143   blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo);
144   if (blocksize != 16 )
145     log_fatal ("unsupported blocksize %u for AEAD\n", blocksize);
146
147   switch (cfx->dek->use_aead)
148     {
149     case AEAD_ALGO_OCB:
150       ciphermode = GCRY_CIPHER_MODE_OCB;
151       startivlen = 15;
152       break;
153
154     default:
155       log_error ("unsupported AEAD algo %d\n", cfx->dek->use_aead);
156       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
157       goto leave;
158     }
159
160   cfx->chunkbyte = 10;
161   cfx->chunksize = (uint64_t)1 << (cfx->chunkbyte + 6);
162   cfx->chunklen = 0;
163   cfx->bufsize = AEAD_ENC_BUFFER_SIZE;
164   cfx->buflen = 0;
165   cfx->buffer = xtrymalloc (cfx->bufsize);
166   if (!cfx->buffer)
167     return gpg_error_from_syserror ();
168
169   memset (&ed, 0, sizeof ed);
170   ed.new_ctb = 1;  /* (Is anyway required for the packet type).  */
171   ed.len = 0; /* fixme: cfx->datalen */
172   ed.extralen    = startivlen + 16; /* (16 is the taglen) */
173   ed.cipher_algo = cfx->dek->algo;
174   ed.aead_algo   = cfx->dek->use_aead;
175   ed.chunkbyte   = cfx->chunkbyte;
176
177   init_packet (&pkt);
178   pkt.pkttype = PKT_ENCRYPTED_AEAD;
179   pkt.pkt.encrypted = &ed;
180
181   log_debug ("aead packet: len=%lu extralen=%d\n",
182              (unsigned long)ed.len, ed.extralen);
183
184   write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
185                        cfx->dek->algo, ed.aead_algo);
186   print_cipher_algo_note (cfx->dek->algo);
187
188   if (build_packet( a, &pkt))
189     log_bug ("build_packet(ENCRYPTED_AEAD) failed\n");
190
191   log_assert (sizeof cfx->startiv >= startivlen);
192   gcry_randomize (cfx->startiv, startivlen, GCRY_STRONG_RANDOM);
193   err = my_iobuf_write (a, cfx->startiv, startivlen);
194   if (err)
195     goto leave;
196
197   err = openpgp_cipher_open (&cfx->cipher_hd,
198                              cfx->dek->algo,
199                              ciphermode,
200                              GCRY_CIPHER_SECURE);
201   if (err)
202     goto leave;
203
204   log_printhex (cfx->dek->key, cfx->dek->keylen, "thekey:");
205   err = gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen);
206   if (err)
207     return err;
208
209   err = set_nonce (cfx);
210   if (err)
211     return err;
212
213   err = set_additional_data (cfx, 0);
214   if (err)
215     return err;
216
217   cfx->wrote_header = 1;
218
219  leave:
220   return err;
221 }
222
223
224 /* Get and write the auth tag to stream A.  */
225 static gpg_error_t
226 write_auth_tag (cipher_filter_context_t *cfx, iobuf_t a)
227 {
228   gpg_error_t err;
229   char tag[16];
230
231   err = gcry_cipher_gettag (cfx->cipher_hd, tag, 16);
232   if (err)
233     goto leave;
234   err = my_iobuf_write (a, tag, 16);
235   if (err)
236     goto leave;
237   log_printhex (tag, 16, "wrote tag:");
238
239  leave:
240   return err;
241 }
242
243
244 /* Write the final chunk to stream A.  */
245 static gpg_error_t
246 write_final_chunk (cipher_filter_context_t *cfx, iobuf_t a)
247 {
248   gpg_error_t err;
249   char dummy[1];
250
251   cfx->chunkindex++;
252
253   err = set_nonce (cfx);
254   if (err)
255     goto leave;
256   err = set_additional_data (cfx, 1);
257   if (err)
258     goto leave;
259
260   gcry_cipher_final (cfx->cipher_hd);
261
262   /* Encrypt an empty string.  */
263   err = gcry_cipher_encrypt (cfx->cipher_hd, dummy, 0, NULL, 0);
264   if (err)
265     goto leave;
266
267   err = write_auth_tag (cfx, a);
268
269  leave:
270   return err;
271 }
272
273
274 /* The core of the flush sub-function of cipher_filter_aead.   */
275 static gpg_error_t
276 do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
277 {
278   gpg_error_t err;
279   int newchunk = 0;
280   size_t n;
281
282   /* Put the data into a buffer, flush and encrypt as needed.  */
283   log_debug ("flushing %zu bytes (cur buflen=%zu)\n", size, cfx->buflen);
284   do
285     {
286       if (cfx->buflen + size < cfx->bufsize)
287         n = size;
288       else
289         n = cfx->bufsize - cfx->buflen;
290
291       if (cfx->chunklen + n >= cfx->chunksize)
292         {
293           size_t n1 = cfx->chunksize - cfx->chunklen;
294           newchunk = 1;
295           log_debug ("chunksize %ju reached;"
296                      " cur buflen=%zu using %zu of %zu\n",
297                      (uintmax_t)cfx->chunksize, (uintmax_t)cfx->buflen,
298                      n1, n);
299           n = n1;
300         }
301
302       memcpy (cfx->buffer + cfx->buflen, buf, n);
303       cfx->buflen += n;
304       buf  += n;
305       size -= n;
306
307       if (cfx->buflen == cfx->bufsize || newchunk)
308         {
309           log_debug ("encrypting: buflen=%zu %s %p\n",
310                      cfx->buflen, newchunk?"(newchunk)":"", cfx->cipher_hd);
311           if (newchunk)
312             gcry_cipher_final (cfx->cipher_hd);
313           if (newchunk)
314             log_printhex (cfx->buffer, cfx->buflen, "plain(1):");
315           else if (cfx->buflen > 32)
316             log_printhex (cfx->buffer + cfx->buflen - 32, 32,
317                           "plain(last 32):");
318
319           /* Take care: even with a buflen of zero an encrypt needs to
320            * be called after gcry_cipher_final and before
321            * gcry_cipher_gettag - at least with libgcrypt 1.8 and OCB
322            * mode.  */
323           gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen,
324                                NULL, 0);
325           if (newchunk)
326             log_printhex (cfx->buffer, cfx->buflen, "ciphr(1):");
327           err = my_iobuf_write (a, cfx->buffer, cfx->buflen);
328           if (err)
329             goto leave;
330           cfx->chunklen += cfx->buflen;
331           cfx->total += cfx->buflen;
332           cfx->buflen = 0;
333
334           if (newchunk)
335             {
336               log_debug ("chunklen=%ju  total=%ju\n",
337                          (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
338               err = write_auth_tag (cfx, a);
339               if (err)
340                 {
341                   log_debug ("gcry_cipher_gettag failed: %s\n",
342                              gpg_strerror (err));
343                   goto leave;
344                 }
345
346               log_debug ("starting a new chunk (cur size=%zu)\n", size);
347               log_printhex (buf, size, "cur buf:");
348               cfx->chunkindex++;
349               cfx->chunklen = 0;
350               err = set_nonce (cfx);
351               if (err)
352                 goto leave;
353               err = set_additional_data (cfx, 0);
354               if (err)
355                 goto leave;
356               newchunk = 0;
357             }
358         }
359     }
360   while (size);
361
362  leave:
363   return err;
364 }
365
366
367 /* The core of the free sub-function of cipher_filter_aead.   */
368 static gpg_error_t
369 do_free (cipher_filter_context_t *cfx, iobuf_t a)
370 {
371   gpg_error_t err = 0;
372
373   /* FIXME: Check what happens if we just wrote the last chunk and no
374    * more bytes were to encrypt.  We should then not call finalize and
375    * write the auth tag again, right?  May this at all happen?  */
376
377   /* Call finalize which will also allow us to flush out and encrypt
378    * the last arbitrary length buffer.  */
379   gcry_cipher_final (cfx->cipher_hd);
380
381   /* Encrypt any remaining bytes.  */
382   if (cfx->buflen)
383     {
384       log_debug ("processing last %zu bytes of the last chunk\n", cfx->buflen);
385       log_printhex (cfx->buffer, cfx->buflen, "plain(2):");
386       gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen, NULL, 0);
387       log_printhex (cfx->buffer, cfx->buflen, "ciphr(2):");
388       err = my_iobuf_write (a, cfx->buffer, cfx->buflen);
389       if (err)
390         goto leave;
391       /* log_printhex (cfx->buffer, cfx->buflen, "wrote:"); */
392       cfx->chunklen += cfx->buflen;
393       cfx->total += cfx->buflen;
394     }
395
396   /* Get and write the authentication tag.  */
397   log_debug ("chunklen=%ju  total=%ju\n",
398              (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
399   err = write_auth_tag (cfx, a);
400   if (err)
401     goto leave;
402
403   /* Write the final chunk.  */
404   log_debug ("creating final chunk\n");
405   err = write_final_chunk (cfx, a);
406
407  leave:
408   xfree (cfx->buffer);
409   cfx->buffer = NULL;
410   /* gcry_cipher_close (cfx->cipher_hd); */
411   /* cfx->cipher_hd = NULL; */
412   return err;
413 }
414
415
416 /*
417  * This filter is used to encrypt data with an AEAD algorithm
418  */
419 int
420 cipher_filter_aead (void *opaque, int control,
421                     iobuf_t a, byte *buf, size_t *ret_len)
422 {
423   cipher_filter_context_t *cfx = opaque;
424   size_t size = *ret_len;
425   int rc = 0;
426
427   if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
428     {
429       rc = -1; /* not used */
430     }
431   else if (control == IOBUFCTRL_FLUSH) /* encrypt */
432     {
433       if (!cfx->wrote_header && (rc=write_header (cfx, a)))
434         ;
435       else
436         rc = do_flush (cfx, a, buf, size);
437     }
438   else if (control == IOBUFCTRL_FREE)
439     {
440       rc = do_free (cfx, a);
441     }
442   else if (control == IOBUFCTRL_DESC)
443     {
444       mem2str (buf, "cipher_filter_aead", *ret_len);
445     }
446
447   return rc;
448 }