[git] GnuPG - branch, master, updated. gnupg-2.2.3-126-gff1bdc2

by Werner Koch cvs at cvs.gnupg.org
Wed Jan 24 13:58:18 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  ff1bdc23d9f1693c1add7c1fe8d218b7bf743e31 (commit)
       via  83a15fa88e91d277811b6d030c4aa40c4fb3e6ad (commit)
       via  f3ef8b0dcaede1c85da0dff8eeceda6a994f0b28 (commit)
      from  112e02ee89b78369c1c50e672873e726cbfeb994 (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 ff1bdc23d9f1693c1add7c1fe8d218b7bf743e31
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jan 24 13:45:05 2018 +0100

    gpg: Fix AEAD encryption for chunk sizes other than 64 KiB.
    
    * g10/cipher-aead.c (do_flush): Init ERR.  Fix remaining chunklen
    computation.
    (do_free): Add dummy encryption.  Close the cipher handle.
    * g10/decrypt-data.c (aead_underflow): Rewrite.
    --
    
    Until we have integrated test into the test suite extensive tests can
    also be done with a script like this:
    
    --8<---------------cut here---------------start------------->8---
    #!/bin/sh
    
    set -e
    GPG="../g10/gpg --rfc4880bis --pinentry-mode=loopback"
    GPG="$GPG --passphrase abc --batch"
    MKTDATA="$HOME/b/gnupg-2.0/tools/mk-tdata"
    
    for chunksize in 6 7 12 13 14 30; do
    for count in $(seq 1 200) $(seq 8100 8200) \
                 $(seq 16350 16400) $(seq 20000 20100); do
      if [ ! -f "testfile-$count" ]; then
        $MKTDATA $count >"testfile-$count"
      fi
      echo "testing chunk size 2^$chunksize with $count bytes"
      $GPG --force-aead --aead-algo ocb --s2k-mode 0 --cipher AES -v -z 0 \
          -c --chunk-size $chunksize \
           <"testfile-$count" >"testfile-$count.gpg" 2>/dev/null
      $GPG -vd <"testfile-$count.gpg" >"testfile-$count.out" 2>/dev/null
      if ! cmp "testfile-$count" "testfile-$count.out"; then
        echo "FAILED comparing count $count" >&2
        exit 1
      fi
    done
    done
    echo All good
    --8<---------------cut here---------------end--------------->8---
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c
index 9cb57bd..573bb43 100644
--- a/g10/cipher-aead.c
+++ b/g10/cipher-aead.c
@@ -271,7 +271,7 @@ write_final_chunk (cipher_filter_context_t *cfx, iobuf_t a)
 static gpg_error_t
 do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
 {
-  gpg_error_t err;
+  gpg_error_t err = 0;
   int newchunk = 0;
   size_t n;
 
@@ -285,9 +285,9 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
       else
         n = cfx->bufsize - cfx->buflen;
 
-      if (cfx->chunklen + n >= cfx->chunksize)
+      if (cfx->chunklen + cfx->buflen + n >= cfx->chunksize)
         {
-          size_t n1 = cfx->chunksize - cfx->chunklen;
+          size_t n1 = cfx->chunksize - (cfx->chunklen + cfx->buflen);
           newchunk = 1;
           if (DBG_FILTER)
             log_debug ("chunksize %ju reached;"
@@ -305,8 +305,8 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
       if (cfx->buflen == cfx->bufsize || newchunk)
         {
           if (DBG_FILTER)
-            log_debug ("encrypting: buflen=%zu %s %p\n",
-                       cfx->buflen, newchunk?"(newchunk)":"", cfx->cipher_hd);
+            log_debug ("encrypting: buflen=%zu %s n=%zu\n",
+                       cfx->buflen, newchunk?"(newchunk)":"", n);
           if (newchunk)
             gcry_cipher_final (cfx->cipher_hd);
           if (!DBG_FILTER)
@@ -372,6 +372,9 @@ do_free (cipher_filter_context_t *cfx, iobuf_t a)
 {
   gpg_error_t err = 0;
 
+  if (DBG_FILTER)
+    log_debug ("do_free: buflen=%zu\n", cfx->buflen);
+
   /* FIXME: Check what happens if we just wrote the last chunk and no
    * more bytes were to encrypt.  We should then not call finalize and
    * write the auth tag again, right?  May this at all happen?  */
@@ -394,6 +397,8 @@ do_free (cipher_filter_context_t *cfx, iobuf_t a)
       cfx->chunklen += cfx->buflen;
       cfx->total += cfx->buflen;
     }
+  else /* Dummy encryption.  */
+    gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, 0, NULL, 0);
 
   /* Get and write the authentication tag.  */
   if (DBG_FILTER)
@@ -411,8 +416,8 @@ do_free (cipher_filter_context_t *cfx, iobuf_t a)
  leave:
   xfree (cfx->buffer);
   cfx->buffer = NULL;
-  /* gcry_cipher_close (cfx->cipher_hd); */
-  /* cfx->cipher_hd = NULL; */
+  gcry_cipher_close (cfx->cipher_hd);
+  cfx->cipher_hd = NULL;
   return err;
 }
 
diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index fc72472..afdedcb 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -56,8 +56,8 @@ struct decode_filter_context_s
   /* The start IV for AEAD encryption.   */
   byte startiv[16];
 
-  /* The holdback buffer and its used length.  For AEAD we need at
-   * least 32+1 byte for MDC 22 bytes are required.  */
+  /* The holdback buffer and its used length.  For AEAD we need 32+1
+   * bytes but we use 48 byte.  For MDC we need 22 bytes.  */
   char holdback[48];
   unsigned int holdbacklen;
 
@@ -536,262 +536,277 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
 static gpg_error_t
 aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
 {
-  const size_t size = *ret_len; /* The initial length of BUF.  */
+  const size_t size = *ret_len; /* The allocated size of BUF.  */
   gpg_error_t err;
-  size_t n; /* Finally the number of decrypted bytes in BUF.  */
+  size_t totallen = 0; /* The number of bytes to return on success or EOF.  */
+  size_t off = 0;      /* The offset into the buffer.  */
+  size_t len;          /* The current number of bytes in BUF+OFF.  */
   int c;
 
-  log_assert (size > 64); /* Our code requires at least this size.  */
+  log_assert (size > 48); /* Our code requires at least this size.  */
 
-  /* Get at least 32 bytes and put it ahead in the buffer.  */
+  /* Copy the rest from the last call of this function into BUF.  */
+  len = dfx->holdbacklen;
+  dfx->holdbacklen = 0;
+  memcpy (buf, dfx->holdback, len);
+
+  if (DBG_FILTER)
+    log_debug ("aead_underflow: size=%zu len=%zu%s\n",
+               size, len, dfx->eof_seen? " eof":"");
+
+  /* Read and fill up BUF.  We need to watchout for an EOF so that we
+   * can detect the last chunk which is commonly shorter than the
+   * chunksize.  After the last data byte from the last chunk 32 more
+   * bytes are expected for the last chunk's tag and the following
+   * final chunk's tag.  To detect the EOF we need to read at least
+   * one further byte; however we try to ready 16 extra bytes to avoid
+   * singel byte reads in some lower layers.  The outcome is that we
+   * have up to 48 extra extra octets which we will later put into the
+   * holdback buffer for the next invocation (which handles the EOF
+   * case).  */
   if (dfx->partial)
     {
-      for (n=32; n < 64; n++)
+      for (; len < size; len++ )
         {
           if ((c = iobuf_get (a)) == -1)
-            break;
-          buf[n] = c;
+            {
+              dfx->eof_seen = 1; /* Normal EOF. */
+              break;
+            }
+          buf[len] = c;
         }
     }
   else
     {
-      for (n=32; n < 64 && dfx->length; n++, dfx->length--)
+      for (; len < size && dfx->length; len++, dfx->length--)
         {
-          if ((c = iobuf_get (a)) == -1)
-            break; /* Premature EOF.  */
-          buf[n] = c;
+          c = iobuf_get (a);
+          if (c == -1)
+            {
+              dfx->eof_seen = 3; /* Premature EOF. */
+              break;
+            }
+          buf[len] = c;
         }
+      if (!dfx->length)
+        dfx->eof_seen = 1; /* Normal EOF.  */
     }
 
-  if (n == 64)
+  if (len < 32)
     {
-      /* We got 32 bytes from A which are good for the last chunk's
-       * auth tag and the final chunk's auth tag.  On the first time
-       * we don't have anything in the holdback buffer and thus we move
-       * those 32 bytes to the start of the buffer.  All further calls
-       * will copy the 32 bytes from the holdback buffer to the start of the
-       * buffer.  */
-      if (!dfx->holdbacklen)
-        {
-          memcpy (buf, buf+32, 32);
-          n = 32;  /* Continue at this position.  */
-        }
-      else
+      /* Not enough data for the last two tags.  */
+      err = gpg_error (GPG_ERR_TRUNCATED);
+      goto leave;
+    }
+  if (dfx->eof_seen)
+    {
+      /* If have seen an EOF we copy only the last two auth tags into
+       * the holdback buffer.  */
+      dfx->holdbacklen = 32;
+      memcpy (dfx->holdback, buf+len-32, 32);
+      len -= 32;
+    }
+  else
+    {
+      /* If have not seen an EOF we copy the entire extra 48 bytes
+       * into the holdback buffer for processing at the next call of
+       * this function.  */
+      dfx->holdbacklen = len > 48? 48 : len;
+      memcpy (dfx->holdback, buf+len-dfx->holdbacklen, dfx->holdbacklen);
+      len -= dfx->holdbacklen;
+    }
+  /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */
+
+  /* Decrypt the buffer.  This requires a loop because a chunk may end
+   * within the buffer.  */
+  if (DBG_FILTER)
+    log_debug ("decrypt loop: chunklen=%ju total=%ju size=%zu len=%zu%s\n",
+               (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, len,
+               dfx->eof_seen? " eof":"");
+
+  while (len && dfx->chunklen + len >= dfx->chunksize)
+    {
+      size_t n = dfx->chunksize - dfx->chunklen;
+      byte tagbuf[16];
+
+      if (DBG_FILTER)
+        log_debug ("chunksize will be reached: n=%zu\n", n);
+      /* log_printhex (buf, n, "ciph:"); */
+      gcry_cipher_final (dfx->cipher_hd);
+      err = gcry_cipher_decrypt (dfx->cipher_hd, buf+off, n, NULL, 0);
+      if (err)
         {
-          memcpy (buf, dfx->holdback, 32);
+          log_error ("gcry_cipher_decrypt failed (1): %s\n",
+                     gpg_strerror (err));
+          goto leave;
         }
+      /* log_printhex (buf, n, "plai:"); */
+      totallen += n;
+      dfx->chunklen += n;
+      dfx->total += n;
+      off += n;
+      len -= n;
 
-      /* Now fill up the provided buffer.  */
-      if (dfx->partial)
+      if (DBG_FILTER)
+        log_debug ("bytes left: %zu at off=%zu\n", len, off);
+
+      /* Check the tag.  */
+      if (len < 16)
         {
-          for (; n < size; n++ )
+          /* The tag is not entirely in the buffer.  Read the rest of
+           * the tag from the holdback buffer.  The shift the holdback
+           * buffer and fill it up again.  */
+          memcpy (tagbuf, buf+off, len);
+          memcpy (tagbuf + len, dfx->holdback, 16 - len);
+          dfx->holdbacklen -= 16-len;
+          memmove (dfx->holdback, dfx->holdback + (16-len), dfx->holdbacklen);
+
+          len = dfx->holdbacklen;
+          if (dfx->partial)
             {
-              if ((c = iobuf_get (a)) == -1)
+              for (; len < 48; len++ )
                 {
-                  dfx->eof_seen = 1; /* Normal EOF. */
-                  break;
+                  if ((c = iobuf_get (a)) == -1)
+                    {
+                      dfx->eof_seen = 1; /* Normal EOF. */
+                      break;
+                    }
+                  dfx->holdback[len] = c;
                 }
-              buf[n] = c;
             }
-        }
-      else
-        {
-          for (; n < size && dfx->length; n++, dfx->length--)
+          else
             {
-              c = iobuf_get (a);
-              if (c == -1)
+              for (; len < 48 && dfx->length; len++, dfx->length--)
                 {
-                  dfx->eof_seen = 3; /* Premature EOF. */
-                  break;
+                  c = iobuf_get (a);
+                  if (c == -1)
+                    {
+                      dfx->eof_seen = 3; /* Premature EOF. */
+                      break;
+                    }
+                  dfx->holdback[len] = c;
                 }
-              buf[n] = c;
+              if (!dfx->length)
+                dfx->eof_seen = 1; /* Normal EOF.  */
+            }
+          if (len < 32)
+            {
+              /* Not enough data for the last two tags.  */
+              err = gpg_error (GPG_ERR_TRUNCATED);
+              goto leave;
             }
-          if (!dfx->length)
-            dfx->eof_seen = 1; /* Normal EOF.  */
+          dfx->holdbacklen = len;
+          /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */
+          len = 0;
+        }
+      else /* We already have the full tag.  */
+        {
+          memcpy (tagbuf, buf+off, 16);
+          /* Remove that tag from the output.  */
+          memmove (buf + off, buf + off + 16, len - 16);
+          len -= 16;
+        }
+      if (DBG_CRYPTO)
+        log_printhex (tagbuf, 16, "tag:");
+      err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16);
+      if (err)
+        {
+          if (DBG_FILTER)
+            log_debug ("gcry_cipher_checktag failed (1): %s\n",
+                       gpg_strerror (err));
+          goto leave;
         }
 
-      /* Move the trailing 32 bytes back to the holdback buffer.  We
-       * got at least 64 bytes and thus a memmove is not needed.  */
-      n -= 32;
-      memcpy (dfx->holdback, buf+n, 32);
-      dfx->holdbacklen = 32;
-    }
-  else if (!dfx->holdbacklen)
-    {
-      /* EOF seen but empty holdback buffer.  This means that we did
-       * not read enough for the two auth tags.  */
-      n -= 32;
-      memcpy (buf, buf+32, n );
-      dfx->eof_seen = 2; /* EOF with incomplete tag.  */
-    }
-  else
-    {
-      /* EOF seen (i.e. read less than 32 bytes). */
-      memcpy (buf, dfx->holdback, 32);
-      n -= 32;
-      memcpy (dfx->holdback, buf+n, 32);
-      dfx->eof_seen = 1; /* Normal EOF. */
-    }
+      /* Prepare a new chunk.  */
+      dfx->chunklen = 0;
+      dfx->chunkindex++;
+      err = aead_set_nonce (dfx);
+      if (err)
+        goto leave;
+      err = aead_set_ad (dfx, 0);
+      if (err)
+        goto leave;
 
-  if (DBG_FILTER)
-    log_debug ("decrypt: chunklen=%ju total=%ju size=%zu n=%zu%s\n",
-               (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, n,
-               dfx->eof_seen? " eof":"");
+      continue;
+    }
 
-  /* Now decrypt the buffer.  */
-  if (n && dfx->eof_seen > 1)
+  if (dfx->eof_seen)
     {
-      err = gpg_error (GPG_ERR_TRUNCATED);
+      /* This is the last block of the last chunk.  Its length may
+       * not be a multiple of the block length.  */
+      gcry_cipher_final (dfx->cipher_hd);
     }
-  else if (!n)
+  err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, len, NULL, 0);
+  if (err)
     {
-      log_assert (dfx->eof_seen);
-      err = gpg_error (GPG_ERR_EOF);
+      log_error ("gcry_cipher_decrypt failed (2): %s\n", gpg_strerror (err));
+      goto leave;
     }
-  else
+  totallen += len;
+  dfx->chunklen += len;
+  dfx->total += len;
+  if (dfx->eof_seen)
     {
-      size_t off = 0;
-
-      if (dfx->chunklen + n >= dfx->chunksize)
-        {
-          size_t n0 = dfx->chunksize - dfx->chunklen;
-
-          if (DBG_FILTER)
-            log_debug ("chunksize will be reached: n0=%zu\n", n0);
-          gcry_cipher_final (dfx->cipher_hd);
-          err = gcry_cipher_decrypt (dfx->cipher_hd, buf, n0, NULL, 0);
-          if (err)
-            {
-              log_error ("gcry_cipher_decrypt failed (1): %s\n",
-                         gpg_strerror (err));
-              goto leave;
-            }
-          /*log_printhex (buf, n, "buf:");*/
-          dfx->chunklen += n0;
-          dfx->total += n0;
-          off = n0;
-          n -= n0;
+      if (DBG_FILTER)
+        log_debug ("eof seen: holdback buffer has the tags.\n");
 
-          if (DBG_FILTER)
-            log_debug ("bytes left: %zu  off=%zu\n", n, off);
-          log_assert (n >= 16);
-          log_assert (dfx->holdbacklen);
-          if (DBG_CRYPTO)
-            log_printhex (buf+off, 16, "tag:");
-          err = gcry_cipher_checktag (dfx->cipher_hd, buf + off, 16);
-          if (err)
-            {
-              if (DBG_FILTER)
-                log_debug ("gcry_cipher_checktag failed (1): %s\n",
-                           gpg_strerror (err));
-              /* Return Bad Signature like we do with MDC encryption. */
-              if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
-                err = gpg_error (GPG_ERR_BAD_SIGNATURE);
-              goto leave;
-            }
-          /* Remove that tag from the output.  */
-          memmove (buf + off, buf + off + 16, n - 16);
-          n -= 16;
-
-          /* Prepare a new chunk.  */
-          dfx->chunklen = 0;
-          dfx->chunkindex++;
-          err = aead_set_nonce (dfx);
-          if (err)
-            goto leave;
-          err = aead_set_ad (dfx, 0);
-          if (err)
-            goto leave;
-        }
+      log_assert (dfx->holdbacklen >= 32);
 
-      if (dfx->eof_seen)
+      if (DBG_FILTER)
+        log_printhex (dfx->holdback, 16, "tag:");
+      err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback, 16);
+      if (err)
         {
-          /* This is the last block of the last chunk.  Its length may
-           * not be a multiple of the block length.  We expect that it
-           * is followed by two authtags.  The first being the one
-           * from the current chunk and the second form the final
-           * chunk encrypting the empty string.  Note that for the
-           * other blocks we assume a multiple of the block length
-           * which is only true because the filter is called with
-           * large 2^n sized buffers.  There is no assert because
-           * gcry_cipher_decrypt would detect such an error.  */
-          gcry_cipher_final (dfx->cipher_hd);
-          /* log_printhex (buf+off, n, "buf+off:"); */
+          log_error ("gcry_cipher_checktag failed (2): %s\n",
+                     gpg_strerror (err));
+          goto leave;
         }
-      err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, n, NULL, 0);
+
+      /* Check the final chunk.  */
+      dfx->chunkindex++;
+      err = aead_set_nonce (dfx);
+      if (err)
+        goto leave;
+      err = aead_set_ad (dfx, 1);
+      if (err)
+        goto leave;
+      gcry_cipher_final (dfx->cipher_hd);
+      /* decrypt an empty string.  */
+      err = gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 0, NULL, 0);
       if (err)
         {
-          log_error ("gcry_cipher_decrypt failed (2): %s\n",
+          log_error ("gcry_cipher_decrypt failed (final): %s\n",
                      gpg_strerror (err));
           goto leave;
         }
-      dfx->chunklen += n;
-      dfx->total += n;
-
-      if (dfx->eof_seen)
+      /* log_printhex (dfx->holdback+16, 16, "tag:"); */
+      err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback+16, 16);
+      if (err)
         {
-          log_printhex (buf+off, n, "buf+off:");
-          if (DBG_FILTER)
-            log_debug ("eof seen: chunklen=%ju total=%ju off=%zu n=%zu\n",
-                       (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, off, n);
-
-          log_assert (dfx->holdbacklen);
-          err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback, 16);
-          if (err)
-            {
-              log_printhex (dfx->holdback, 16, "tag:");
-              log_error ("gcry_cipher_checktag failed (2): %s\n",
-                         gpg_strerror (err));
-              /* Return Bad Signature like we do with MDC encryption. */
-              if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
-                err = gpg_error (GPG_ERR_BAD_SIGNATURE);
-              goto leave;
-            }
-
-          /* Check the final chunk.  */
-          dfx->chunkindex++;
-          err = aead_set_nonce (dfx);
-          if (err)
-            goto leave;
-          err = aead_set_ad (dfx, 1);
-          if (err)
-            goto leave;
-          gcry_cipher_final (dfx->cipher_hd);
-          /* decrypt an empty string.  */
-          err = gcry_cipher_decrypt (dfx->cipher_hd, buf, 0, NULL, 0);
-          if (err)
-            {
-              log_error ("gcry_cipher_decrypt failed (final): %s\n",
-                         gpg_strerror (err));
-              goto leave;
-            }
-          err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback+16, 16);
-          if (err)
-            {
-              if (DBG_FILTER)
-                log_debug ("gcry_cipher_checktag failed (final): %s\n",
-                           gpg_strerror (err));
-              /* Return Bad Signature like we do with MDC encryption. */
-              if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
-                err = gpg_error (GPG_ERR_BAD_SIGNATURE);
-              goto leave;
-            }
-
-          n += off;
           if (DBG_FILTER)
-            log_debug ("eof seen: returning %zu\n", n);
-          /* log_printhex (buf, n, "buf:"); */
+            log_debug ("gcry_cipher_checktag failed (final): %s\n",
+                       gpg_strerror (err));
+          goto leave;
         }
-      else
-        n += off;
+      err = gpg_error (GPG_ERR_EOF);
     }
 
  leave:
-  /* In case of a real error we better wipe out the buffer than to
-   * keep partly encrypted data.  */
+  if (DBG_FILTER)
+    log_debug ("aead_underflow: returning %zu (%s)\n",
+               totallen, gpg_strerror (err));
+
+  /* In case of an auth error we map the error code to the same as
+   * used by the MDC decryption.  */
+  if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
+    err = gpg_error (GPG_ERR_BAD_SIGNATURE);
+
+  /* In case of an error we better wipe out the buffer than to convey
+   * partly decrypted data.  */
   if (err && gpg_err_code (err) != GPG_ERR_EOF)
     memset (buf, 0, size);
-  *ret_len = n;
+
+  *ret_len = totallen;
 
   return err;
 }

commit 83a15fa88e91d277811b6d030c4aa40c4fb3e6ad
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jan 24 08:59:06 2018 +0100

    gpg: Rename a variable in decrypt-data for clarity.
    
    * g10/decrypt-data.c (decode_filter_context_s): Rename field 'defer'
    to 'holdback' and replace 'defer_filled' flag into 'holdbacklen'.
    Change all users.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index 3d7d747..fc72472 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -56,11 +56,10 @@ struct decode_filter_context_s
   /* The start IV for AEAD encryption.   */
   byte startiv[16];
 
-  /* The holdback buffer.  For AEAD we need 32 bytes for MDC 22 bytes
-   * are enough.  The flag indicates whether the holdback buffer is
-   * filled. */
-  char defer[32];
-  unsigned int defer_filled : 1;
+  /* The holdback buffer and its used length.  For AEAD we need at
+   * least 32+1 byte for MDC 22 bytes are required.  */
+  char holdback[48];
+  unsigned int holdbacklen;
 
   /* Working on a partial length packet.  */
   unsigned int partial : 1;
@@ -512,16 +511,16 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
 
       log_assert (dfx->cipher_hd);
       log_assert (dfx->mdc_hash);
-      gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0);
-      gcry_md_write (dfx->mdc_hash, dfx->defer, 2);
+      gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 22, NULL, 0);
+      gcry_md_write (dfx->mdc_hash, dfx->holdback, 2);
       gcry_md_final (dfx->mdc_hash);
 
-      if (   dfx->defer[0] != '\xd3'
-          || dfx->defer[1] != '\x14'
+      if (   dfx->holdback[0] != '\xd3'
+          || dfx->holdback[1] != '\x14'
           || datalen != 20
-          || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen))
+          || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->holdback+2, datalen))
         rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
-      /* log_printhex("MDC message:", dfx->defer, 22); */
+      /* log_printhex("MDC message:", dfx->holdback, 22); */
       /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */
     }
 
@@ -568,18 +567,18 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
     {
       /* We got 32 bytes from A which are good for the last chunk's
        * auth tag and the final chunk's auth tag.  On the first time
-       * we don't have anything in the defer buffer and thus we move
+       * we don't have anything in the holdback buffer and thus we move
        * those 32 bytes to the start of the buffer.  All further calls
-       * will copy the deferred 32 bytes to the start of the
+       * will copy the 32 bytes from the holdback buffer to the start of the
        * buffer.  */
-      if (!dfx->defer_filled)
+      if (!dfx->holdbacklen)
         {
           memcpy (buf, buf+32, 32);
           n = 32;  /* Continue at this position.  */
         }
       else
         {
-          memcpy (buf, dfx->defer, 32);
+          memcpy (buf, dfx->holdback, 32);
         }
 
       /* Now fill up the provided buffer.  */
@@ -611,16 +610,16 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
             dfx->eof_seen = 1; /* Normal EOF.  */
         }
 
-      /* Move the trailing 32 bytes back to the defer buffer.  We
+      /* Move the trailing 32 bytes back to the holdback buffer.  We
        * got at least 64 bytes and thus a memmove is not needed.  */
       n -= 32;
-      memcpy (dfx->defer, buf+n, 32);
-      dfx->defer_filled = 1;
+      memcpy (dfx->holdback, buf+n, 32);
+      dfx->holdbacklen = 32;
     }
-  else if (!dfx->defer_filled)
+  else if (!dfx->holdbacklen)
     {
-      /* EOF seen but empty defer buffer.  This means that we did not
-       * read enough for the two auth tags.  */
+      /* EOF seen but empty holdback buffer.  This means that we did
+       * not read enough for the two auth tags.  */
       n -= 32;
       memcpy (buf, buf+32, n );
       dfx->eof_seen = 2; /* EOF with incomplete tag.  */
@@ -628,9 +627,9 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
   else
     {
       /* EOF seen (i.e. read less than 32 bytes). */
-      memcpy (buf, dfx->defer, 32);
+      memcpy (buf, dfx->holdback, 32);
       n -= 32;
-      memcpy (dfx->defer, buf+n, 32);
+      memcpy (dfx->holdback, buf+n, 32);
       dfx->eof_seen = 1; /* Normal EOF. */
     }
 
@@ -676,7 +675,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
           if (DBG_FILTER)
             log_debug ("bytes left: %zu  off=%zu\n", n, off);
           log_assert (n >= 16);
-          log_assert (dfx->defer_filled);
+          log_assert (dfx->holdbacklen);
           if (DBG_CRYPTO)
             log_printhex (buf+off, 16, "tag:");
           err = gcry_cipher_checktag (dfx->cipher_hd, buf + off, 16);
@@ -717,7 +716,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
            * large 2^n sized buffers.  There is no assert because
            * gcry_cipher_decrypt would detect such an error.  */
           gcry_cipher_final (dfx->cipher_hd);
-          /*log_printhex (buf+off, n, "buf+off:");*/
+          /* log_printhex (buf+off, n, "buf+off:"); */
         }
       err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, n, NULL, 0);
       if (err)
@@ -731,15 +730,16 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
 
       if (dfx->eof_seen)
         {
-          /* log_printhex (buf+off, n, "buf+off:"); */
+          log_printhex (buf+off, n, "buf+off:");
           if (DBG_FILTER)
             log_debug ("eof seen: chunklen=%ju total=%ju off=%zu n=%zu\n",
                        (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, off, n);
 
-          log_assert (dfx->defer_filled);
-          err = gcry_cipher_checktag (dfx->cipher_hd, dfx->defer, 16);
+          log_assert (dfx->holdbacklen);
+          err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback, 16);
           if (err)
             {
+              log_printhex (dfx->holdback, 16, "tag:");
               log_error ("gcry_cipher_checktag failed (2): %s\n",
                          gpg_strerror (err));
               /* Return Bad Signature like we do with MDC encryption. */
@@ -765,7 +765,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
                          gpg_strerror (err));
               goto leave;
             }
-          err = gcry_cipher_checktag (dfx->cipher_hd, dfx->defer+16, 16);
+          err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback+16, 16);
           if (err)
             {
               if (DBG_FILTER)
@@ -881,8 +881,8 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
         }
       if (n == 44)
         {
-          /* We have enough stuff - flush the deferred stuff.  */
-          if ( !dfx->defer_filled )  /* First time. */
+          /* We have enough stuff - flush the holdback buffer.  */
+          if ( !dfx->holdbacklen )  /* First time. */
             {
               memcpy (buf, buf+22, 22);
               n = 22;
@@ -890,7 +890,7 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
           else
             {
 
-              memcpy (buf, dfx->defer, 22);
+              memcpy (buf, dfx->holdback, 22);
 	    }
           /* Fill up the buffer. */
           if (dfx->partial)
@@ -921,13 +921,13 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
                 dfx->eof_seen = 1; /* Normal EOF.  */
             }
 
-          /* Move the trailing 22 bytes back to the defer buffer.  We
+          /* Move the trailing 22 bytes back to the holdback buffer.  We
              have at least 44 bytes thus a memmove is not needed.  */
           n -= 22;
-          memcpy (dfx->defer, buf+n, 22 );
-          dfx->defer_filled = 1;
+          memcpy (dfx->holdback, buf+n, 22 );
+          dfx->holdbacklen = 22;
 	}
-      else if ( !dfx->defer_filled )  /* EOF seen but empty defer buffer. */
+      else if ( !dfx->holdbacklen ) /* EOF seen but empty holdback. */
         {
           /* This is bad because it means an incomplete hash. */
           n -= 22;
@@ -936,9 +936,9 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
 	}
       else  /* EOF seen (i.e. read less than 22 bytes). */
         {
-          memcpy (buf, dfx->defer, 22 );
+          memcpy (buf, dfx->holdback, 22 );
           n -= 22;
-          memcpy (dfx->defer, buf+n, 22 );
+          memcpy (dfx->holdback, buf+n, 22 );
           dfx->eof_seen = 1; /* Normal EOF. */
 	}
 

commit f3ef8b0dcaede1c85da0dff8eeceda6a994f0b28
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jan 23 19:08:16 2018 +0100

    gpg: New option --chunk-size.
    
    * g10/gpg.c (opts): New option --chunk-size.
    (oChunkSize): New const.
    (build_list_aead_test_algo, build_list_aead_algo_name): New.
    (my_strusage): List AEAD algos.
    (main): Implement --chunk-size..
    * g10/options.h (struct opt): Add field 'chunk_size'.
    (DBG_IPC): Remove duplicated macro.
    * g10/main.h (DEFAULT_AEAD_ALGO): Depend on Libgcrypt version.
    * g10/misc.c (openpgp_aead_test_algo): Ditto.
    
    * g10/cipher-aead.c: Silence if not in debug mode.
    * g10/decrypt-data.c: Ditto.
    --
    
    And that new option immediatley revealed bugs in our chunking code :-(.

diff --git a/doc/gpg.texi b/doc/gpg.texi
index 35bb9a8..1e6ea59 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -2255,6 +2255,16 @@ works properly with such messages, there is often a desire to set a
 maximum file size that will be generated before processing is forced to
 stop by the OS limits. Defaults to 0, which means "no limit".
 
+ at item --chunk-size @var{n}
+ at opindex chunk-size
+The AEAD encryption mode encrypts the data in chunks so that a
+receiving side can check for transmission errors or tampering at the
+end of each chunk and does not need to delay this until all data has
+been received.  The used chunk size is 2^@var{n} byte.  The lowest
+allowed value for @var{n} is 6 (64 byte) and the largest is 62 (4
+EiB). The default value for @var{n} is 30 which creates chunks not
+larger than 1 GiB.
+
 @item --input-size-hint @var{n}
 @opindex input-size-hint
 This option can be used to tell GPG the size of the input data in
@@ -2592,6 +2602,16 @@ is the default.
 @itemx --no-force-v4-certs
 These options are obsolete and have no effect since GnuPG 2.1.
 
+ at item --force-aead
+ at opindex force-aead
+Force the use of AEAD encryption over MDC encryption.  AEAD is a
+modern and faster way to do authenticated encrytion than the old MDC
+method.  See also options @option{--aead-algo} and
+ at option{--chunk-size}.
+
+This option requires the use of option @option{--rfc4880bis} to
+declare that a not yet standardized feature is used.
+
 @item --force-mdc
 @opindex force-mdc
 Force the use of encryption with a modification detection code. This
@@ -2623,6 +2643,16 @@ preferences, as GPG will only select an algorithm that is usable by
 all recipients.  The most highly ranked cipher in this list is also
 used for the @option{--symmetric} encryption command.
 
+ at item --personal-aead-preferences @var{string}
+ at opindex personal-aead-preferences
+Set the list of personal AEAD preferences to @var{string}.  Use
+ at command{@gpgname --version} to get a list of available algorithms,
+and use @code{none} to set no preference at all.  This allows the user
+to safely override the algorithm chosen by the recipient key
+preferences, as GPG will only select an algorithm that is usable by
+all recipients.  The most highly ranked cipher in this list is also
+used for the @option{--symmetric} encryption command.
+
 @item --personal-digest-preferences @var{string}
 @opindex personal-digest-preferences
 Set the list of personal digest preferences to @var{string}.  Use
@@ -2981,17 +3011,28 @@ Use @var{name} as cipher algorithm. Running the program with the
 command @option{--version} yields a list of supported algorithms. If
 this is not used the cipher algorithm is selected from the preferences
 stored with the key. In general, you do not want to use this option as
-it allows you to violate the OpenPGP standard.
+it allows you to violate the OpenPGP standard.  The option
 @option{--personal-cipher-preferences} is the safe way to accomplish the
 same thing.
 
+ at item --aead-algo @var{name}
+ at opindex aead-algo
+Specify that the AEAD algorithm @var{name} is to be used.  This is
+useful for symmetric encryption where no key preference are available
+to select the AEAD algorithm.  Runing @command{@gpgname} with option
+ at option{--version} shows the available AEAD algorithms.  In general,
+you do not want to use this option as it allows you to violate the
+OpenPGP standard.  The option @option{--personal-aead-preferences} is
+the safe way to accomplish the same thing.
+
 @item --digest-algo @var{name}
 @opindex digest-algo
 Use @var{name} as the message digest algorithm. Running the program
-with the command @option{--version} yields a list of supported algorithms. In
-general, you do not want to use this option as it allows you to
-violate the OpenPGP standard. @option{--personal-digest-preferences} is the
-safe way to accomplish the same thing.
+with the command @option{--version} yields a list of supported
+algorithms. In general, you do not want to use this option as it
+allows you to violate the OpenPGP standard.  The option
+ at option{--personal-digest-preferences} is the safe way to accomplish
+the same thing.
 
 @item --compress-algo @var{name}
 @opindex compress-algo
@@ -3013,8 +3054,9 @@ significant in low memory situations. Note, however, that PGP (all
 versions) only supports ZIP compression. Using any algorithm other
 than ZIP or "none" will make the message unreadable with PGP. In
 general, you do not want to use this option as it allows you to
-violate the OpenPGP standard. @option{--personal-compress-preferences} is the
-safe way to accomplish the same thing.
+violate the OpenPGP standard.  The option
+ at option{--personal-compress-preferences} is the safe way to accomplish
+the same thing.
 
 @item --cert-digest-algo @var{name}
 @opindex cert-digest-algo
diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c
index 637bd71..9cb57bd 100644
--- a/g10/cipher-aead.c
+++ b/g10/cipher-aead.c
@@ -86,7 +86,8 @@ set_additional_data (cipher_filter_context_t *cfx, int final)
       ad[19] = cfx->total >>  8;
       ad[20] = cfx->total;
     }
-  log_printhex (ad, final? 21 : 13, "authdata:");
+  if (DBG_CRYPTO)
+    log_printhex (ad, final? 21 : 13, "authdata:");
   return gcry_cipher_authenticate (cfx->cipher_hd, ad, final? 21 : 13);
 }
 
@@ -124,7 +125,8 @@ set_nonce (cipher_filter_context_t *cfx)
   nonce[i++] ^= cfx->chunkindex >>  8;
   nonce[i++] ^= cfx->chunkindex;
 
-  log_printhex (nonce, 15, "nonce:");
+  if (DBG_CRYPTO)
+    log_printhex (nonce, 15, "nonce:");
   return gcry_cipher_setiv (cfx->cipher_hd, nonce, i);
 }
 
@@ -149,7 +151,8 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
   if (err)
     goto leave;
 
-  cfx->chunkbyte = 10;
+  log_assert (opt.chunk_size >= 6 && opt.chunk_size <= 62);
+  cfx->chunkbyte = opt.chunk_size - 6;
   cfx->chunksize = (uint64_t)1 << (cfx->chunkbyte + 6);
   cfx->chunklen = 0;
   cfx->bufsize = AEAD_ENC_BUFFER_SIZE;
@@ -170,8 +173,9 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
   pkt.pkttype = PKT_ENCRYPTED_AEAD;
   pkt.pkt.encrypted = &ed;
 
-  log_debug ("aead packet: len=%lu extralen=%d\n",
-             (unsigned long)ed.len, ed.extralen);
+  if (DBG_FILTER)
+    log_debug ("aead packet: len=%lu extralen=%d\n",
+               (unsigned long)ed.len, ed.extralen);
 
   write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
                        cfx->dek->algo, ed.aead_algo);
@@ -193,7 +197,8 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
   if (err)
     goto leave;
 
-  log_printhex (cfx->dek->key, cfx->dek->keylen, "thekey:");
+  if (DBG_CRYPTO)
+    log_printhex (cfx->dek->key, cfx->dek->keylen, "thekey:");
   err = gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen);
   if (err)
     return err;
@@ -226,7 +231,6 @@ write_auth_tag (cipher_filter_context_t *cfx, iobuf_t a)
   err = my_iobuf_write (a, tag, 16);
   if (err)
     goto leave;
-  log_printhex (tag, 16, "wrote tag:");
 
  leave:
   return err;
@@ -272,7 +276,8 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
   size_t n;
 
   /* Put the data into a buffer, flush and encrypt as needed.  */
-  log_debug ("flushing %zu bytes (cur buflen=%zu)\n", size, cfx->buflen);
+  if (DBG_FILTER)
+    log_debug ("flushing %zu bytes (cur buflen=%zu)\n", size, cfx->buflen);
   do
     {
       if (cfx->buflen + size < cfx->bufsize)
@@ -284,10 +289,11 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
         {
           size_t n1 = cfx->chunksize - cfx->chunklen;
           newchunk = 1;
-          log_debug ("chunksize %ju reached;"
-                     " cur buflen=%zu using %zu of %zu\n",
-                     (uintmax_t)cfx->chunksize, (uintmax_t)cfx->buflen,
-                     n1, n);
+          if (DBG_FILTER)
+            log_debug ("chunksize %ju reached;"
+                       " cur buflen=%zu using %zu of %zu\n",
+                       (uintmax_t)cfx->chunksize, (uintmax_t)cfx->buflen,
+                       n1, n);
           n = n1;
         }
 
@@ -298,11 +304,14 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
 
       if (cfx->buflen == cfx->bufsize || newchunk)
         {
-          log_debug ("encrypting: buflen=%zu %s %p\n",
-                     cfx->buflen, newchunk?"(newchunk)":"", cfx->cipher_hd);
+          if (DBG_FILTER)
+            log_debug ("encrypting: buflen=%zu %s %p\n",
+                       cfx->buflen, newchunk?"(newchunk)":"", cfx->cipher_hd);
           if (newchunk)
             gcry_cipher_final (cfx->cipher_hd);
-          if (newchunk)
+          if (!DBG_FILTER)
+            ;
+          else if (newchunk)
             log_printhex (cfx->buffer, cfx->buflen, "plain(1):");
           else if (cfx->buflen > 32)
             log_printhex (cfx->buffer + cfx->buflen - 32, 32,
@@ -314,7 +323,7 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
            * mode.  */
           gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen,
                                NULL, 0);
-          if (newchunk)
+          if (newchunk && DBG_FILTER)
             log_printhex (cfx->buffer, cfx->buflen, "ciphr(1):");
           err = my_iobuf_write (a, cfx->buffer, cfx->buflen);
           if (err)
@@ -325,18 +334,19 @@ do_flush (cipher_filter_context_t *cfx, iobuf_t a, byte *buf, size_t size)
 
           if (newchunk)
             {
-              log_debug ("chunklen=%ju  total=%ju\n",
-                         (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
+              if (DBG_FILTER)
+                log_debug ("chunklen=%ju  total=%ju\n",
+                           (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
               err = write_auth_tag (cfx, a);
               if (err)
                 {
-                  log_debug ("gcry_cipher_gettag failed: %s\n",
+                  log_error ("gcry_cipher_gettag failed: %s\n",
                              gpg_strerror (err));
                   goto leave;
                 }
 
-              log_debug ("starting a new chunk (cur size=%zu)\n", size);
-              log_printhex (buf, size, "cur buf:");
+              if (DBG_FILTER)
+                log_debug ("starting a new chunk (cur size=%zu)\n", size);
               cfx->chunkindex++;
               cfx->chunklen = 0;
               err = set_nonce (cfx);
@@ -373,10 +383,10 @@ do_free (cipher_filter_context_t *cfx, iobuf_t a)
   /* Encrypt any remaining bytes.  */
   if (cfx->buflen)
     {
-      log_debug ("processing last %zu bytes of the last chunk\n", cfx->buflen);
-      log_printhex (cfx->buffer, cfx->buflen, "plain(2):");
+      if (DBG_FILTER)
+        log_debug ("processing last %zu bytes of the last chunk\n",
+                   cfx->buflen);
       gcry_cipher_encrypt (cfx->cipher_hd, cfx->buffer, cfx->buflen, NULL, 0);
-      log_printhex (cfx->buffer, cfx->buflen, "ciphr(2):");
       err = my_iobuf_write (a, cfx->buffer, cfx->buflen);
       if (err)
         goto leave;
@@ -386,14 +396,16 @@ do_free (cipher_filter_context_t *cfx, iobuf_t a)
     }
 
   /* Get and write the authentication tag.  */
-  log_debug ("chunklen=%ju  total=%ju\n",
-             (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
+  if (DBG_FILTER)
+    log_debug ("chunklen=%ju  total=%ju\n",
+               (uintmax_t)cfx->chunklen, (uintmax_t)cfx->total);
   err = write_auth_tag (cfx, a);
   if (err)
     goto leave;
 
   /* Write the final chunk.  */
-  log_debug ("creating final chunk\n");
+  if (DBG_FILTER)
+    log_debug ("creating final chunk\n");
   err = write_final_chunk (cfx, a);
 
  leave:
diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index 46650f2..3d7d747 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -150,7 +150,8 @@ aead_set_nonce (decode_filter_ctx_t dfx)
   nonce[i++] ^= dfx->chunkindex >>  8;
   nonce[i++] ^= dfx->chunkindex;
 
-  log_printhex (nonce, i, "nonce:");
+  if (DBG_CRYPTO)
+    log_printhex (nonce, i, "nonce:");
   return gcry_cipher_setiv (dfx->cipher_hd, nonce, i);
 }
 
@@ -186,7 +187,8 @@ aead_set_ad (decode_filter_ctx_t dfx, int final)
       ad[19] = dfx->total >>  8;
       ad[20] = dfx->total;
     }
-  log_printhex (ad, final? 21 : 13, "authdata:");
+  if (DBG_CRYPTO)
+    log_printhex (ad, final? 21 : 13, "authdata:");
   return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13);
 }
 
@@ -327,7 +329,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
       if (rc)
         goto leave; /* Should never happen.  */
 
-      log_printhex (dek->key, dek->keylen, "thekey:");
+      if (DBG_CRYPTO)
+        log_printhex (dek->key, dek->keylen, "thekey:");
       rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
       if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
         {
@@ -631,9 +634,10 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
       dfx->eof_seen = 1; /* Normal EOF. */
     }
 
-  log_debug ("decrypt: chunklen=%ju total=%ju size=%zu n=%zu%s\n",
-             (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, n,
-             dfx->eof_seen? " eof":"");
+  if (DBG_FILTER)
+    log_debug ("decrypt: chunklen=%ju total=%ju size=%zu n=%zu%s\n",
+               (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, n,
+               dfx->eof_seen? " eof":"");
 
   /* Now decrypt the buffer.  */
   if (n && dfx->eof_seen > 1)
@@ -653,12 +657,13 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
         {
           size_t n0 = dfx->chunksize - dfx->chunklen;
 
-          log_debug ("chunksize will be reached: n0=%zu\n", n0);
+          if (DBG_FILTER)
+            log_debug ("chunksize will be reached: n0=%zu\n", n0);
           gcry_cipher_final (dfx->cipher_hd);
           err = gcry_cipher_decrypt (dfx->cipher_hd, buf, n0, NULL, 0);
           if (err)
             {
-              log_debug ("gcry_cipher_decrypt failed (1): %s\n",
+              log_error ("gcry_cipher_decrypt failed (1): %s\n",
                          gpg_strerror (err));
               goto leave;
             }
@@ -668,15 +673,18 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
           off = n0;
           n -= n0;
 
-          log_debug ("bytes left: %zu  off=%zu\n", n, off);
+          if (DBG_FILTER)
+            log_debug ("bytes left: %zu  off=%zu\n", n, off);
           log_assert (n >= 16);
           log_assert (dfx->defer_filled);
-          log_printhex (buf+off, 16, "tag:");
+          if (DBG_CRYPTO)
+            log_printhex (buf+off, 16, "tag:");
           err = gcry_cipher_checktag (dfx->cipher_hd, buf + off, 16);
           if (err)
             {
-              log_debug ("gcry_cipher_checktag failed (1): %s\n",
-                         gpg_strerror (err));
+              if (DBG_FILTER)
+                log_debug ("gcry_cipher_checktag failed (1): %s\n",
+                           gpg_strerror (err));
               /* Return Bad Signature like we do with MDC encryption. */
               if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
                 err = gpg_error (GPG_ERR_BAD_SIGNATURE);
@@ -714,7 +722,8 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
       err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, n, NULL, 0);
       if (err)
         {
-          log_debug ("gcry_cipher_decrypt failed (2): %s\n",gpg_strerror (err));
+          log_error ("gcry_cipher_decrypt failed (2): %s\n",
+                     gpg_strerror (err));
           goto leave;
         }
       dfx->chunklen += n;
@@ -723,14 +732,15 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
       if (dfx->eof_seen)
         {
           /* log_printhex (buf+off, n, "buf+off:"); */
-          log_debug ("eof seen: chunklen=%ju total=%ju off=%zu n=%zu\n",
-                     (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, off, n);
+          if (DBG_FILTER)
+            log_debug ("eof seen: chunklen=%ju total=%ju off=%zu n=%zu\n",
+                       (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, off, n);
 
           log_assert (dfx->defer_filled);
           err = gcry_cipher_checktag (dfx->cipher_hd, dfx->defer, 16);
           if (err)
             {
-              log_debug ("gcry_cipher_checktag failed (2): %s\n",
+              log_error ("gcry_cipher_checktag failed (2): %s\n",
                          gpg_strerror (err));
               /* Return Bad Signature like we do with MDC encryption. */
               if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
@@ -751,15 +761,16 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
           err = gcry_cipher_decrypt (dfx->cipher_hd, buf, 0, NULL, 0);
           if (err)
             {
-              log_debug ("gcry_cipher_decrypt failed (final): %s\n",
+              log_error ("gcry_cipher_decrypt failed (final): %s\n",
                          gpg_strerror (err));
               goto leave;
             }
           err = gcry_cipher_checktag (dfx->cipher_hd, dfx->defer+16, 16);
           if (err)
             {
-              log_debug ("gcry_cipher_checktag failed (final): %s\n",
-                         gpg_strerror (err));
+              if (DBG_FILTER)
+                log_debug ("gcry_cipher_checktag failed (final): %s\n",
+                           gpg_strerror (err));
               /* Return Bad Signature like we do with MDC encryption. */
               if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
                 err = gpg_error (GPG_ERR_BAD_SIGNATURE);
@@ -767,7 +778,8 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
             }
 
           n += off;
-          log_debug ("eof seen: returning %zu\n", n);
+          if (DBG_FILTER)
+            log_debug ("eof seen: returning %zu\n", n);
           /* log_printhex (buf, n, "buf:"); */
         }
       else
diff --git a/g10/gpg.c b/g10/gpg.c
index 2ae3e8a..283de20 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -105,6 +105,7 @@ enum cmd_and_opt_values
     oBatch	  = 500,
     oMaxOutput,
     oInputSizeHint,
+    oChunkSize,
     oSigNotation,
     oCertNotation,
     oShowNotation,
@@ -596,6 +597,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
   ARGPARSE_p_u (oMaxOutput, "max-output", "@"),
   ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"),
+  ARGPARSE_s_i (oChunkSize, "chunk-size", "@"),
 
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
   ARGPARSE_s_n (oQuiet,	  "quiet",   "@"),
@@ -1016,6 +1018,18 @@ build_list_cipher_algo_name (int algo)
 }
 
 static int
+build_list_aead_test_algo (int algo)
+{
+  return openpgp_aead_test_algo (algo);
+}
+
+static const char *
+build_list_aead_algo_name (int algo)
+{
+  return openpgp_aead_algo_name (algo);
+}
+
+static int
 build_list_md_test_algo (int algo)
 {
   /* By default we do not accept MD5 based signatures.  To avoid
@@ -1036,7 +1050,7 @@ build_list_md_algo_name (int algo)
 static const char *
 my_strusage( int level )
 {
-  static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry;
+  static char *digests, *pubkeys, *ciphers, *zips, *aeads, *ver_gcry;
   const char *p;
 
     switch( level ) {
@@ -1096,13 +1110,20 @@ my_strusage( int level )
 	p = ciphers;
 	break;
       case 36:
+	if (!aeads)
+          aeads = build_list ("AEAD: ", 'A',
+                              build_list_aead_algo_name,
+                              build_list_aead_test_algo);
+	p = aeads;
+	break;
+      case 37:
 	if( !digests )
 	    digests = build_list(_("Hash: "), 'H',
                                  build_list_md_algo_name,
                                  build_list_md_test_algo );
 	p = digests;
 	break;
-      case 37:
+      case 38:
 	if( !zips )
 	    zips = build_list(_("Compression: "),'Z',
                               compress_algo_to_string,
@@ -1123,6 +1144,7 @@ build_list (const char *text, char letter,
   membuf_t mb;
   int indent;
   int i, j, len;
+  int limit;
   const char *s;
   char *string;
 
@@ -1133,7 +1155,8 @@ build_list (const char *text, char letter,
   len = 0;
   init_membuf (&mb, 512);
 
-  for (i=0; i <= 110; i++ )
+  limit = (letter == 'A')? 4 : 110;
+  for (i=0; i <= limit; i++ )
     {
       if (!chkf (i) && (s = mapf (i)))
         {
@@ -2648,6 +2671,10 @@ main (int argc, char **argv)
             opt.input_size_hint = string_to_u64 (pargs.r.ret_str);
             break;
 
+          case oChunkSize:
+            opt.chunk_size = pargs.r.ret_int;
+            break;
+
 	  case oQuiet: opt.quiet = 1; break;
 	  case oNoTTY: tty_no_terminal(1); break;
 	  case oDryRun: opt.dry_run = 1; break;
@@ -3836,6 +3863,21 @@ main (int argc, char **argv)
        keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP))
       log_error(_("invalid personal compress preferences\n"));
 
+    /* Check chunk size.  Please fix also the man page if you chnage
+     * the default.  The limits are given by the specs.  */
+    if (!opt.chunk_size)
+      opt.chunk_size = 30; /* Default to 1 GiB chunks.  */
+    else if (opt.chunk_size < 6)
+      {
+        opt.chunk_size = 6;
+        log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
+      }
+    else if (opt.chunk_size > 62)
+      {
+        opt.chunk_size = 62;
+        log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
+      }
+
     /* We don't support all possible commands with multifile yet */
     if(multifile)
       {
diff --git a/g10/main.h b/g10/main.h
index a02c574..2f7c159 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -41,7 +41,11 @@
 # define DEFAULT_CIPHER_ALGO     CIPHER_ALGO_3DES
 #endif
 
-#define DEFAULT_AEAD_ALGO  AEAD_ALGO_EAX
+#if GCRYPT_VERSION_NUMBER < 0x019000
+# define DEFAULT_AEAD_ALGO  AEAD_ALGO_OCB
+#else
+# define DEFAULT_AEAD_ALGO  AEAD_ALGO_EAX
+#endif
 
 #define DEFAULT_DIGEST_ALGO     ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1)
 #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1
diff --git a/g10/misc.c b/g10/misc.c
index 36d3bdc..8c54793 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -591,11 +591,23 @@ openpgp_cipher_algo_name (cipher_algo_t algo)
 gpg_error_t
 openpgp_aead_test_algo (aead_algo_t algo)
 {
+  /* FIXME: We currently have no easy way to test whether libgcrypt
+   * implements a mode.  The only way we can do this is to open a
+   * cipher context with that mode and close it immediately.  That is
+   * a bit costly.  So we look at the libgcrypt version and assume
+   * nothing has been patched out.  */
   switch (algo)
     {
     case AEAD_ALGO_NONE:
       break;
+
     case AEAD_ALGO_EAX:
+#if GCRYPT_VERSION_NUMBER < 0x010900
+      break;
+#else
+      return 0;
+#endif
+
     case AEAD_ALGO_OCB:
       return 0;
     }
diff --git a/g10/options.h b/g10/options.h
index 36bea69..471aee7 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -62,6 +62,9 @@ struct
    * progress info and to decide on how to allocate buffers.  */
   uint64_t input_size_hint;
 
+  /* The AEAD chunk size expressed as a power of 2.  */
+  int chunk_size;
+
   int dry_run;
   int autostart;
   int list_only;
@@ -319,7 +322,6 @@ struct {
 #define DBG_TRUST  (opt.debug & DBG_TRUST_VALUE)
 #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
 #define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
-#define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
 #define DBG_CLOCK   (opt.debug & DBG_CLOCK_VALUE)
 #define DBG_LOOKUP  (opt.debug & DBG_LOOKUP_VALUE)
 #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)

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

Summary of changes:
 doc/gpg.texi       |  56 ++++++-
 g10/cipher-aead.c  |  81 ++++++----
 g10/decrypt-data.c | 461 ++++++++++++++++++++++++++++-------------------------
 g10/gpg.c          |  48 +++++-
 g10/main.h         |   6 +-
 g10/misc.c         |  12 ++
 g10/options.h      |   4 +-
 7 files changed, 407 insertions(+), 261 deletions(-)


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




More information about the Gnupg-commits mailing list