[git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-377-gb6d2a25

by Werner Koch cvs at cvs.gnupg.org
Tue Apr 12 11:15:56 CEST 2016


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 crypto library".

The branch, master has been updated
       via  b6d2a25a275a35ec4dbd53ecaa9ea0ed7aa99c7b (commit)
      from  ee7e1a0e835f8ffcfbcba2a44abab8632db8fed5 (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 b6d2a25a275a35ec4dbd53ecaa9ea0ed7aa99c7b
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Apr 12 11:11:35 2016 +0200

    cipher: Buffer data from gcry_cipher_authenticate in OCB mode.
    
    * cipher/cipher-internal.h (gcry_cipher_handle): Add fields
    aad_leftover and aad_nleftover to u_mode.ocb.
    * cipher/cipher-ocb.c (_gcry_cipher_ocb_set_nonce): Clear
    aad_nleftover.
    (_gcry_cipher_ocb_authenticate): Add buffering and facor some code out
    to ...
    (ocb_aad_finalize): new.
    (compute_tag_if_needed): Call new function.
    * tests/basic.c (check_ocb_cipher_splitaad): New.
    (check_ocb_cipher): Call new function.
    (main): Also call check_cipher_modes with --ciper-modes.
    --
    
    It is more convenient to not require full blocks for
    gcry_cipher_authenticate.  Other modes than OCB do this as well.
    
    Note that the size of the context structure is not increased because
    other modes require more context data.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index 80e7c09..9fd1d91 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -274,10 +274,16 @@ struct gcry_cipher_handle
          checksum of the data.  */
       unsigned char aad_sum[OCB_BLOCK_LEN];
 
+      /* A buffer to store AAD data not yet processed.  */
+      unsigned char aad_leftover[OCB_BLOCK_LEN];
+
       /* Number of data/aad blocks processed so far.  */
       u64 data_nblocks;
       u64 aad_nblocks;
 
+      /* Number of valid bytes in AAD_LEFTOVER.  */
+      unsigned char aad_nleftover;
+
       /* Length of the tag.  Fixed for now but may eventually be
          specified using a set of gcry_cipher_flags.  */
       unsigned char taglen;
diff --git a/cipher/cipher-ocb.c b/cipher/cipher-ocb.c
index 6db1db3..92260d2 100644
--- a/cipher/cipher-ocb.c
+++ b/cipher/cipher-ocb.c
@@ -1,5 +1,5 @@
 /* cipher-ocb.c -  OCB cipher mode
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -211,6 +211,7 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
   c->marks.finalize = 0;
   c->u_mode.ocb.data_nblocks = 0;
   c->u_mode.ocb.aad_nblocks = 0;
+  c->u_mode.ocb.aad_nleftover = 0;
   c->u_mode.ocb.data_finalized = 0;
   c->u_mode.ocb.aad_finalized = 0;
 
@@ -235,10 +236,7 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
 
 /* Process additional authentication data.  This implementation allows
    to add additional authentication data at any time before the final
-   gcry_cipher_gettag.  The size of the data provided in
-   (ABUF,ABUFLEN) must be a multiple of the blocksize.  If a
-   non-multiple of the blocksize is used no further data may be passed
-   to this function.  */
+   gcry_cipher_gettag.  */
 gcry_err_code_t
 _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
                                size_t abuflen)
@@ -254,6 +252,32 @@ _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
   /* Check correct usage and arguments.  */
   if (c->spec->blocksize != OCB_BLOCK_LEN)
     return GPG_ERR_CIPHER_ALGO;
+
+  /* Process remaining data from the last call first.  */
+  if (c->u_mode.ocb.aad_nleftover)
+    {
+      for (; abuflen && c->u_mode.ocb.aad_nleftover < OCB_BLOCK_LEN;
+           abuf++, abuflen--)
+        c->u_mode.ocb.aad_leftover[c->u_mode.ocb.aad_nleftover++] = *abuf;
+
+      if (c->u_mode.ocb.aad_nleftover == OCB_BLOCK_LEN)
+        {
+          c->u_mode.ocb.aad_nblocks++;
+
+          /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+          buf_xor_1 (c->u_mode.ocb.aad_offset,
+                     ocb_get_l (c, l_tmp, c->u_mode.ocb.aad_nblocks),
+                     OCB_BLOCK_LEN);
+          /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
+          buf_xor (l_tmp, c->u_mode.ocb.aad_offset,
+                   c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN);
+          c->spec->encrypt (&c->context.c, l_tmp, l_tmp);
+          buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
+
+          c->u_mode.ocb.aad_nleftover = 0;
+        }
+    }
+
   if (!abuflen)
     return 0;
 
@@ -291,31 +315,56 @@ _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
       abuflen -= OCB_BLOCK_LEN;
     }
 
-  /* Hash final partial block.  Note that we expect ABUFLEN to be
-     shorter than OCB_BLOCK_LEN.  */
-  if (abuflen)
+  /* Store away the remaining data.  */
+  for (; abuflen && c->u_mode.ocb.aad_nleftover < OCB_BLOCK_LEN;
+       abuf++, abuflen--)
+    c->u_mode.ocb.aad_leftover[c->u_mode.ocb.aad_nleftover++] = *abuf;
+  gcry_assert (!abuflen);
+
+  return 0;
+}
+
+
+/* Hash final partial AAD block.  */
+static void
+ocb_aad_finalize (gcry_cipher_hd_t c)
+{
+  unsigned char l_tmp[OCB_BLOCK_LEN];
+
+  /* Check that a nonce and thus a key has been set and that we have
+     not yet computed the tag.  We also skip this if the aad has been
+     finalized.  */
+  if (!c->marks.iv || c->marks.tag || c->u_mode.ocb.aad_finalized)
+    return;
+  if (c->spec->blocksize != OCB_BLOCK_LEN)
+    return;  /* Ooops.  */
+
+  /* Hash final partial block if any.  */
+  if (c->u_mode.ocb.aad_nleftover)
     {
       /* Offset_* = Offset_m xor L_*  */
       buf_xor_1 (c->u_mode.ocb.aad_offset,
                  c->u_mode.ocb.L_star, OCB_BLOCK_LEN);
       /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_*  */
-      buf_cpy (l_tmp, abuf, abuflen);
-      memset (l_tmp + abuflen, 0, OCB_BLOCK_LEN - abuflen);
-      l_tmp[abuflen] = 0x80;
+      buf_cpy (l_tmp, c->u_mode.ocb.aad_leftover, c->u_mode.ocb.aad_nleftover);
+      memset (l_tmp + c->u_mode.ocb.aad_nleftover, 0,
+              OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover);
+      l_tmp[c->u_mode.ocb.aad_nleftover] = 0x80;
       buf_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN);
       /* Sum = Sum_m xor ENCIPHER(K, CipherInput)  */
       c->spec->encrypt (&c->context.c, l_tmp, l_tmp);
       buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
 
-      /* Mark AAD as finalized to avoid accidentally calling this
-         function again after a non-full block has been processed.  */
-      c->u_mode.ocb.aad_finalized = 1;
+      c->u_mode.ocb.aad_nleftover = 0;
     }
 
-  return 0;
+  /* Mark AAD as finalized so that gcry_cipher_ocb_authenticate can
+   * return an erro when called again.  */
+  c->u_mode.ocb.aad_finalized = 1;
 }
 
 
+
 /* Checksumming for encrypt and decrypt.  */
 static void
 ocb_checksum (unsigned char *chksum, const unsigned char *plainbuf,
@@ -507,6 +556,7 @@ compute_tag_if_needed (gcry_cipher_hd_t c)
 {
   if (!c->marks.tag)
     {
+      ocb_aad_finalize (c);
       buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, OCB_BLOCK_LEN);
       c->marks.tag = 1;
     }
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index c710765..a78c5fd 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -1883,7 +1883,7 @@ the end of the input data. This is done with:
 Set a flag in the context to tell the encrypt and decrypt functions
 that their next call will provide the last chunk of data.  Only the
 first call to this function has an effect and only for modes which
-support it.  Checking the error in in general not necessary.  This is
+support it.  Checking the error is in general not necessary.  This is
 implemented as a macro.
 @end deftypefun
 
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index c269621..bd25d1b 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1065,7 +1065,7 @@ gcry_error_t gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag,
                                                      (oid), 0);
 
 /* Indicate to the encrypt and decrypt functions that the next call
-   provides the final data.  Only used with some modes. e */
+   provides the final data.  Only used with some modes.  */
 #define gcry_cipher_final(a) \
             gcry_cipher_ctl ((a), GCRYCTL_FINALIZE, NULL, 0)
 
diff --git a/tests/basic.c b/tests/basic.c
index 1a7d3cb..4940f6a 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -3596,6 +3596,236 @@ check_ocb_cipher_largebuf (int algo, int keylen, const char *tagexpect)
 
 
 static void
+check_ocb_cipher_splitaad (void)
+{
+  const char t_nonce[] = ("BBAA9988776655443322110D");
+  const char t_plain[] = ("000102030405060708090A0B0C0D0E0F1011121314151617"
+                          "18191A1B1C1D1E1F2021222324252627");
+  const char t_ciph[]  = ("D5CA91748410C1751FF8A2F618255B68A0A12E093FF45460"
+                          "6E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483"
+                          "A7035490C5769E60");
+  struct {
+    const char *aad0;
+    const char *aad1;
+    const char *aad2;
+    const char *aad3;
+  } tv[] = {
+    {
+      "000102030405060708090A0B0C0D0E0F"
+      "101112131415161718191A1B1C1D1E1F2021222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "2021222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "1011121314151617",
+      "18191A1B1C1D1E1F",
+      "2021222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "20",
+      "21222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "2021",
+      "222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "202122",
+      "2324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "20212223",
+      "24252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "2021222324",
+      "252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "202122232425",
+      "2627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "101112131415161718191A1B1C1D1E1F",
+      "20212223242526"
+      "27"
+    },
+    {
+      "000102030405060708090A0B0C0D0E0F",
+      "1011121314151617",
+      "18191A1B1C1D1E1F2021222324252627"
+    },
+    {
+      "00",
+      "0102030405060708090A0B0C0D0E0F",
+      "1011121314151617",
+      "18191A1B1C1D1E1F2021222324252627"
+    },
+    {
+      "0001",
+      "02030405060708090A0B0C0D0E0F",
+      "1011121314151617",
+      "18191A1B1C1D1E1F2021222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D",
+      "0E0F",
+      "1011121314151617",
+      "18191A1B1C1D1E1F2021222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E",
+      "0F",
+      "1011121314151617",
+      "18191A1B1C1D1E1F2021222324252627"
+    },
+    {
+      "000102030405060708090A0B0C0D0E",
+      "0F101112131415161718191A1B1C1D1E1F20212223242526",
+      "27"
+    }
+  };
+
+  gpg_error_t err = 0;
+  gcry_cipher_hd_t hde;
+  unsigned char out[MAX_DATA_LEN];
+  unsigned char tag[16];
+  int tidx;
+  char *key, *nonce, *ciph, *plain;
+  size_t keylen, noncelen, ciphlen, plainlen;
+  int i;
+
+  /* Convert to hex strings to binary.  */
+  key   = hex2buffer ("000102030405060708090A0B0C0D0E0F", &keylen);
+  nonce = hex2buffer (t_nonce, &noncelen);
+  plain = hex2buffer (t_plain, &plainlen);
+  ciph  = hex2buffer (t_ciph, &ciphlen);
+
+  /* Check that our test vectors are sane.  */
+  assert (plainlen <= sizeof out);
+  assert (16 <= ciphlen);
+  assert (16 <= sizeof tag);
+
+  for (tidx = 0; tidx < DIM (tv); tidx++)
+    {
+      char *aad[4];
+      size_t aadlen[4];
+
+      if (verbose)
+        fprintf (stderr, "    checking OCB aad split (tv %d)\n", tidx);
+
+      aad[0] = tv[tidx].aad0? hex2buffer (tv[tidx].aad0, aadlen+0) : NULL;
+      aad[1] = tv[tidx].aad1? hex2buffer (tv[tidx].aad1, aadlen+1) : NULL;
+      aad[2] = tv[tidx].aad2? hex2buffer (tv[tidx].aad2, aadlen+2) : NULL;
+      aad[3] = tv[tidx].aad3? hex2buffer (tv[tidx].aad3, aadlen+3) : NULL;
+
+      err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OCB, 0);
+      if (err)
+        {
+          fail ("cipher-ocb-splitadd, gcry_cipher_open failed: %s\n",
+                gpg_strerror (err));
+          return;
+        }
+
+      err = gcry_cipher_setkey (hde, key, keylen);
+      if (err)
+        {
+          fail ("cipher-ocb-splitaad, gcry_cipher_setkey failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          return;
+        }
+
+      err = gcry_cipher_setiv (hde, nonce, noncelen);
+      if (err)
+        {
+          fail ("cipher-ocb-splitaad, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          return;
+        }
+
+      for (i=0; i < DIM (aad); i++)
+        {
+          if (!aad[i])
+            continue;
+          err = gcry_cipher_authenticate (hde, aad[i], aadlen[i]);
+          if (err)
+            {
+              fail ("cipher-ocb-splitaad,"
+                    " gcry_cipher_authenticate failed (tv=%d,i=%d): %s\n",
+                    tidx, i, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              return;
+            }
+        }
+
+      err = gcry_cipher_final (hde);
+      if (!err)
+        err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, plain, plainlen);
+      if (err)
+        {
+          fail ("cipher-ocb-splitaad, gcry_cipher_encrypt failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          return;
+        }
+
+      /* Check that the encrypt output matches the expected cipher
+         text without the tag (i.e. at the length of plaintext).  */
+      if (memcmp (ciph, out, plainlen))
+        {
+          mismatch (ciph, plainlen, out, plainlen);
+          fail ("cipher-ocb-splitaad, encrypt data mismatch\n");
+        }
+
+      /* Check that the tag matches TAGLEN bytes from the end of the
+         expected ciphertext.  */
+      err = gcry_cipher_gettag (hde, tag, 16);
+      if (err)
+        {
+          fail ("cipher-ocb-splitaad, gcry_cipher_gettag failed: %s\n",
+                gpg_strerror (err));
+        }
+      if (memcmp (ciph + ciphlen - 16, tag, 16))
+        {
+          mismatch (ciph + ciphlen - 16, 16, tag, 16);
+          fail ("cipher-ocb-splitaad, encrypt tag mismatch\n");
+        }
+
+
+      gcry_cipher_close (hde);
+      xfree (aad[0]);
+      xfree (aad[1]);
+      xfree (aad[2]);
+      xfree (aad[3]);
+    }
+
+  xfree (nonce);
+  xfree (ciph);
+  xfree (plain);
+  xfree (key);
+}
+
+
+static void
 check_ocb_cipher (void)
 {
   /* Check OCB cipher with separate destination and source buffers for
@@ -3636,6 +3866,9 @@ check_ocb_cipher (void)
   check_ocb_cipher_largebuf(GCRY_CIPHER_SERPENT256, 32,
 			    "\xe7\x8b\xe6\xd4\x2f\x7a\x36\x4c"
 			    "\xba\xee\x20\xe2\x68\xf4\xcb\xcc");
+
+  /* Check that the AAD data is correctly buffered.  */
+  check_ocb_cipher_splitaad ();
 }
 
 
@@ -9128,7 +9361,10 @@ main (int argc, char **argv)
       if (pubkey_only)
         check_pubkey ();
       else if (cipher_modes_only)
-        check_ciphers ();
+        {
+          check_ciphers ();
+          check_cipher_modes ();
+        }
       else if (!selftest_only)
         {
           check_ciphers ();

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

Summary of changes:
 cipher/cipher-internal.h |   6 ++
 cipher/cipher-ocb.c      |  80 +++++++++++++---
 doc/gcrypt.texi          |   2 +-
 src/gcrypt.h.in          |   2 +-
 tests/basic.c            | 238 ++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 310 insertions(+), 18 deletions(-)


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits




More information about the Gcrypt-devel mailing list