gpg: New card function agent_scd_keypairinfo.
[gnupg.git] / g10 / encrypt.c
index c63ec88..972d13c 100644 (file)
@@ -47,12 +47,12 @@ static int write_pubkey_enc_from_list (ctrl_t ctrl,
 
 /****************
  * Encrypt FILENAME with only the symmetric cipher.  Take input from
- * stdin if FILENAME is NULL.
+ * stdin if FILENAME is NULL.  If --force-aead is used we use an SKESK.
  */
 int
 encrypt_symmetric (const char *filename)
 {
-  return encrypt_simple( filename, 1, );
+  return encrypt_simple( filename, 1, opt.force_aead);
 }
 
 
@@ -67,99 +67,190 @@ encrypt_store (const char *filename)
 }
 
 
-/* *SESKEY contains the unencrypted session key ((*SESKEY)->KEY) and
-   the algorithm that will be used to encrypt the contents of the SED
-   packet ((*SESKEY)->ALGO).  If *SESKEY is NULL, then a random
-   session key that is appropriate for DEK->ALGO is generated and
-   stored there.
-
-   Encrypt that session key using DEK and store the result in ENCKEY,
-   which must be large enough to hold (*SESKEY)->KEYLEN + 1 bytes.  */
-void
-encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
+/* Encrypt a session key using DEK and store a pointer to the result
+ * at R_ENCKEY and its length at R_ENCKEYLEN.
+ *
+ * R_SESKEY points to the unencrypted session key (.KEY, .KEYLEN) and
+ * the algorithm that will be used to encrypt the contents of the
+ * SKESK packet (.ALGO).  If R_SESKEY points to NULL, then a random
+ * session key that is appropriate for DEK->ALGO is generated and
+ * stored at R_SESKEY.  If AEAD_ALGO is not 0 the given AEAD algorithm
+ * is used for encryption.
+ */
+gpg_error_t
+encrypt_seskey (DEK *dek, aead_algo_t aead_algo,
+                DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
 {
-  gcry_cipher_hd_t hd;
-  byte buf[33];
+  gpg_error_t err;
+  gcry_cipher_hd_t hd = NULL;
+  byte *buf = NULL;
+  DEK *seskey;
+
+  *r_enckey = NULL;
+  *r_enckeylen = 0;
 
-  log_assert ( dek->keylen <= 32 );
-  if (!*seskey)
+  if (*r_seskey)
+    seskey = *r_seskey;
+  else
     {
-      *seskey=xmalloc_clear(sizeof(DEK));
-      (*seskey)->algo=dek->algo;
-      make_session_key(*seskey);
+      seskey = xtrycalloc (1, sizeof(DEK));
+      if (!seskey)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      seskey->algo = dek->algo;
+      make_session_key (seskey);
       /*log_hexdump( "thekey", c->key, c->keylen );*/
     }
 
-  /* The encrypted session key is prefixed with a one-octet algorithm id.  */
-  buf[0] = (*seskey)->algo;
-  memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
-
-  /* We only pass already checked values to the following function,
-     thus we consider any failure as fatal.  */
-  if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
-    BUG ();
-  if (gcry_cipher_setkey (hd, dek->key, dek->keylen))
-    BUG ();
-  gcry_cipher_setiv (hd, NULL, 0);
-  gcry_cipher_encrypt (hd, buf, (*seskey)->keylen + 1, NULL, 0);
-  gcry_cipher_close (hd);
 
-  memcpy( enckey, buf, (*seskey)->keylen + 1 );
-  wipememory( buf, sizeof buf ); /* burn key */
-}
+  if (aead_algo)
+    {
+      unsigned int noncelen;
+      enum gcry_cipher_modes ciphermode;
+      byte ad[4];
+
+      err = openpgp_aead_algo_info (aead_algo, &ciphermode, &noncelen);
+      if (err)
+        goto leave;
+
+      /* Allocate space for the nonce, the key, and the authentication
+       * tag (16).  */
+      buf = xtrymalloc_secure (noncelen + seskey->keylen + 16);
+      if (!buf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
 
+      gcry_randomize (buf, noncelen, GCRY_STRONG_RANDOM);
+
+      err = openpgp_cipher_open (&hd, dek->algo,
+                                 ciphermode, GCRY_CIPHER_SECURE);
+      if (!err)
+        err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+      if (!err)
+        err = gcry_cipher_setiv (hd, buf, noncelen);
+      if (err)
+        goto leave;
+
+      ad[0] = (0xc0 | PKT_SYMKEY_ENC);
+      ad[1] = 5;
+      ad[2] = dek->algo;
+      ad[3] = aead_algo;
+      err = gcry_cipher_authenticate (hd, ad, 4);
+      if (err)
+        goto leave;
+
+      memcpy (buf + noncelen, seskey->key, seskey->keylen);
+      gcry_cipher_final (hd);
+      err = gcry_cipher_encrypt (hd, buf + noncelen, seskey->keylen, NULL,0);
+      if (err)
+        goto leave;
+      err = gcry_cipher_gettag (hd, buf + noncelen + seskey->keylen, 16);
+      if (err)
+        goto leave;
+      *r_enckeylen = noncelen + seskey->keylen + 16;
+      *r_enckey = buf;
+      buf = NULL;
+    }
+  else
+    {
+      /* In the old version 4 SKESK the encrypted session key is
+       * prefixed with a one-octet algorithm id.  */
+      buf = xtrymalloc_secure (1 + seskey->keylen);
+      if (!buf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      buf[0] = seskey->algo;
+      memcpy (buf + 1, seskey->key, seskey->keylen);
+
+      err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1);
+      if (!err)
+        err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
+      if (!err)
+        err = gcry_cipher_setiv (hd, NULL, 0);
+      if (!err)
+        err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0);
+      if (err)
+        goto leave;
+      *r_enckeylen = seskey->keylen + 1;
+      *r_enckey = buf;
+      buf = NULL;
+    }
 
-/* We try very hard to use a MDC */
-int
-use_mdc (pk_list_t pk_list,int algo)
-{
-  /* RFC-2440 don't has MDC */
-  if (RFC2440)
-    return 0;
+  /* Return the session key in case we allocated it.  */
+  *r_seskey = seskey;
+  seskey = NULL;
 
-  /* --force-mdc overrides --disable-mdc */
-  if(opt.force_mdc)
-    return 1;
+ leave:
+  gcry_cipher_close (hd);
+  if (seskey != *r_seskey)
+    xfree (seskey);
+  xfree (buf);
+  return err;
+}
 
-  if(opt.disable_mdc)
-    return 0;
 
-  /* Do the keys really support MDC? */
+/* Return the AEAD algo if we shall use AEAD mode.  Returns 0 if AEAD
+ * shall not be used.  */
+aead_algo_t
+use_aead (pk_list_t pk_list, int algo)
+{
+  int can_use;
 
-  if(select_mdc_from_pklist(pk_list))
-    return 1;
+  if (!opt.flags.rfc4880bis)
+    {
+      if (opt.force_aead)
+        log_info ("Warning: Option %s currently requires option '%s'\n",
+                  "--force-aead", "--rfc4880bis");
+      return 0;
+    }
 
-  /* The keys don't support MDC, so now we do a bit of a hack - if any
-     of the AESes or TWOFISH are in the prefs, we assume that the user
-     can handle a MDC.  This is valid for PGP 7, which can handle MDCs
-     though it will not generate them.  2440bis allows this, by the
-     way. */
+  can_use = openpgp_cipher_get_algo_blklen (algo) == 16;
 
-  if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
-                           CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES)
-    return 1;
+  /* 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 0;
+        }
+      return default_aead_algo ();
+    }
 
-  if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
-                           CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192)
-    return 1;
+  /* AEAD does only work with 128 bit cipher blocklength.  */
+  if (!can_use)
+    return 0;
 
-  if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
-                           CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256)
-    return 1;
+  /* Note the user which keys have no AEAD feature flag set.  */
+  if (opt.verbose)
+    warn_missing_aead_from_pklist (pk_list);
 
-  if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
-                           CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH)
-    return 1;
+  /* If all keys support AEAD we can use it.  */
+  return select_aead_from_pklist (pk_list);
+}
 
-  /* Last try.  Use MDC for the modern ciphers. */
 
-  if (openpgp_cipher_get_algo_blklen (algo) != 8)
-    return 1;
+/* Shall we use the MDC?  Yes - unless rfc-2440 compatibility is
+ * requested. */
+int
+use_mdc (pk_list_t pk_list,int algo)
+{
+  (void)pk_list;
+  (void)algo;
 
-  if (opt.verbose)
-    warn_missing_mdc_from_pklist (pk_list);
+  /* RFC-2440 don't has MDC - this is the only way to create a legacy
+   * non-MDC encryption packet.  */
+  if (RFC2440)
+    return 0;
 
-  return 0; /* No MDC */
+  return 1; /* In all other cases we use the MDC */
 }
 
 
@@ -174,9 +265,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   PACKET pkt;
   PKT_plaintext *pt = NULL;
   STRING2KEY *s2k = NULL;
-  byte enckey[33];
+  void *enckey = NULL;
+  size_t enckeylen = 0;
   int rc = 0;
-  int seskeylen = 0;
   u32 filesize;
   cipher_filter_context_t cfx;
   armor_filter_context_t  *afx = NULL;
@@ -229,6 +320,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   if ( mode )
     {
       int canceled;
+      aead_algo_t aead_algo;
 
       s2k = xmalloc_clear( sizeof *s2k );
       s2k->mode = opt.s2k_mode;
@@ -252,23 +344,42 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
                       "due to the S2K mode\n"));
         }
 
+      /* See whether we want to use AEAD.  */
+      aead_algo = use_aead (NULL, cfx.dek->algo);
+
       if ( use_seskey )
         {
           DEK *dek = NULL;
 
-          seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ());
-          encrypt_seskey( cfx.dek, &dek, enckey );
-          xfree( cfx.dek ); cfx.dek = dek;
+          rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen);
+          if (rc)
+            {
+              xfree (cfx.dek);
+              xfree (s2k);
+              iobuf_close (inp);
+              release_progress_context (pfx);
+              return rc;
+            }
+          /* Replace key in DEK.  */
+          xfree (cfx.dek);
+          cfx.dek = dek;
         }
 
-      if (opt.verbose)
-        log_info(_("using cipher %s\n"),
-                 openpgp_cipher_algo_name (cfx.dek->algo));
+      if (aead_algo)
+        cfx.dek->use_aead = aead_algo;
+      else
+        cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
 
-      cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
+      if (opt.verbose)
+        log_info(_("using cipher %s.%s\n"),
+                 openpgp_cipher_algo_name (cfx.dek->algo),
+                 cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
+                 /**/             : "CFB");
     }
 
-  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)
@@ -293,20 +404,24 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
 
   if ( s2k )
     {
-      PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 );
-      enc->version = 4;
+      /* Fixme: This is quite similar to write_symkey_enc.  */
+      PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
+      enc->version = cfx.dek->use_aead ? 5 : 4;
       enc->cipher_algo = cfx.dek->algo;
+      enc->aead_algo = cfx.dek->use_aead;
       enc->s2k = *s2k;
-      if ( use_seskey && seskeylen )
+      if (enckeylen)
         {
-          enc->seskeylen = seskeylen + 1; /* algo id */
-          memcpy (enc->seskey, enckey, seskeylen + 1 );
+          enc->seskeylen = enckeylen;
+          memcpy (enc->seskey, enckey, enckeylen);
         }
       pkt.pkttype = PKT_SYMKEY_ENC;
       pkt.pkt.symkey_enc = enc;
       if ((rc = build_packet( out, &pkt )))
         log_error("build symkey packet failed: %s\n", gpg_strerror (rc) );
       xfree (enc);
+      xfree (enckey);
+      enckey = NULL;
     }
 
   if (!opt.no_literal)
@@ -363,12 +478,15 @@ 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 )
     {
-      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());
     }
@@ -407,6 +525,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   if (pt)
     pt->buf = NULL;
   free_packet (&pkt, NULL);
+  xfree (enckey);
   xfree (cfx.dek);
   xfree (s2k);
   release_armor_context (afx);
@@ -438,23 +557,33 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
 
 
 static int
-write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
-                  iobuf_t out)
+write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
+                  DEK *symkey_dek, DEK *dek, iobuf_t out)
 {
-  int rc, seskeylen = openpgp_cipher_get_algo_keylen (dek->algo);
-
+  int rc;
+  void *enckey;
+  size_t enckeylen;
   PKT_symkey_enc *enc;
-  byte enckey[33];
   PACKET pkt;
 
-  enc=xmalloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1);
-  encrypt_seskey(symkey_dek,&dek,enckey);
+  rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen);
+  if (rc)
+    return rc;
+  enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
+  if (!enc)
+    {
+      rc = gpg_error_from_syserror ();
+      xfree (enckey);
+      return rc;
+    }
 
-  enc->version = 4;
+  enc->version = aead_algo? 5 : 4;
   enc->cipher_algo = opt.s2k_cipher_algo;
+  enc->aead_algo = aead_algo;
   enc->s2k = *symkey_s2k;
-  enc->seskeylen = seskeylen + 1; /* algo id */
-  memcpy( enc->seskey, enckey, seskeylen + 1 );
+  enc->seskeylen = enckeylen;
+  memcpy (enc->seskey, enckey, enckeylen);
+  xfree (enckey);
 
   pkt.pkttype = PKT_SYMKEY_ENC;
   pkt.pkt.symkey_enc = enc;
@@ -462,7 +591,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
   if ((rc=build_packet(out,&pkt)))
     log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc));
 
-  xfree(enc);
+  xfree (enc);
   return rc;
 }
 
@@ -603,7 +732,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
 
       /* In case 3DES has been selected, print a warning if any key
          does not have a preference for AES.  This should help to
-         indentify why encrypting to several recipients falls back to
+         identify why encrypting to several recipients falls back to
          3DES. */
       if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES)
         warn_missing_aes_from_pklist (pk_list);
@@ -628,8 +757,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   if (! gnupg_cipher_is_allowed (opt.compliance, 1, cfx.dek->algo,
                                  GCRY_CIPHER_MODE_CFB))
     {
-      log_error (_("you may not use cipher algorithm '%s'"
-                  " while in %s mode\n"),
+      log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
                 openpgp_cipher_algo_name (cfx.dek->algo),
                 gnupg_compliance_option_string (opt.compliance));
       rc = gpg_error (GPG_ERR_CIPHER_ALGO);
@@ -657,16 +785,12 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
         PKT_public_key *pk = pkr->pk;
         unsigned int nbits = nbits_from_pk (pk);
 
-        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_ENCRYPTION,
-                                   pk->pubkey_algo, pk->pkey, nbits, NULL))
-          {
-            log_error (_("key %s not suitable for encryption"
-                         " while in %s mode\n"),
-                       keystr_from_pk (pk),
-                       gnupg_compliance_option_string (opt.compliance));
-            rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
-            goto leave;
-          }
+        if (!gnupg_pk_is_compliant (opt.compliance,
+                                    pk->pubkey_algo, pk->pkey, nbits, NULL))
+          log_info (_("WARNING: key %s is not suitable for encryption"
+                      " in %s mode\n"),
+                    keystr_from_pk (pk),
+                    gnupg_compliance_option_string (opt.compliance));
 
         if (compliant
             && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
@@ -681,14 +805,17 @@ 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);
+  cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo);
+  if (!cfx.dek->use_aead)
+    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);
@@ -702,17 +829,18 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
 
   make_session_key (cfx.dek);
   if (DBG_CRYPTO)
-    log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen );
+    log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: ");
 
   rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out);
   if (rc)
     goto leave;
 
   /* We put the passphrase (if any) after any public keys as this
-     seems to be the most useful on the recipient side - there is no
-     point in prompting a user for a passphrase if they have the
-     secret key needed to decrypt.  */
-  if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
+   * seems to be the most useful on the recipient side - there is no
+   * point in prompting a user for a passphrase if they have the
+   * secret key needed to decrypt.  */
+  if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead,
+                                            symkey_dek, cfx.dek, out)))
     goto leave;
 
   if (!opt.no_literal)
@@ -755,7 +883,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)
@@ -782,7 +913,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);
         }
@@ -872,7 +1003,7 @@ encrypt_filter (void *opaque, int control,
 
               /* In case 3DES has been selected, print a warning if
                  any key does not have a preference for AES.  This
-                 should help to indentify why encrypting to several
+                 should help to identify why encrypting to several
                  recipients falls back to 3DES. */
               if (opt.verbose
                   && efx->cfx.dek->algo == CIPHER_ALGO_3DES)
@@ -892,11 +1023,13 @@ 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);
+          efx->cfx.dek->use_aead = use_aead (efx->pk_list, efx->cfx.dek->algo);
+          if (!efx->cfx.dek->use_aead)
+            efx->cfx.dek->use_mdc = !!use_mdc (efx->pk_list,efx->cfx.dek->algo);
 
           make_session_key ( efx->cfx.dek );
           if (DBG_CRYPTO)
-            log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen);
+            log_printhex (efx->cfx.dek->key, efx->cfx.dek->keylen, "DEK is: ");
 
           rc = write_pubkey_enc_from_list (efx->ctrl,
                                            efx->pk_list, efx->cfx.dek, a);
@@ -905,13 +1038,16 @@ encrypt_filter (void *opaque, int control,
 
           if(efx->symkey_s2k && efx->symkey_dek)
             {
-              rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
-                                  efx->cfx.dek,a);
-              if(rc)
+              rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead,
+                                     efx->symkey_dek, efx->cfx.dek, a);
+              if (rc)
                 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;
         }
@@ -972,9 +1108,11 @@ write_pubkey_enc (ctrl_t ctrl,
       if ( opt.verbose )
         {
           char *ustr = get_user_id_string_native (ctrl, enc->keyid);
-          log_info (_("%s/%s encrypted for: \"%s\"\n"),
+          log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
                     openpgp_pk_algo_name (enc->pubkey_algo),
                     openpgp_cipher_algo_name (dek->algo),
+                    dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
+                    /**/         : "CFB",
                     ustr );
           xfree (ustr);
         }
@@ -998,9 +1136,9 @@ write_pubkey_enc (ctrl_t ctrl,
 static int
 write_pubkey_enc_from_list (ctrl_t ctrl, PK_LIST pk_list, DEK *dek, iobuf_t out)
 {
-  if (opt.throw_keyids && (PGP6 || PGP7 || PGP8))
+  if (opt.throw_keyids && (PGP7 || PGP8))
     {
-      log_info(_("you may not use %s while in %s mode\n"),
+      log_info(_("option '%s' may not be used in %s mode\n"),
                "--throw-keyids",
                gnupg_compliance_option_string (opt.compliance));
       compliance_failure();