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