[git] GnuPG - branch, master, updated. gnupg-2.2.3-116-g81d7181

by Werner Koch cvs at cvs.gnupg.org
Wed Jan 10 17:39:49 CET 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  81d71818d054a5faa9153fd52a4b79bbbb71e9d5 (commit)
       via  4e2ba546cdccbbc6d3e29867ee5671fd44d74e67 (commit)
       via  8217cd49364b9f81b390f7ca6a608dd946f93efc (commit)
      from  945381c4c26ffa5a9b1b0781294d0440e55d2ade (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 81d71818d054a5faa9153fd52a4b79bbbb71e9d5
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jan 10 17:33:50 2018 +0100

    gpg: Add stub function for encrypting AEAD.
    
    * g10/cipher.c (cipher_filter): Rename to cipher_filter_cfb.
    * g10/cipher-aead.c: New.  Right now only with a stub function.
    * g10/Makefile.am (gpg_sources): Add file.
    * g10/encrypt.c (encrypt_simple): Push either cipher_filter_cfb or
    cipher_filter_aead.
    (encrypt_crypt): Ditto.
    (encrypt_filter): Ditto.
    * g10/sign.c (sign_symencrypt_file): Ditto.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/Makefile.am b/g10/Makefile.am
index cc4ef5c..cba65b2 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -132,6 +132,7 @@ gpg_sources = server.c          \
 	      decrypt.c 	\
 	      decrypt-data.c	\
 	      cipher.c		\
+	      cipher-aead.c     \
 	      encrypt.c		\
 	      sign.c		\
 	      verify.c		\
diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c
new file mode 100644
index 0000000..bf0afcf
--- /dev/null
+++ b/g10/cipher-aead.c
@@ -0,0 +1,67 @@
+/* cipher-aead.c - Enciphering filter for AEAD modes
+ * Copyright (C) 2018 Werner koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0+
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpg.h"
+#include "../common/status.h"
+#include "../common/iobuf.h"
+#include "../common/util.h"
+#include "filter.h"
+#include "packet.h"
+#include "options.h"
+#include "main.h"
+
+
+/*
+ * This filter is used to encipher data with an AEAD algorithm
+ */
+int
+cipher_filter_aead (void *opaque, int control,
+                   iobuf_t a, byte *buf, size_t *ret_len)
+{
+  cipher_filter_context_t *cfx = opaque;
+  size_t size = *ret_len;
+  int rc = 0;
+
+  if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
+    {
+      rc = -1; /* not yet used */
+    }
+  else if (control == IOBUFCTRL_FLUSH) /* encrypt */
+    {
+      log_assert (a);
+      rc = GPG_ERR_NOT_IMPLEMENTED;
+    }
+  else if (control == IOBUFCTRL_FREE)
+    {
+      gcry_cipher_close (cfx->cipher_hd);
+    }
+  else if (control == IOBUFCTRL_DESC)
+    {
+      mem2str (buf, "cipher_filter_aead", *ret_len);
+    }
+
+  return rc;
+}
diff --git a/g10/cipher.c b/g10/cipher.c
index b950d0c..ad7399d 100644
--- a/g10/cipher.c
+++ b/g10/cipher.c
@@ -1,4 +1,4 @@
-/* cipher.c - En-/De-ciphering filter
+/* cipher.c - Enciphering filter for the old CFB mode.
  * Copyright (C) 1998-2003, 2006, 2009 Free Software Foundation, Inc.
  * Copyright (C) 1998-2003, 2006, 2009, 2017 Werner koch
  *
@@ -117,7 +117,8 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
  * This filter is used to en/de-cipher data with a symmetric algorithm
  */
 int
-cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len)
+cipher_filter_cfb (void *opaque, int control,
+                   iobuf_t a, byte *buf, size_t *ret_len)
 {
   cipher_filter_context_t *cfx = opaque;
   size_t size = *ret_len;
@@ -177,7 +178,7 @@ cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len)
     }
   else if (control == IOBUFCTRL_DESC)
     {
-      mem2str (buf, "cipher_filter", *ret_len);
+      mem2str (buf, "cipher_filter_cfb", *ret_len);
     }
 
   return rc;
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 2951a45..01feb4a 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -409,7 +409,10 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
 
   /* Register the cipher filter. */
   if (mode)
-    iobuf_push_filter ( out, cipher_filter, &cfx );
+    iobuf_push_filter (out,
+                       cfx.dek->use_aead? cipher_filter_aead
+                       /**/             : cipher_filter_cfb,
+                       &cfx );
 
   /* Register the compress filter. */
   if ( do_compress )
@@ -800,7 +803,10 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
     cfx.datalen = filesize && !do_compress ? filesize : 0;
 
   /* Register the cipher filter. */
-  iobuf_push_filter (out, cipher_filter, &cfx);
+  iobuf_push_filter (out,
+                     cfx.dek->use_aead? cipher_filter_aead
+                     /**/             : cipher_filter_cfb,
+                     &cfx);
 
   /* Register the compress filter. */
   if (do_compress)
@@ -959,7 +965,10 @@ encrypt_filter (void *opaque, int control,
                 return rc;
             }
 
-          iobuf_push_filter (a, cipher_filter, &efx->cfx);
+          iobuf_push_filter (a,
+                             efx->cfx.dek->use_aead? cipher_filter_aead
+                             /**/                  : cipher_filter_cfb,
+                             &efx->cfx);
 
           efx->header_okay = 1;
         }
diff --git a/g10/filter.h b/g10/filter.h
index 9e4b1e5..2924355 100644
--- a/g10/filter.h
+++ b/g10/filter.h
@@ -145,8 +145,12 @@ void push_compress_filter2(iobuf_t out,compress_filter_context_t *zfx,
 			   int algo,int rel);
 
 /*-- cipher.c --*/
-int cipher_filter( void *opaque, int control,
-		   iobuf_t chain, byte *buf, size_t *ret_len);
+int cipher_filter_cfb (void *opaque, int control,
+                       iobuf_t chain, byte *buf, size_t *ret_len);
+
+/*-- cipher-aead.c --*/
+int cipher_filter_aead (void *opaque, int control,
+                        iobuf_t chain, byte *buf, size_t *ret_len);
 
 /*-- textfilter.c --*/
 int text_filter( void *opaque, int control,
diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c
index 8c156d2..f879838 100644
--- a/g10/gpgcompose.c
+++ b/g10/gpgcompose.c
@@ -2573,7 +2573,7 @@ encrypted (const char *option, int argc, char *argv[], void *cookie)
 
   cfx->datalen = 0;
 
-  filter_push (out, cipher_filter, cfx, PKT_ENCRYPTED, cfx->datalen == 0);
+  filter_push (out, cipher_filter_cfb, cfx, PKT_ENCRYPTED, cfx->datalen == 0);
 
   debug ("Wrote encrypted packet:\n");
 
diff --git a/g10/sign.c b/g10/sign.c
index f8a1241..051ab59 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1379,7 +1379,10 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
     }
 
     /* Push the encryption filter */
-    iobuf_push_filter( out, cipher_filter, &cfx );
+    iobuf_push_filter (out,
+                       cfx.dek->use_aead? cipher_filter_aead
+                       /**/             : cipher_filter_cfb,
+                       &cfx);
 
     /* Push the compress filter */
     if (default_compress_algo())

commit 4e2ba546cdccbbc6d3e29867ee5671fd44d74e67
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jan 10 17:07:11 2018 +0100

    gpg: New option --force-aead
    
    * g10/dek.h (DEK): Turn fields use_mdc, algo_printed and symmetric
    into single bit vars.  Make sure they are always set to 1 or 0.
    (DEK): New field use_aead.
    * g10/options.h (struct opt): New field force_aead.
    * g10/pkclist.c (select_aead_from_pklist): New.
    * g10/gpg.c (oForceAEAD): New const.
    (opts): New options "--force-aead".
    (main): Set new option.
    * g10/encrypt.c (use_aead): New.
    (encrypt_simple): Implement new flags DEK.use_aead.
    (encrypt_crypt): Ditto.
    (encrypt_filter): Ditto.
    * g10/sign.c (sign_symencrypt_file): Ditto.
    --
    
    This patch should be enough to detect whether AEAD can be used.
    Not tested.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/dek.h b/g10/dek.h
index 666810c..64e98fc 100644
--- a/g10/dek.h
+++ b/g10/dek.h
@@ -1,5 +1,5 @@
 /* dek.h - The data encryption key structure.
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2014, 2017 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -26,14 +26,25 @@ typedef struct
   int algo;
   /* The length of the key (in bytes).  */
   int keylen;
+
   /* Whether we've already printed information about this key.  This
-     is currently only used in decrypt_data() and only if we are in
-     verbose mode.  */
-  int algo_info_printed;
-  int use_mdc;
+   * is currently only used in decrypt_data() and only if we are in
+   * verbose mode.  */
+  int algo_info_printed : 1;
+
+  /* AEAD shall be used.  */
+  int use_aead : 1;
+
+  /* MDC shall be used.  */
+  int use_mdc : 1;
+
   /* This key was read from a SK-ESK packet (see proc_symkey_enc).  */
-  int symmetric;
-  byte key[32]; /* This is the largest used keylen (256 bit). */
+  int symmetric : 1;
+
+  /* This is the largest used keylen (256 bit). */
+  byte key[32];
+
+  /* The cacheid for the S2K. */
   char s2k_cacheid[1+16+1];
 } DEK;
 
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 263226a..2951a45 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -109,6 +109,47 @@ encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
 }
 
 
+/* Return true if we shall use AEAD mode.  */
+int
+use_aead (pk_list_t pk_list, int algo)
+{
+  int can_use;
+
+  if (!opt.flags.rfc4880bis)
+    {
+      if (opt.force_aead)
+        log_info ("Warning: Option %s currently requires option '%s'\n",
+                  "--force-aead", "--rfc4880bis");
+      return 0;
+    }
+
+  can_use = openpgp_cipher_get_algo_blklen (algo) != 16;
+
+  /* With --force-mdc we clearly do not want AEAD.  */
+  if (opt.force_mdc)
+    return 0;
+
+  /* However with --force-aead we want AEAD.  */
+  if (opt.force_aead)
+    {
+      if (!can_use)
+        log_info ("Warning: request to use AEAD ignored for cipher '%s'\n",
+                  openpgp_cipher_algo_name (algo));
+      return 1;
+    }
+
+  /* AEAD does noly work with 128 bit cipher blocklength.  */
+  if (!can_use)
+    return 0;
+
+  /* If all keys support AEAD we can use it.  */
+  if (select_aead_from_pklist (pk_list))
+    return 1;
+
+  return 0; /* No AEAD. */
+}
+
+
 /* We try very hard to use a MDC */
 int
 use_mdc (pk_list_t pk_list,int algo)
@@ -265,10 +306,15 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
         log_info(_("using cipher %s\n"),
                  openpgp_cipher_algo_name (cfx.dek->algo));
 
-      cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
+      if (use_aead (NULL, cfx.dek->algo))
+        cfx.dek->use_aead = 1;
+      else
+        cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
     }
 
-  if (do_compress && cfx.dek && cfx.dek->use_mdc
+  if (do_compress
+      && cfx.dek
+      && (cfx.dek->use_mdc || cfx.dek->use_aead)
       && is_file_compressed(filename, &rc))
     {
       if (opt.verbose)
@@ -368,7 +414,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   /* Register the compress filter. */
   if ( do_compress )
     {
-      if (cfx.dek && cfx.dek->use_mdc)
+      if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
         zfx.new_ctb = 1;
       push_compress_filter (out, &zfx, default_compress_algo());
     }
@@ -676,14 +722,18 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
                           gnupg_status_compliance_flag (CO_DE_VS),
                           NULL);
 
-  cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo);
+  if (use_aead (pk_list, cfx.dek->algo))
+    cfx.dek->use_aead = 1;
+  else
+    cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo);
 
   /* Only do the is-file-already-compressed check if we are using a
-     MDC.  This forces compressed files to be re-compressed if we do
-     not have a MDC to give some protection against chosen ciphertext
-     attacks. */
-
-  if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2))
+   * MDC or AEAD.  This forces compressed files to be re-compressed if
+   * we do not have a MDC to give some protection against chosen
+   * ciphertext attacks. */
+  if (do_compress
+      && (cfx.dek->use_mdc || cfx.dek->use_aead)
+      && is_file_compressed (filename, &rc2))
     {
       if (opt.verbose)
         log_info(_("'%s' already compressed\n"), filename);
@@ -777,7 +827,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
       /* Algo 0 means no compression. */
       if (compr_algo)
         {
-          if (cfx.dek && cfx.dek->use_mdc)
+          if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
             zfx.new_ctb = 1;
           push_compress_filter (out,&zfx,compr_algo);
         }
@@ -887,7 +937,10 @@ encrypt_filter (void *opaque, int control,
 	      efx->cfx.dek->algo = opt.def_cipher_algo;
 	    }
 
-          efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
+          if (use_aead (efx->pk_list, efx->cfx.dek->algo))
+            efx->cfx.dek->use_aead = 1;
+          else
+            efx->cfx.dek->use_mdc = !!use_mdc (efx->pk_list,efx->cfx.dek->algo);
 
           make_session_key ( efx->cfx.dek );
           if (DBG_CRYPTO)
diff --git a/g10/gpg.c b/g10/gpg.c
index fadd2f0..a643388 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -304,6 +304,7 @@ enum cmd_and_opt_values
     oNoForceMDC,
     oDisableMDC,
     oNoDisableMDC,
+    oForceAEAD,
     oS2KMode,
     oS2KDigest,
     oS2KCipher,
@@ -605,6 +606,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oDisableMDC, "disable-mdc", "@"),
   ARGPARSE_s_n (oNoDisableMDC, "no-disable-mdc", "@"),
 
+  ARGPARSE_s_n (oForceAEAD, "force-aead", "@"),
+
   ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
 
   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
@@ -2977,6 +2980,8 @@ main (int argc, char **argv)
 	  case oDisableMDC: opt.disable_mdc = 1; break;
 	  case oNoDisableMDC: opt.disable_mdc = 0; break;
 
+	  case oForceAEAD: opt.force_aead = 1; break;
+
           case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break;
 
 	  case oS2KMode:   opt.s2k_mode = pargs.r.ret_int; break;
diff --git a/g10/keydb.h b/g10/keydb.h
index 7393768..9f6064b 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -232,6 +232,7 @@ int  algo_available( preftype_t preftype, int algo,
 int  select_algo_from_prefs( PK_LIST pk_list, int preftype,
 			     int request, const union pref_hint *hint);
 int  select_mdc_from_pklist (PK_LIST pk_list);
+int  select_aead_from_pklist (pk_list_t pk_list);
 void warn_missing_mdc_from_pklist (PK_LIST pk_list);
 void warn_missing_aes_from_pklist (PK_LIST pk_list);
 
diff --git a/g10/main.h b/g10/main.h
index 6abc598..393a1b0 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -233,6 +233,7 @@ void display_online_help( const char *keyword );
 /*-- encode.c --*/
 int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
 void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey);
+int use_aead (pk_list_t pk_list, int algo);
 int use_mdc (pk_list_t pk_list,int algo);
 int encrypt_symmetric (const char *filename );
 int encrypt_store (const char *filename );
diff --git a/g10/options.h b/g10/options.h
index 6ad1037..36bea69 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -95,6 +95,7 @@ struct
   int def_aead_algo;
   int force_mdc;
   int disable_mdc;
+  int force_aead;
   int def_digest_algo;
   int cert_digest_algo;
   int compress_algo;
diff --git a/g10/pkclist.c b/g10/pkclist.c
index a759672..b85efa4 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1651,6 +1651,31 @@ select_mdc_from_pklist (PK_LIST pk_list)
 }
 
 
+/* Select the AEAD flag from the pk_list.  We can only use AEAD if all
+ * recipients support this feature.  Returns true if AEAD can be used.  */
+int
+select_aead_from_pklist (PK_LIST pk_list)
+{
+  pk_list_t pkr;
+  int aead;
+
+  if (!pk_list)
+    return 0;
+
+  for (pkr = pk_list; pkr; pkr = pkr->next)
+    {
+      if (pkr->pk->user_id) /* selected by user ID */
+        aead = pkr->pk->user_id->flags.aead;
+      else
+        aead = pkr->pk->flags.aead;
+      if (!aead)
+        return 0;  /* At least one recipient does not support it. */
+    }
+
+  return 1; /* Can be used. */
+}
+
+
 /* Print a warning for all keys in PK_LIST missing the MDC feature. */
 void
 warn_missing_mdc_from_pklist (PK_LIST pk_list)
diff --git a/g10/sign.c b/g10/sign.c
index 4cf0cd3..f8a1241 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1337,7 +1337,10 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
         goto leave;
     }
 
-    cfx.dek->use_mdc = use_mdc (NULL, cfx.dek->algo);
+    if (use_aead (NULL, cfx.dek->algo))
+      cfx.dek->use_aead = 1;
+    else
+      cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
 
     /* now create the outfile */
     rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
@@ -1381,7 +1384,7 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
     /* Push the compress filter */
     if (default_compress_algo())
       {
-        if (cfx.dek && cfx.dek->use_mdc)
+        if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
           zfx.new_ctb = 1;
         push_compress_filter (out, &zfx,default_compress_algo() );
       }

commit 8217cd49364b9f81b390f7ca6a608dd946f93efc
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jan 10 11:42:38 2018 +0100

    gpg: Add option and preference framework for AEAD.
    
    * common/openpgpdefs.h (aead_algo_t): New.
    (SIGSUBPKT_PREF_AEAD): New.
    * g10/gpg.c (oAEADAlgo, oPersonalAEADPreferences): New.
    (opts): New options --aead-algo and --personal-aead-preferences.
    (set_compliance_option): Clar aead algo.
    (main): Parse and check the new options
    * g10/options.h (struct opt): Add fields def_aead_algo and
    personal_aead_prefs.
    * g10/packet.h (PREFTYPE_AEAD): New enum value.
    (PKT_user_id): Add field flags.aead.
    (PKT_public_key): Add field flags.aead.
    * g10/pkclist.c (select_algo_from_prefs): Support PREFTYPE_AEAD.
    * g10/getkey.c (fixup_uidnode): Set AEAD flag.
    (merge_selfsigs): Ditto.
    * g10/kbnode.c (dump_kbnode): Show aead flag.
    * g10/keyedit.c (show_prefs): Ditto.
    (show_key_with_all_names_colon): Ditto.
    * g10/keygen.c (aead_presf, n_aead_prefs): New vars.
    (set_one_pref): Suppport PREFTYPE_AEAD.
    (keygen_set_std_prefs): Parse AEAD preferences.
    (keygen_get_std_prefs): Ditto.
    (add_feature_aead): New.
    (keygen_upd_std_prefs): Call that and build AEAD pref  packet.
    * g10/main.h (DEFAULT_AEAD_ALGO): New const.
    * g10/misc.c (openpgp_aead_test_algo): New.
    (openpgp_aead_algo_name): New.
    (string_to_aead_algo): New.
    (default_aead_algo): New.
    --
    
    This is only used in --rfc4880bis mode and not really tested.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h
index 85a4251..aeb3389 100644
--- a/common/openpgpdefs.h
+++ b/common/openpgpdefs.h
@@ -115,7 +115,8 @@ typedef enum
     SIGSUBPKT_FEATURES      = 30, /* Feature flags. */
 
     SIGSUBPKT_SIGNATURE     = 32, /* Embedded signature. */
-    SIGSUBPKT_ISSUER_FPR    = 33, /* EXPERIMENTAL: Issuer fingerprint. */
+    SIGSUBPKT_ISSUER_FPR    = 33, /* Issuer fingerprint. */
+    SIGSUBPKT_PREF_AEAD     = 34, /* Preferred AEAD algorithms. */
 
     SIGSUBPKT_FLAG_CRITICAL = 128
   }
@@ -144,6 +145,15 @@ cipher_algo_t;
 
 typedef enum
   {
+    AEAD_ALGO_NONE	    =  0,
+    AEAD_ALGO_EAX	    =  1,
+    AEAD_ALGO_OCB	    =  2
+  }
+aead_algo_t;
+
+
+typedef enum
+  {
     PUBKEY_ALGO_RSA         =  1,
     PUBKEY_ALGO_RSA_E       =  2, /* RSA encrypt only (legacy). */
     PUBKEY_ALGO_RSA_S       =  3, /* RSA sign only (legacy).    */
diff --git a/g10/getkey.c b/g10/getkey.c
index dabd052..497dace 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -2539,6 +2539,12 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
   if (p && n && (p[0] & 0x01))
     uid->flags.mdc = 1;
 
+  /* See whether we have the AEAD feature.  */
+  uid->flags.aead = 0;
+  p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+  if (p && n && (p[0] & 0x01))
+    uid->flags.aead = 1;
+
   /* And the keyserver modify flag.  */
   uid->flags.ks_modify = 1;
   p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
@@ -3357,6 +3363,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
   PKT_public_key *main_pk;
   prefitem_t *prefs;
   unsigned int mdc_feature;
+  unsigned int aead_feature;
 
   if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
     {
@@ -3418,7 +3425,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
    * all preferences.
    * Do a similar thing for the MDC feature flag.  */
   prefs = NULL;
-  mdc_feature = 0;
+  mdc_feature = aead_feature = 0;
   for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
     {
       if (k->pkt->pkttype == PKT_USER_ID
@@ -3427,6 +3434,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
 	{
 	  prefs = k->pkt->pkt.user_id->prefs;
 	  mdc_feature = k->pkt->pkt.user_id->flags.mdc;
+	  aead_feature = k->pkt->pkt.user_id->flags.aead;
 	  break;
 	}
     }
@@ -3440,6 +3448,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
 	    xfree (pk->prefs);
 	  pk->prefs = copy_prefs (prefs);
 	  pk->flags.mdc = mdc_feature;
+	  pk->flags.aead = aead_feature;
 	}
     }
 }
diff --git a/g10/gpg.c b/g10/gpg.c
index 61e39b8..fadd2f0 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -245,6 +245,7 @@ enum cmd_and_opt_values
     oRFC2440Text,
     oNoRFC2440Text,
     oCipherAlgo,
+    oAEADAlgo,
     oDigestAlgo,
     oCertDigestAlgo,
     oCompressAlgo,
@@ -371,6 +372,7 @@ enum cmd_and_opt_values
     oDefaultPreferenceList,
     oDefaultKeyserverURL,
     oPersonalCipherPreferences,
+    oPersonalAEADPreferences,
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
     oAgentProgram,
@@ -668,6 +670,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"),
   ARGPARSE_s_i (oS2KCount, "s2k-count", "@"),
   ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"),
+  ARGPARSE_s_s (oAEADAlgo,   "aead-algo", "@"),
   ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"),
   ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"),
   ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"),
@@ -824,6 +827,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDefaultPreferenceList,  "default-preference-list", "@"),
   ARGPARSE_s_s (oDefaultKeyserverURL,  "default-keyserver-url", "@"),
   ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"),
+  ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-preferences","@"),
   ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"),
   ARGPARSE_s_s (oPersonalCompressPreferences,
                                          "personal-compress-preferences", "@"),
@@ -835,6 +839,7 @@ static ARGPARSE_OPTS opts[] = {
   /* Aliases.  I constantly mistype these, and assume other people do
      as well. */
   ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"),
+  ARGPARSE_s_s (oPersonalAEADPreferences,   "personal-aead-prefs", "@"),
   ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"),
   ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
 
@@ -2125,6 +2130,7 @@ set_compliance_option (enum cmd_and_opt_values option)
       opt.escape_from = 1;
       opt.not_dash_escaped = 0;
       opt.def_cipher_algo = 0;
+      opt.def_aead_algo = 0;
       opt.def_digest_algo = 0;
       opt.cert_digest_algo = 0;
       opt.compress_algo = -1;
@@ -2141,6 +2147,7 @@ set_compliance_option (enum cmd_and_opt_values option)
       opt.escape_from = 0;
       opt.not_dash_escaped = 0;
       opt.def_cipher_algo = 0;
+      opt.def_aead_algo = 0;
       opt.def_digest_algo = 0;
       opt.cert_digest_algo = 0;
       opt.compress_algo = -1;
@@ -2157,6 +2164,7 @@ set_compliance_option (enum cmd_and_opt_values option)
       set_compliance_option (oOpenPGP);
       opt.compliance = CO_DE_VS;
       opt.force_mdc = 1;
+      opt.def_aead_algo = 0;
       /* Fixme: Change other options.  */
       break;
 
@@ -2286,12 +2294,14 @@ main (int argc, char **argv)
     const char *trustdb_name = NULL;
 #endif /*!NO_TRUST_MODELS*/
     char *def_cipher_string = NULL;
+    char *def_aead_string = NULL;
     char *def_digest_string = NULL;
     char *compress_algo_string = NULL;
     char *cert_digest_string = NULL;
     char *s2k_cipher_string = NULL;
     char *s2k_digest_string = NULL;
     char *pers_cipher_list = NULL;
+    char *pers_aead_list = NULL;
     char *pers_digest_list = NULL;
     char *pers_compress_list = NULL;
     int eyes_only=0;
@@ -2355,6 +2365,7 @@ main (int argc, char **argv)
     opt.bz2_compress_level = -1; /* defaults to standard compress level */
     /* note: if you change these lines, look at oOpenPGP */
     opt.def_cipher_algo = 0;
+    opt.def_aead_algo = 0;
     opt.def_digest_algo = 0;
     opt.cert_digest_algo = 0;
     opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */
@@ -3113,6 +3124,9 @@ main (int argc, char **argv)
 	  case oCipherAlgo:
             def_cipher_string = xstrdup(pargs.r.ret_str);
             break;
+	  case oAEADAlgo:
+            def_aead_string = xstrdup (pargs.r.ret_str);
+            break;
 	  case oDigestAlgo:
             def_digest_string = xstrdup(pargs.r.ret_str);
             break;
@@ -3392,6 +3406,9 @@ main (int argc, char **argv)
           case oPersonalCipherPreferences:
 	    pers_cipher_list=pargs.r.ret_str;
 	    break;
+          case oPersonalAEADPreferences:
+	    pers_aead_list = pargs.r.ret_str;
+	    break;
           case oPersonalDigestPreferences:
 	    pers_digest_list=pargs.r.ret_str;
 	    break;
@@ -3737,6 +3754,13 @@ main (int argc, char **argv)
 	if ( openpgp_cipher_test_algo (opt.def_cipher_algo) )
 	    log_error(_("selected cipher algorithm is invalid\n"));
     }
+    if (def_aead_string)
+      {
+	opt.def_aead_algo = string_to_aead_algo (def_aead_string);
+	xfree (def_aead_string); def_aead_string = NULL;
+	if (openpgp_aead_test_algo (opt.def_aead_algo))
+          log_error(_("selected AEAD algorithm is invalid\n"));
+      }
     if( def_digest_string ) {
 	opt.def_digest_algo = string_to_digest_algo (def_digest_string);
 	xfree(def_digest_string); def_digest_string = NULL;
@@ -3796,6 +3820,9 @@ main (int argc, char **argv)
        keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM))
       log_error(_("invalid personal cipher preferences\n"));
 
+    if (pers_aead_list && keygen_set_std_prefs (pers_aead_list, PREFTYPE_AEAD))
+      log_error(_("invalid personal AEAD preferences\n"));
+
     if(pers_digest_list &&
        keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH))
       log_error(_("invalid personal digest preferences\n"));
@@ -3861,6 +3888,12 @@ main (int argc, char **argv)
 	    badalg = openpgp_cipher_algo_name (opt.def_cipher_algo);
 	    badtype = PREFTYPE_SYM;
 	  }
+	else if(opt.def_aead_algo
+	   && !algo_available(PREFTYPE_AEAD, opt.def_aead_algo, NULL))
+	  {
+	    badalg = openpgp_aead_algo_name (opt.def_aead_algo);
+	    badtype = PREFTYPE_AEAD;
+	  }
 	else if(opt.def_digest_algo
 		&& !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL))
 	  {
@@ -3890,6 +3923,12 @@ main (int argc, char **argv)
 			 badalg,
                           gnupg_compliance_option_string (opt.compliance));
 		break;
+	      case PREFTYPE_AEAD:
+		log_info (_("AEAD algorithm '%s'"
+                            " may not be used in %s mode\n"),
+                          badalg,
+                          gnupg_compliance_option_string (opt.compliance));
+		break;
 	      case PREFTYPE_HASH:
 		log_info (_("digest algorithm '%s'"
                             " may not be used in %s mode\n"),
@@ -3915,6 +3954,7 @@ main (int argc, char **argv)
      * is not.  This is us being nice to the user informing her early
      * that the chosen algorithms are not available.  We also check
      * and enforce this right before the actual operation.  */
+    /* FIXME: We also need to check the AEAD algo. */
     if (opt.def_cipher_algo
 	&& ! gnupg_cipher_is_allowed (opt.compliance,
 				      cmd == aEncr
diff --git a/g10/kbnode.c b/g10/kbnode.c
index c2aaacd..64def05 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -415,13 +415,14 @@ dump_kbnode (KBNODE node)
         {
           PKT_public_key *pk = node->pkt->pkt.public_key;
 
-          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c\n",
+          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c%c\n",
                       (ulong)keyid_from_pk( pk, NULL ),
                       pk->pubkey_algo, pk->pubkey_usage,
                       pk->has_expired? 'e':'.',
                       pk->flags.revoked? 'r':'.',
                       pk->flags.valid?    'v':'.',
-                      pk->flags.mdc?   'm':'.');
+                      pk->flags.mdc?   'm':'.',
+                      pk->flags.aead?  'a':'.');
         }
       else
         log_printf ("\n");
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 8d86253..81344eb 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -3118,7 +3118,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
 	    }
 	  tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
 	}
-      if (uid->flags.mdc || !uid->flags.ks_modify)
+      if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify)
 	{
 	  tty_printf ("\n     ");
 	  tty_printf (_("Features: "));
@@ -3128,6 +3128,12 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
 	      tty_printf ("MDC");
 	      any = 1;
 	    }
+	  if (!uid->flags.aead)
+	    {
+	      if (any)
+		tty_printf (", ");
+	      tty_printf ("AEAD");
+	    }
 	  if (!uid->flags.ks_modify)
 	    {
 	      if (any)
@@ -3172,6 +3178,8 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
 	}
       if (uid->flags.mdc)
 	tty_printf (" [mdc]");
+      if (uid->flags.aead)
+	tty_printf (" [aead]");
       if (!uid->flags.ks_modify)
 	tty_printf (" [no-ks-modify]");
       tty_printf ("\n");
@@ -3317,6 +3325,8 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
 		}
 	      if (uid->flags.mdc)
 		es_fputs (",mdc", fp);
+	      if (uid->flags.aead)
+		es_fputs (",aead", fp);
 	      if (!uid->flags.ks_modify)
 		es_fputs (",no-ks-modify", fp);
 	    }
diff --git a/g10/keygen.c b/g10/keygen.c
index 912fa39..d5f7782 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -127,6 +127,9 @@ struct opaque_data_usage_and_pk {
 };
 
 
+/* FIXME: These globals vars are ugly.  And using MAX_PREFS even for
+ * aeads is useless, given that we don't expects more than a very few
+ * algorithms.  */
 static int prefs_initialized = 0;
 static byte sym_prefs[MAX_PREFS];
 static int nsym_prefs;
@@ -134,7 +137,11 @@ static byte hash_prefs[MAX_PREFS];
 static int nhash_prefs;
 static byte zip_prefs[MAX_PREFS];
 static int nzip_prefs;
-static int mdc_available,ks_modify;
+static byte aead_prefs[MAX_PREFS];
+static int naead_prefs;
+static int mdc_available;
+static int ks_modify;
+static int aead_available;
 
 static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
                                      const char *algostr, const char *usagestr,
@@ -326,6 +333,8 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
 	  log_info(_("too many digest preferences\n"));
 	else if(type==3)
 	  log_info(_("too many compression preferences\n"));
+	else if(type==4)
+	  log_info(_("too many AEAD preferences\n"));
 	else
 	  BUG();
 
@@ -346,10 +355,10 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
 int
 keygen_set_std_prefs (const char *string,int personal)
 {
-    byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
-    int nsym=0, nhash=0, nzip=0, val, rc=0;
+    byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS], aead[MAX_PREFS];
+    int nsym=0, nhash=0, nzip=0, naead=0, val, rc=0;
     int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */
-    char dummy_string[20*4+1]; /* Enough for 20 items. */
+    char dummy_string[25*4+1]; /* Enough for 25 items. */
 
     if (!string || !ascii_strcasecmp (string, "default"))
       {
@@ -383,6 +392,11 @@ keygen_set_std_prefs (const char *string,int personal)
 	      strcat(dummy_string,"S7 ");
 	    strcat(dummy_string,"S2 "); /* 3DES */
 
+            if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB))
+	      strcat(dummy_string,"A2 ");
+            if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_EAX))
+	      strcat(dummy_string,"A1 ");
+
             if (personal)
               {
                 /* The default internal hash algo order is:
@@ -475,6 +489,11 @@ keygen_set_std_prefs (const char *string,int personal)
 		if(set_one_pref(val,3,tok,zip,&nzip))
 		  rc=-1;
 	      }
+	    else if ((val=string_to_aead_algo (tok)))
+	      {
+		if (set_one_pref (val, 4, tok, aead, &naead))
+		  rc = -1;
+	      }
 	    else if (ascii_strcasecmp(tok,"mdc")==0)
 	      mdc=1;
 	    else if (ascii_strcasecmp(tok,"no-mdc")==0)
@@ -520,6 +539,29 @@ keygen_set_std_prefs (const char *string,int personal)
 		    opt.personal_cipher_prefs[i].value = 0;
 		  }
 	      }
+	    else if (personal == PREFTYPE_AEAD)
+	      {
+		xfree(opt.personal_aead_prefs);
+
+		if (!naead)
+		  opt.personal_aead_prefs = NULL;
+		else
+		  {
+		    int i;
+
+		    opt.personal_aead_prefs=
+		      xmalloc(sizeof(prefitem_t *)*(naead+1));
+
+		    for (i=0; i<naead; i++)
+		      {
+			opt.personal_aead_prefs[i].type = PREFTYPE_AEAD;
+			opt.personal_aead_prefs[i].value = sym[i];
+		      }
+
+		    opt.personal_aead_prefs[i].type = PREFTYPE_NONE;
+		    opt.personal_aead_prefs[i].value = 0;
+		  }
+	      }
 	    else if(personal==PREFTYPE_HASH)
 	      {
 		xfree(opt.personal_digest_prefs);
@@ -572,7 +614,9 @@ keygen_set_std_prefs (const char *string,int personal)
 	    memcpy (sym_prefs,  sym,  (nsym_prefs=nsym));
 	    memcpy (hash_prefs, hash, (nhash_prefs=nhash));
 	    memcpy (zip_prefs,  zip,  (nzip_prefs=nzip));
+	    memcpy (aead_prefs, aead,  (naead_prefs=naead));
 	    mdc_available = mdc;
+            aead_available = !!naead;
 	    ks_modify = modify;
 	    prefs_initialized = 1;
 	  }
@@ -581,6 +625,7 @@ keygen_set_std_prefs (const char *string,int personal)
     return rc;
 }
 
+
 /* Return a fake user ID containing the preferences.  Caller must
    free. */
 PKT_user_id *
@@ -594,8 +639,8 @@ keygen_get_std_prefs(void)
 
   uid->ref=1;
 
-  uid->prefs=xmalloc((sizeof(prefitem_t *)*
-		      (nsym_prefs+nhash_prefs+nzip_prefs+1)));
+  uid->prefs = xmalloc ((sizeof(prefitem_t *)*
+                         (nsym_prefs+naead_prefs+nhash_prefs+nzip_prefs+1)));
 
   for(i=0;i<nsym_prefs;i++,j++)
     {
@@ -603,6 +648,12 @@ keygen_get_std_prefs(void)
       uid->prefs[j].value=sym_prefs[i];
     }
 
+  for (i=0; i < naead_prefs; i++, j++)
+    {
+      uid->prefs[j].type = PREFTYPE_AEAD;
+      uid->prefs[j].value = aead_prefs[i];
+    }
+
   for(i=0;i<nhash_prefs;i++,j++)
     {
       uid->prefs[j].type=PREFTYPE_HASH;
@@ -618,8 +669,9 @@ keygen_get_std_prefs(void)
   uid->prefs[j].type=PREFTYPE_NONE;
   uid->prefs[j].value=0;
 
-  uid->flags.mdc=mdc_available;
-  uid->flags.ks_modify=ks_modify;
+  uid->flags.mdc = mdc_available;
+  uid->flags.aead = aead_available;
+  uid->flags.ks_modify = ks_modify;
 
   return uid;
 }
@@ -665,6 +717,49 @@ add_feature_mdc (PKT_signature *sig,int enabled)
     xfree (buf);
 }
 
+
+static void
+add_feature_aead (PKT_signature *sig, int enabled)
+{
+  const byte *s;
+  size_t n;
+  int i;
+  char *buf;
+
+  s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+  if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02))))
+    return; /* Already set or cleared */
+
+  if (!s || !n)
+    { /* Create a new one */
+      n = 1;
+      buf = xmalloc_clear (n);
+    }
+  else
+    {
+      buf = xmalloc (n);
+      memcpy (buf, s, n);
+    }
+
+  if (enabled)
+    buf[0] |= 0x02; /* AEAD supported */
+  else
+    buf[0] &= ~0x02;
+
+  /* Are there any bits set? */
+  for (i=0; i < n; i++)
+    if (buf[i])
+      break;
+
+  if (i == n)
+    delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES);
+  else
+    build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
+
+  xfree (buf);
+}
+
+
 static void
 add_keyserver_modify (PKT_signature *sig,int enabled)
 {
@@ -726,6 +821,14 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
       delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
     }
 
+  if (naead_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_AEAD, aead_prefs, naead_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_AEAD);
+    }
+
   if (nhash_prefs)
     build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
   else
@@ -744,6 +847,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
 
   /* Make sure that the MDC feature flag is set if needed.  */
   add_feature_mdc (sig,mdc_available);
+  add_feature_aead (sig, aead_available);
   add_keyserver_modify (sig,ks_modify);
   keygen_add_keyserver_url(sig,NULL);
 
diff --git a/g10/main.h b/g10/main.h
index 4a8f8c3..6abc598 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -41,6 +41,8 @@
 # define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_3DES
 #endif
 
+#define DEFAULT_AEAD_ALGO  AEAD_ALGO_EAX
+
 #define DEFAULT_DIGEST_ALGO     ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1)
 #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1
 #ifdef HAVE_ZIP
@@ -123,6 +125,9 @@ int openpgp_cipher_blocklen (cipher_algo_t algo);
 int openpgp_cipher_test_algo(cipher_algo_t algo);
 const char *openpgp_cipher_algo_name (cipher_algo_t algo);
 
+gpg_error_t openpgp_aead_test_algo (aead_algo_t algo);
+const char *openpgp_aead_algo_name (aead_algo_t algo);
+
 pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo);
 int openpgp_pk_test_algo (pubkey_algo_t algo);
 int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use);
@@ -151,12 +156,14 @@ void obsolete_scdaemon_option (const char *configname,
                                unsigned int configlineno, const char *name);
 
 int string_to_cipher_algo (const char *string);
+aead_algo_t string_to_aead_algo (const char *string);
 int string_to_digest_algo (const char *string);
 
 const char *compress_algo_to_string(int algo);
 int string_to_compress_algo(const char *string);
 int check_compress_algo(int algo);
 int default_cipher_algo(void);
+aead_algo_t default_aead_algo(void);
 int default_compress_algo(void);
 void compliance_failure(void);
 
diff --git a/g10/misc.c b/g10/misc.c
index 9016d27..2da0d27 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -582,6 +582,41 @@ openpgp_cipher_algo_name (cipher_algo_t algo)
 }
 
 
+/* Return 0 if ALGO is supported.  Return an error if not. */
+gpg_error_t
+openpgp_aead_test_algo (aead_algo_t algo)
+{
+  switch (algo)
+    {
+    case AEAD_ALGO_NONE:
+      break;
+    case AEAD_ALGO_EAX:
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    case AEAD_ALGO_OCB:
+      return 0;
+    }
+
+  return gpg_error (GPG_ERR_INV_CIPHER_MODE);
+}
+
+
+/* Map the OpenPGP AEAD algorithm with ID ALGO to a string
+ * representation of the algorithm name.  For unknown algorithm IDs
+ * this function returns "?".  */
+const char *
+openpgp_aead_algo_name (aead_algo_t algo)
+{
+  switch (algo)
+    {
+    case AEAD_ALGO_NONE:  break;
+    case AEAD_ALGO_EAX:   return "EAX";
+    case AEAD_ALGO_OCB:   return "OCB";
+    }
+
+  return "?";
+}
+
+
 /* Return 0 if ALGO is a supported OpenPGP public key algorithm.  */
 int
 openpgp_pk_test_algo (pubkey_algo_t algo)
@@ -1112,6 +1147,39 @@ string_to_cipher_algo (const char *string)
   return val;
 }
 
+
+/*
+ * Map an AEAD mode string to a an AEAD algorithm number as defined by
+ * rrc4880bis.  Also support the "An" syntax as used by the preference
+ * strings.
+ */
+aead_algo_t
+string_to_aead_algo (const char *string)
+{
+  int result;
+
+  if (!string)
+    result = 0;
+  if (!ascii_strcasecmp (string, "EAX"))
+    result = 1;
+  else if (!ascii_strcasecmp (string, "OCB"))
+    result = 2;
+  else if ((string[0]=='A' || string[0]=='a'))
+    {
+      char *endptr;
+
+      string++;
+      result = strtol (string, &endptr, 10);
+      if (!*string || *endptr || result < 1 || result > 2)
+        result = 0;
+    }
+  else
+    result = 0;
+
+  return result;
+}
+
+
 /*
  * Wrapper around gcry_md_map_name to provide a fallback using the
  * "Hn" syntax as used by the preference strings.
@@ -1228,6 +1296,18 @@ default_cipher_algo(void)
     return opt.s2k_cipher_algo;
 }
 
+
+aead_algo_t
+default_aead_algo(void)
+{
+  if(opt.def_aead_algo)
+    return opt.def_aead_algo;
+  else if(opt.personal_aead_prefs)
+    return opt.personal_aead_prefs[0].value;
+  else
+    return DEFAULT_AEAD_ALGO;
+}
+
 /* There is no default_digest_algo function, but see
    sign.c:hash_for() */
 
diff --git a/g10/options.h b/g10/options.h
index 61f7403..6ad1037 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -92,6 +92,7 @@ struct
   int no_armor;
   int list_packets; /* Option --list-packets active.  */
   int def_cipher_algo;
+  int def_aead_algo;
   int force_mdc;
   int disable_mdc;
   int def_digest_algo;
@@ -177,6 +178,7 @@ struct
   const char *def_preference_list;
   const char *def_keyserver_url;
   prefitem_t *personal_cipher_prefs;
+  prefitem_t *personal_aead_prefs;
   prefitem_t *personal_digest_prefs;
   prefitem_t *personal_compress_prefs;
   struct weakhash *weak_digests;
diff --git a/g10/packet.h b/g10/packet.h
index 8dca88b..894b389 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -72,7 +72,8 @@ typedef enum {
     PREFTYPE_NONE = 0,
     PREFTYPE_SYM = 1,
     PREFTYPE_HASH = 2,
-    PREFTYPE_ZIP = 3
+    PREFTYPE_ZIP = 3,
+    PREFTYPE_AEAD = 4
 } preftype_t;
 
 typedef struct {
@@ -290,6 +291,7 @@ typedef struct
   struct
   {
     unsigned int mdc:1;
+    unsigned int aead:1;
     unsigned int ks_modify:1;
     unsigned int compacted:1;
     unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */
@@ -386,6 +388,7 @@ typedef struct
   struct
   {
     unsigned int mdc:1;           /* MDC feature set.  */
+    unsigned int aead:1;          /* AEAD feature set.  */
     unsigned int disabled_valid:1;/* The next flag is valid.  */
     unsigned int disabled:1;      /* The key has been disabled.  */
     unsigned int primary:1;       /* This is a primary key.  */
@@ -471,7 +474,7 @@ typedef struct {
      Note: this is ignored when encrypting.  */
   byte is_partial;
   /* If 0, MDC is disabled.  Otherwise, the MDC method that was used
-     (currently, only DIGEST_ALGO_SHA1 is supported).  */
+     (only DIGEST_ALGO_SHA1 has ever been defined).  */
   byte mdc_method;
   /* An iobuf holding the data to be decrypted.  (This is not used for
      encryption!)  */
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 581cae4..a759672 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1468,9 +1468,12 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
 	     support.  All this doesn't mean IDEA is actually
 	     available, of course. */
           implicit=CIPHER_ALGO_3DES;
-
 	  break;
 
+	case PREFTYPE_AEAD:
+          /* No implicit algo.  */
+          break;
+
 	case PREFTYPE_HASH:
 	  /* While I am including this code for completeness, note
 	     that currently --pgp2 mode locks the hash at MD5, so this
@@ -1553,6 +1556,8 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
       prefs=NULL;
       if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs)
 	prefs=opt.personal_cipher_prefs;
+      else if(preftype==PREFTYPE_AEAD && opt.personal_aead_prefs)
+	prefs=opt.personal_aead_prefs;
       else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs)
 	prefs=opt.personal_digest_prefs;
       else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs)

-----------------------------------------------------------------------

Summary of changes:
 common/openpgpdefs.h |  12 +++++-
 g10/Makefile.am      |   1 +
 g10/cipher-aead.c    |  67 ++++++++++++++++++++++++++++
 g10/cipher.c         |   7 +--
 g10/dek.h            |  25 ++++++++---
 g10/encrypt.c        |  90 ++++++++++++++++++++++++++++++++------
 g10/filter.h         |   8 +++-
 g10/getkey.c         |  11 ++++-
 g10/gpg.c            |  45 +++++++++++++++++++
 g10/gpgcompose.c     |   2 +-
 g10/kbnode.c         |   5 ++-
 g10/keydb.h          |   1 +
 g10/keyedit.c        |  12 +++++-
 g10/keygen.c         | 120 +++++++++++++++++++++++++++++++++++++++++++++++----
 g10/main.h           |   8 ++++
 g10/misc.c           |  80 ++++++++++++++++++++++++++++++++++
 g10/options.h        |   3 ++
 g10/packet.h         |   7 ++-
 g10/pkclist.c        |  32 +++++++++++++-
 g10/sign.c           |  12 ++++--
 20 files changed, 502 insertions(+), 46 deletions(-)
 create mode 100644 g10/cipher-aead.c


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list