gpg: Implement AEAD for SKESK packets.
authorWerner Koch <wk@gnupg.org>
Tue, 23 Jan 2018 11:07:25 +0000 (12:07 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 23 Jan 2018 11:07:57 +0000 (12:07 +0100)
* g10/packet.h (PKT_symkey_enc): Add field aead_algo.
* g10/build-packet.c (do_symkey_enc): Support version 5 packets.
* g10/parse-packet.c (parse_symkeyenc): Ditto.
* g10/encrypt.c (encrypt_symmetric): Force using a random session
key in AEAD mode.
(encrypt_seskey): Add and support arg aead_algo.
(write_symkey_enc): Ditto.
(encrypt_simple): Adjust accordingly.
(encrypt_filter): Ditto.
* g10/gpgcompose.c (sk_esk): For now call encrypt_seskey without AEAD
support.
* g10/mainproc.c (symkey_decrypt_seskey): Support AEAD.  Nver call BUG
but return an error.
(proc_symkey_enc): Call symkey_decrypt_seskey in a bug compatible way.

* g10/import.c (check_prefs): Check AEAD preferences.
* g10/keyedit.c (show_prefs): Print AEAD preferences.
--

For easier debugging this patch also changes some diagnostics to also
print the encryption mode with the cipher algorithm.

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/build-packet.c
g10/decrypt-data.c
g10/encrypt.c
g10/gpgcompose.c
g10/import.c
g10/keyedit.c
g10/main.h
g10/mainproc.c
g10/packet.h
g10/parse-packet.c
g10/sign.c

index fc64c9c..b4e03d0 100644 (file)
@@ -617,11 +617,8 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
   IOBUF a = iobuf_temp();
 
   log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC);
   IOBUF a = iobuf_temp();
 
   log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC);
+  log_assert (enc->version == 4 || enc->version == 5);
 
 
-  /* The only acceptable version.  */
-  log_assert( enc->version == 4 );
-
-  /* RFC 4880, Section 3.7.  */
   switch (enc->s2k.mode)
     {
     case 0: /* Simple S2K.  */
   switch (enc->s2k.mode)
     {
     case 0: /* Simple S2K.  */
@@ -632,23 +629,26 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
     default:
       log_bug ("do_symkey_enc: s2k=%d\n", enc->s2k.mode);
     }
     default:
       log_bug ("do_symkey_enc: s2k=%d\n", enc->s2k.mode);
     }
-    iobuf_put( a, enc->version );
-    iobuf_put( a, enc->cipher_algo );
-    iobuf_put( a, enc->s2k.mode );
-    iobuf_put( a, enc->s2k.hash_algo );
-    if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) {
-       iobuf_write(a, enc->s2k.salt, 8 );
-       if( enc->s2k.mode == 3 )
-           iobuf_put(a, enc->s2k.count);
+  iobuf_put (a, enc->version);
+  iobuf_put (a, enc->cipher_algo);
+  if (enc->version == 5)
+    iobuf_put (a, enc->aead_algo);
+  iobuf_put (a, enc->s2k.mode);
+  iobuf_put (a, enc->s2k.hash_algo);
+  if (enc->s2k.mode == 1 || enc->s2k.mode == 3)
+    {
+      iobuf_write (a, enc->s2k.salt, 8);
+      if (enc->s2k.mode == 3)
+        iobuf_put (a, enc->s2k.count);
     }
     }
-    if( enc->seskeylen )
-       iobuf_write(a, enc->seskey, enc->seskeylen );
+  if (enc->seskeylen)
+    iobuf_write (a, enc->seskey, enc->seskeylen);
 
 
-    write_header(out, ctb, iobuf_get_temp_length(a) );
-    rc = iobuf_write_temp( out, a );
+  write_header (out, ctb, iobuf_get_temp_length(a));
+  rc = iobuf_write_temp (out, a);
 
 
-    iobuf_close(a);
-    return rc;
+  iobuf_close (a);
+  return rc;
 }
 
 
 }
 
 
index 7ed0bf0..46650f2 100644 (file)
@@ -212,8 +212,10 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
   if ( opt.verbose && !dek->algo_info_printed )
     {
       if (!openpgp_cipher_test_algo (dek->algo))
   if ( opt.verbose && !dek->algo_info_printed )
     {
       if (!openpgp_cipher_test_algo (dek->algo))
-        log_info (_("%s encrypted data\n"),
-                  openpgp_cipher_algo_name (dek->algo));
+        log_info (_("%s.%s encrypted data\n"),
+                  openpgp_cipher_algo_name (dek->algo),
+                  ed->aead_algo? openpgp_aead_algo_name (ed->aead_algo)
+                  /**/         : "CFB");
       else
         log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
       dek->algo_info_printed = 1;
       else
         log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
       dek->algo_info_printed = 1;
index 4cc4b1a..c6c9e3a 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
 
 /****************
  * 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)
 {
  */
 int
 encrypt_symmetric (const char *filename)
 {
-  return encrypt_simple( filename, 1, );
+  return encrypt_simple( filename, 1, opt.force_aead);
 }
 
 
 }
 
 
@@ -70,14 +70,16 @@ encrypt_store (const char *filename)
 /* Encrypt a session key using DEK and store a pointer to the result
  * at R_ENCKEY and its length at R_ENCKEYLEN.
  *
 /* 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
+ * 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
  * 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.
+ * stored at R_SESKEY.  If AEAD_ALGO is not 0 the given AEAD algorithm
+ * is used for encryption.
  */
 gpg_error_t
  */
 gpg_error_t
-encrypt_seskey (DEK *dek, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
+encrypt_seskey (DEK *dek, aead_algo_t aead_algo,
+                DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
 {
   gpg_error_t err;
   gcry_cipher_hd_t hd = NULL;
 {
   gpg_error_t err;
   gcry_cipher_hd_t hd = NULL;
@@ -102,30 +104,84 @@ encrypt_seskey (DEK *dek, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
       /*log_hexdump( "thekey", c->key, c->keylen );*/
     }
 
       /*log_hexdump( "thekey", c->key, c->keylen );*/
     }
 
-  buf = xtrymalloc_secure (1 + seskey->keylen);
-  if (!buf)
+
+  if (aead_algo)
     {
     {
-      err = gpg_error_from_syserror ();
-      goto leave;
-    }
+      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;
+        }
 
 
-  /* The encrypted session key is prefixed with a one-octet algorithm id.  */
-  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;
+      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;
+    }
 
 
-  *r_enckey = buf;
-  buf = NULL;
-  *r_enckeylen = seskey->keylen + 1;
   /* Return the session key in case we allocated it.  */
   *r_seskey = seskey;
   seskey = NULL;
   /* Return the session key in case we allocated it.  */
   *r_seskey = seskey;
   seskey = NULL;
@@ -332,7 +388,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
         {
           DEK *dek = NULL;
 
         {
           DEK *dek = NULL;
 
-          rc = encrypt_seskey (cfx.dek, &dek, &enckey, &enckeylen);
+          rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen);
           if (rc)
             {
               xfree (cfx.dek);
           if (rc)
             {
               xfree (cfx.dek);
@@ -346,14 +402,16 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
           cfx.dek = 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);
       if (aead_algo)
         cfx.dek->use_aead = aead_algo;
       else
         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
     }
 
   if (do_compress
@@ -385,8 +443,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
     {
       /* Fixme: This is quite similar to write_symkey_enc.  */
       PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
     {
       /* Fixme: This is quite similar to write_symkey_enc.  */
       PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
-      enc->version = 4;
+      enc->version = cfx.dek->use_aead ? 5 : 4;
       enc->cipher_algo = cfx.dek->algo;
       enc->cipher_algo = cfx.dek->algo;
+      enc->aead_algo = cfx.dek->use_aead;
       enc->s2k = *s2k;
       if (enckeylen)
         {
       enc->s2k = *s2k;
       if (enckeylen)
         {
@@ -535,8 +594,8 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
 
 
 static int
 
 
 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;
   void *enckey;
 {
   int rc;
   void *enckey;
@@ -544,7 +603,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
   PKT_symkey_enc *enc;
   PACKET pkt;
 
   PKT_symkey_enc *enc;
   PACKET pkt;
 
-  rc = encrypt_seskey (symkey_dek, &dek, &enckey, &enckeylen);
+  rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen);
   if (rc)
     return rc;
   enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
   if (rc)
     return rc;
   enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
@@ -555,8 +614,9 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
       return rc;
     }
 
       return rc;
     }
 
-  enc->version = 4;
+  enc->version = aead_algo? 5 : 4;
   enc->cipher_algo = opt.s2k_cipher_algo;
   enc->cipher_algo = opt.s2k_cipher_algo;
+  enc->aead_algo = aead_algo;
   enc->s2k = *symkey_s2k;
   enc->seskeylen = enckeylen;
   memcpy (enc->seskey, enckey, enckeylen);
   enc->s2k = *symkey_s2k;
   enc->seskeylen = enckeylen;
   memcpy (enc->seskey, enckey, enckeylen);
@@ -813,10 +873,11 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
     goto leave;
 
   /* We put the passphrase (if any) after any public keys as this
     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)
     goto leave;
 
   if (!opt.no_literal)
@@ -1014,9 +1075,9 @@ encrypt_filter (void *opaque, int control,
 
           if(efx->symkey_s2k && efx->symkey_dek)
             {
 
           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;
             }
 
                 return rc;
             }
 
@@ -1084,9 +1145,11 @@ write_pubkey_enc (ctrl_t ctrl,
       if ( opt.verbose )
         {
           char *ustr = get_user_id_string_native (ctrl, enc->keyid);
       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),
                     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);
         }
                     ustr );
           xfree (ustr);
         }
index f22c7c2..094bc76 100644 (file)
@@ -2284,7 +2284,7 @@ sk_esk (const char *option, int argc, char *argv[], void *cookie)
 
       /* Now encrypt the session key (or rather, the algorithm used to
          encrypt the SKESK plus the session key) using ENCKEY.  */
 
       /* Now encrypt the session key (or rather, the algorithm used to
          encrypt the SKESK plus the session key) using ENCKEY.  */
-      err = encrypt_seskey (&s2kdek, &sesdekp,
+      err = encrypt_seskey (&s2kdek, 0, &sesdekp,
                             (void**)&ske->seskey, (size_t *)&ske->seskeylen);
       if (err)
         log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err));
                             (void**)&ske->seskey, (size_t *)&ske->seskeylen);
       if (err)
         log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err));
index 71e3955..ed679d5 100644 (file)
@@ -1113,6 +1113,24 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
                      problem=1;
                    }
                }
                      problem=1;
                    }
                }
+             else if(prefs->type==PREFTYPE_AEAD)
+               {
+                 if (openpgp_aead_test_algo (prefs->value))
+                   {
+                      /* FIXME: The test below is wrong.  We should
+                       * check if ...algo_name yields a "?" and
+                       * only in that case use NUM.  */
+                     const char *algo =
+                        (openpgp_aead_test_algo (prefs->value)
+                         ? num
+                         : openpgp_aead_algo_name (prefs->value));
+                     if(!problem)
+                       check_prefs_warning(pk);
+                     log_info(_("         \"%s\": preference for AEAD"
+                                " algorithm %s\n"), user, algo);
+                     problem=1;
+                   }
+               }
              else if(prefs->type==PREFTYPE_HASH)
                {
                  if(openpgp_md_test_algo(prefs->value))
              else if(prefs->type==PREFTYPE_HASH)
                {
                  if(openpgp_md_test_algo(prefs->value))
@@ -2255,6 +2273,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
         {
           char countbuf[35];
 
         {
           char countbuf[35];
 
+          /* FIXME: Support AEAD */
           /* Note that the IVLEN may be zero if we are working on a
              dummy key.  We can't express that in an S-expression and
              thus we send dummy data for the IV.  */
           /* Note that the IVLEN may be zero if we are working on a
              dummy key.  We can't express that in an S-expression and
              thus we send dummy data for the IV.  */
index 81344eb..3ae96a3 100644 (file)
@@ -3064,6 +3064,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
          tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
        }
       tty_printf ("\n     ");
          tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
        }
       tty_printf ("\n     ");
+      tty_printf (_("AEAD: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_AEAD)
+           {
+             if (any)
+               tty_printf (", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!openpgp_aead_test_algo (prefs[i].value)
+                 && prefs[i].value < 100)
+               tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value));
+             else
+               tty_printf ("[%d]", prefs[i].value);
+           }
+       }
+      tty_printf ("\n     ");
       tty_printf (_("Digest: "));
       for (i = any = 0; prefs[i].type; i++)
        {
       tty_printf (_("Digest: "));
       for (i = any = 0; prefs[i].type; i++)
        {
@@ -3172,6 +3189,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
       for (i = 0; prefs[i].type; i++)
        {
          tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
       for (i = 0; prefs[i].type; i++)
        {
          tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
+                     prefs[i].type == PREFTYPE_AEAD ? 'A' :
                      prefs[i].type == PREFTYPE_HASH ? 'H' :
                      prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
                      prefs[i].value);
                      prefs[i].type == PREFTYPE_HASH ? 'H' :
                      prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
                      prefs[i].value);
index 96899ac..a02c574 100644 (file)
@@ -235,7 +235,7 @@ void display_online_help( const char *keyword );
 
 /*-- encode.c --*/
 int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
 
 /*-- encode.c --*/
 int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
-gpg_error_t encrypt_seskey (DEK *dek, DEK **r_seskey,
+gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey,
                             void **r_enckey, size_t *r_enckeylen);
 aead_algo_t use_aead (pk_list_t pk_list, int algo);
 int use_mdc (pk_list_t pk_list,int algo);
                             void **r_enckey, size_t *r_enckeylen);
 aead_algo_t use_aead (pk_list_t pk_list, int algo);
 int use_mdc (pk_list_t pk_list,int algo);
index 92da982..d1d44d7 100644 (file)
@@ -245,46 +245,102 @@ add_signature (CTX c, PACKET *pkt)
   return 1;
 }
 
   return 1;
 }
 
-static int
+static gpg_error_t
 symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
 {
 symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
 {
+  gpg_error_t err;
   gcry_cipher_hd_t hd;
   gcry_cipher_hd_t hd;
+  unsigned int noncelen, keylen;
+  enum gcry_cipher_modes ciphermode;
+  byte ad[4];
+
+  if (dek->use_aead)
+    {
+      err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen);
+      if (err)
+        return err;
+    }
+  else
+    {
+      ciphermode = GCRY_CIPHER_MODE_CFB;
+      noncelen = 0;
+    }
 
 
-  if(slen < 17 || slen > 33)
+  /* Check that the session key has a size of 16 to 32 bytes.  */
+  if ((dek->use_aead && (slen < (noncelen + 16 + 16)
+                         || slen > (noncelen + 32 + 16)))
+      || (!dek->use_aead && (slen < 17 || slen > 33)))
     {
       log_error ( _("weird size for an encrypted session key (%d)\n"),
                  (int)slen);
     {
       log_error ( _("weird size for an encrypted session key (%d)\n"),
                  (int)slen);
-      return GPG_ERR_BAD_KEY;
+      return gpg_error (GPG_ERR_BAD_KEY);
     }
 
     }
 
-  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_decrypt ( hd, seskey, slen, NULL, 0 );
-  gcry_cipher_close ( hd );
-
-  /* Now we replace the dek components with the real session key to
-     decrypt the contents of the sequencing packet. */
-
-  dek->keylen=slen-1;
-  dek->algo=seskey[0];
+  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, noncelen? seskey : NULL, noncelen);
+  if (err)
+    goto leave;
 
 
-  if(dek->keylen > DIM(dek->key))
-    BUG ();
-
-  memcpy(dek->key, seskey + 1, dek->keylen);
+  if (dek->use_aead)
+    {
+      byte ad[4];
+
+      ad[0] = (0xc0 | PKT_SYMKEY_ENC);
+      ad[1] = 5;
+      ad[2] = dek->algo;
+      ad[3] = dek->use_aead;
+      err = gcry_cipher_authenticate (hd, ad, 4);
+      if (err)
+        goto leave;
+      gcry_cipher_final (hd);
+      keylen = slen - noncelen - 16;
+      err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0);
+      if (err)
+        goto leave;
+      err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16);
+      if (err)
+        goto leave;
+      /* Now we replace the dek components with the real session key to
+       * decrypt the contents of the sequencing packet. */
+      if (keylen > DIM(dek->key))
+        {
+          err = gpg_error (GPG_ERR_TOO_LARGE);
+          goto leave;
+        }
+      dek->keylen = keylen;
+      memcpy (dek->key, seskey + noncelen, dek->keylen);
+    }
+  else
+    {
+      gcry_cipher_decrypt (hd, seskey, slen, NULL, 0 );
+      /* Now we replace the dek components with the real session key to
+       * decrypt the contents of the sequencing packet. */
+      keylen = slen-1;
+      if (keylen > DIM(dek->key))
+        {
+          err = gpg_error (GPG_ERR_TOO_LARGE);
+          goto leave;
+        }
+      dek->algo = seskey[0];
+      dek->keylen = keylen;
+      memcpy (dek->key, seskey + 1, dek->keylen);
+    }
 
   /*log_hexdump( "thekey", dek->key, dek->keylen );*/
 
 
   /*log_hexdump( "thekey", dek->key, dek->keylen );*/
 
-  return 0;
+ leave:
+  gcry_cipher_close (hd);
+  return err;
 }
 
 
 static void
 proc_symkey_enc (CTX c, PACKET *pkt)
 {
 }
 
 
 static void
 proc_symkey_enc (CTX c, PACKET *pkt)
 {
+  gpg_error_t err;
   PKT_symkey_enc *enc;
 
   enc = pkt->pkt.symkey_enc;
   PKT_symkey_enc *enc;
 
   enc = pkt->pkt.symkey_enc;
@@ -294,19 +350,21 @@ proc_symkey_enc (CTX c, PACKET *pkt)
     {
       int algo = enc->cipher_algo;
       const char *s = openpgp_cipher_algo_name (algo);
     {
       int algo = enc->cipher_algo;
       const char *s = openpgp_cipher_algo_name (algo);
+      const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo)
+                       /**/           : "CFB");
 
       if (!openpgp_cipher_test_algo (algo))
         {
           if (!opt.quiet)
             {
               if (enc->seskeylen)
 
       if (!openpgp_cipher_test_algo (algo))
         {
           if (!opt.quiet)
             {
               if (enc->seskeylen)
-                log_info (_("%s encrypted session key\n"), s );
+                log_info (_("%s.%s encrypted session key\n"), s, a );
               else
               else
-                log_info (_("%s encrypted data\n"), s );
+                log_info (_("%s.%s encrypted data\n"), s, a );
             }
         }
       else
             }
         }
       else
-        log_error (_("encrypted with unknown algorithm %d\n"), algo);
+        log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a);
 
       if (openpgp_md_test_algo (enc->s2k.hash_algo))
         {
 
       if (openpgp_md_test_algo (enc->s2k.hash_algo))
         {
@@ -334,6 +392,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
           if (c->dek)
             {
               c->dek->symmetric = 1;
           if (c->dek)
             {
               c->dek->symmetric = 1;
+              c->dek->use_aead = enc->aead_algo;
 
               /* FIXME: This doesn't work perfectly if a symmetric key
                  comes before a public key in the message - if the
 
               /* FIXME: This doesn't work perfectly if a symmetric key
                  comes before a public key in the message - if the
@@ -344,9 +403,16 @@ proc_symkey_enc (CTX c, PACKET *pkt)
                  come later. */
               if (enc->seskeylen)
                 {
                  come later. */
               if (enc->seskeylen)
                 {
-                  if (symkey_decrypt_seskey (c->dek,
-                                             enc->seskey, enc->seskeylen))
+                  err = symkey_decrypt_seskey (c->dek,
+                                               enc->seskey, enc->seskeylen);
+                  if (err)
                     {
                     {
+                      log_info ("decryption of the symmetrically encrypted"
+                                 " session key failed: %s\n",
+                                 gpg_strerror (err));
+                      if (gpg_err_code (err) != GPG_ERR_BAD_KEY)
+                        log_fatal ("process terminated to be bug compatible"
+                                   " with GnuPG <= 2.2\n");
                       xfree (c->dek);
                       c->dek = NULL;
                     }
                       xfree (c->dek);
                       c->dek = NULL;
                     }
index 4d15574..4f4569f 100644 (file)
@@ -94,12 +94,14 @@ typedef struct
 /* A symmetric-key encrypted session key packet as defined in RFC
    4880, Section 5.3.  All fields are serialized.  */
 typedef struct {
 /* A symmetric-key encrypted session key packet as defined in RFC
    4880, Section 5.3.  All fields are serialized.  */
 typedef struct {
-  /* RFC 4880: this must be 4.  */
+  /* We support version 4 (rfc4880) and 5 (rfc4880bis).  */
   byte version;
   byte version;
-  /* The cipher algorithm used to encrypt the session key.  (This may
-     be different from the algorithm that is used to encrypt the SED
-     packet.)  */
+  /* The cipher algorithm used to encrypt the session key.  Note that
+   * this may be different from the algorithm that is used to encrypt
+   * bulk data.  */
   byte cipher_algo;
   byte cipher_algo;
+  /* The AEAD algorithm or 0 for CFB encryption.  */
+  byte aead_algo;
   /* The string-to-key specifier.  */
   STRING2KEY s2k;
   /* The length of SESKEY in bytes or 0 if this packet does not
   /* The string-to-key specifier.  */
   STRING2KEY s2k;
   /* The length of SESKEY in bytes or 0 if this packet does not
@@ -107,7 +109,8 @@ typedef struct {
      S2K function on the password is the session key. See RFC 4880,
      Section 5.3.)  */
   byte seskeylen;
      S2K function on the password is the session key. See RFC 4880,
      Section 5.3.)  */
   byte seskeylen;
-  /* The session key as encrypted by the S2K specifier.  */
+  /* The session key as encrypted by the S2K specifier.  For AEAD this
+   * includes the nonce and the authentication tag.  */
   byte seskey[1];
 } PKT_symkey_enc;
 
   byte seskey[1];
 } PKT_symkey_enc;
 
index de51770..5c6d364 100644 (file)
@@ -1105,7 +1105,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
 {
   PKT_symkey_enc *k;
   int rc = 0;
 {
   PKT_symkey_enc *k;
   int rc = 0;
-  int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
+  int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen;
 
   if (pktlen < 4)
     {
 
   if (pktlen < 4)
     {
@@ -1117,7 +1117,11 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   version = iobuf_get_noeof (inp);
   pktlen--;
     }
   version = iobuf_get_noeof (inp);
   pktlen--;
-  if (version != 4)
+  if (version == 4)
+    ;
+  else if (version == 5)
+    ;
+  else
     {
       log_error ("packet(%d) with unknown version %d\n", pkttype, version);
       if (list_mode)
     {
       log_error ("packet(%d) with unknown version %d\n", pkttype, version);
       if (list_mode)
@@ -1135,6 +1139,13 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   cipher_algo = iobuf_get_noeof (inp);
   pktlen--;
     }
   cipher_algo = iobuf_get_noeof (inp);
   pktlen--;
+  if (version == 5)
+    {
+      aead_algo = iobuf_get_noeof (inp);
+      pktlen--;
+    }
+  else
+    aead_algo = 0;
   s2kmode = iobuf_get_noeof (inp);
   pktlen--;
   hash_algo = iobuf_get_noeof (inp);
   s2kmode = iobuf_get_noeof (inp);
   pktlen--;
   hash_algo = iobuf_get_noeof (inp);
@@ -1169,6 +1180,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
                                              + seskeylen - 1);
   k->version = version;
   k->cipher_algo = cipher_algo;
                                              + seskeylen - 1);
   k->version = version;
   k->cipher_algo = cipher_algo;
+  k->aead_algo = aead_algo;
   k->s2k.mode = s2kmode;
   k->s2k.hash_algo = hash_algo;
   if (s2kmode == 1 || s2kmode == 3)
   k->s2k.mode = s2kmode;
   k->s2k.hash_algo = hash_algo;
   if (s2kmode == 1 || s2kmode == 3)
@@ -1199,10 +1211,20 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
   if (list_mode)
     {
       es_fprintf (listfp,
   if (list_mode)
     {
       es_fprintf (listfp,
-                  ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
-                  version, cipher_algo, s2kmode, hash_algo);
+                  ":symkey enc packet: version %d, cipher %d, aead %d,"
+                  " s2k %d, hash %d",
+                  version, cipher_algo, aead_algo, s2kmode, hash_algo);
       if (seskeylen)
       if (seskeylen)
-       es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
+        {
+          /* To compute the size of the session key we need to know
+           * the size of the AEAD nonce which we may not know.  Thus
+           * we show only the seize of the entire encrypted session
+           * key.  */
+          if (aead_algo)
+            es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen);
+          else
+            es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
+        }
       es_fprintf (listfp, "\n");
       if (s2kmode == 1 || s2kmode == 3)
        {
       es_fprintf (listfp, "\n");
       if (s2kmode == 1 || s2kmode == 3)
        {
index 7045e8c..df71ccc 100644 (file)
@@ -1326,9 +1326,6 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
     s2k->hash_algo = S2K_DIGEST_ALGO;
 
     algo = default_cipher_algo();
     s2k->hash_algo = S2K_DIGEST_ALGO;
 
     algo = default_cipher_algo();
-    if (!opt.quiet || !opt.batch)
-        log_info (_("%s encryption will be used\n"),
-                  openpgp_cipher_algo_name (algo) );
     cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled);
 
     if (!cfx.dek || !cfx.dek->keylen) {
     cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled);
 
     if (!cfx.dek || !cfx.dek->keylen) {
@@ -1341,6 +1338,12 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
     if (!cfx.dek->use_aead)
       cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
 
     if (!cfx.dek->use_aead)
       cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
 
+    if (!opt.quiet || !opt.batch)
+        log_info (_("%s.%s encryption will be used\n"),
+                  openpgp_cipher_algo_name (algo),
+                  cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
+                  /**/             : "CFB");
+
     /* now create the outfile */
     rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
     if (rc)
     /* now create the outfile */
     rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
     if (rc)