[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-381-gc43a8c0

by Werner Koch cvs at cvs.gnupg.org
Thu Nov 14 23:51:21 CET 2013


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  c43a8c0d81a711161f7a81b24ef7c33a1353eee0 (commit)
      from  7d91e99bcd30a463dd4faed014b8521a663d8316 (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 c43a8c0d81a711161f7a81b24ef7c33a1353eee0
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Nov 14 23:40:41 2013 +0100

    md: Fix hashing for data >= 256 GB
    
    * cipher/hash-common.h (gcry_md_block_ctx): Add "nblocks_high".
    * cipher/hash-common.c (_gcry_md_block_write): Bump NBLOCKS_HIGH.
    * cipher/md4.c (md4_init, md4_final): Take care of NBLOCKS_HIGH.
    * cipher/md5.c (md5_init, md5_final): Ditto.
    * cipher/rmd160.c (_gcry_rmd160_init, rmd160_final): Ditto.
    * cipher/sha1.c (sha1_init, sha1_final): Ditto.
    * cipher/sha256.c (sha256_init, sha224_init, sha256_final): Ditto.
    * cipher/sha512.c (sha512_init, sha384_init, sha512_final): Ditto.
    * cipher/tiger.c (do_init, tiger_final): Ditto.
    * cipher/whirlpool.c (whirlpool_final): Ditto.
    
    * cipher/md.c (gcry_md_algo_info): Add GCRYCTL_SELFTEST.
    (_gcry_md_selftest): Return "not implemented" as required.
    * tests/hashtest.c: New.
    * tests/genhashdata.c: New.
    * tests/Makefile.am (TESTS): Add hashtest.
    (noinst_PROGRAMS): Add genhashdata
    --
    
    Problem found by Denis Corbin and analyzed by Yuriy Kaminskiy.
    
    sha512 and whirlpool should not have this problem because they use 64
    bit types for counting the blocks. However, a similar fix has been
    employed to allow for really huge sizes - despite that it will be very
    hard to test them.
    
    The test vectors have been produced by sha{1,224,256}sum and the
    genhashdata tool.  A sequence of 'a' is used for them because a test
    using one million 'a' is commonly used for test vectors.  More test
    vectors are required.  Running the large tests needs to be done
    manual for now:
    
      ./hashtest --gigs 256
    
    tests all algorithms,
    
      ./hashtest --gigs 256 sha1 sha224 sha256
    
    only the given ones.  A configure option to include these test in the
    standard regression suite will be useful.  The tests will take looong.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/hash-common.c b/cipher/hash-common.c
index e318e7e..ffbc39e 100644
--- a/cipher/hash-common.c
+++ b/cipher/hash-common.c
@@ -115,7 +115,8 @@ _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen)
       _gcry_burn_stack (stack_burn);
       stack_burn = 0;
       hd->count = 0;
-      hd->nblocks++;
+      if (!++hd->nblocks)
+        hd->nblocks_high++;
     }
   if (!inbuf)
     return;
@@ -133,7 +134,8 @@ _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen)
     {
       stack_burn = hd->bwrite (hd, inbuf);
       hd->count = 0;
-      hd->nblocks++;
+      if (!++hd->nblocks)
+        hd->nblocks_high++;
       inlen -= hd->blocksize;
       inbuf += hd->blocksize;
     }
diff --git a/cipher/hash-common.h b/cipher/hash-common.h
index ce91da5..aa95365 100644
--- a/cipher/hash-common.h
+++ b/cipher/hash-common.h
@@ -45,6 +45,7 @@ typedef struct gcry_md_block_ctx
 {
     byte buf[MD_BLOCK_MAX_BLOCKSIZE];
     MD_NBLOCKS_TYPE nblocks;
+    MD_NBLOCKS_TYPE nblocks_high;
     int count;
     size_t blocksize;
     _gcry_md_block_write_t bwrite;
diff --git a/cipher/md.c b/cipher/md.c
index 5c66397..3bfa3bd 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1028,6 +1028,8 @@ md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen)
  *  GCRYCTL_GET_ASNOID:
  *	Return the ASNOID of the algorithm in buffer. if buffer is NULL, only
  *	the required length is returned.
+ *  GCRYCTL_SELFTEST
+ *      Helper for the regression tests - shall not be used by applications.
  *
  * Note:  Because this function is in most cases used to return an
  * integer value, we can make it easier for the caller to just look at
@@ -1076,6 +1078,12 @@ gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes)
         }
       break;
 
+    case GCRYCTL_SELFTEST:
+      /* Helper function for the regression tests.  */
+      err = gpg_err_code (_gcry_md_selftest (algo, nbytes? (int)*nbytes : 0,
+                                             NULL));
+      break;
+
     default:
       err = GPG_ERR_INV_OP;
       break;
@@ -1227,7 +1235,7 @@ _gcry_md_selftest (int algo, int extended, selftest_report_func_t report)
     ec = spec->selftest (algo, extended, report);
   else
     {
-      ec = GPG_ERR_DIGEST_ALGO;
+      ec = spec->selftest? GPG_ERR_DIGEST_ALGO : GPG_ERR_NOT_IMPLEMENTED;
       if (report)
         report ("digest", algo, "module",
                 (spec && !spec->flags.disabled)?
diff --git a/cipher/md4.c b/cipher/md4.c
index ab32b14..b9a1a95 100644
--- a/cipher/md4.c
+++ b/cipher/md4.c
@@ -79,6 +79,7 @@ md4_init( void *context )
   ctx->D = 0x10325476;
 
   ctx->bctx.nblocks = 0;
+  ctx->bctx.nblocks_high = 0;
   ctx->bctx.count = 0;
   ctx->bctx.blocksize = 64;
   ctx->bctx.bwrite = transform;
@@ -191,16 +192,21 @@ static void
 md4_final( void *context )
 {
   MD4_CONTEXT *hd = context;
-  u32 t, msb, lsb;
+  u32 t, th, msb, lsb;
   byte *p;
   unsigned int burn;
 
   _gcry_md_block_write(hd, NULL, 0); /* flush */;
 
   t = hd->bctx.nblocks;
+  if (sizeof t == sizeof hd->bctx.nblocks)
+    th = hd->bctx.nblocks_high;
+  else
+    th = hd->bctx.nblocks >> 32;
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 26;
+  msb = (th << 6) | (t >> 26);
   /* add the count */
   t = lsb;
   if( (lsb += hd->bctx.count) < t )
diff --git a/cipher/md5.c b/cipher/md5.c
index 1b6ad48..79b6e87 100644
--- a/cipher/md5.c
+++ b/cipher/md5.c
@@ -63,6 +63,7 @@ md5_init( void *context )
   ctx->D = 0x10325476;
 
   ctx->bctx.nblocks = 0;
+  ctx->bctx.nblocks_high = 0;
   ctx->bctx.count = 0;
   ctx->bctx.blocksize = 64;
   ctx->bctx.bwrite = transform;
@@ -215,16 +216,21 @@ static void
 md5_final( void *context)
 {
   MD5_CONTEXT *hd = context;
-  u32 t, msb, lsb;
+  u32 t, th, msb, lsb;
   byte *p;
   unsigned int burn;
 
   _gcry_md_block_write(hd, NULL, 0); /* flush */;
 
   t = hd->bctx.nblocks;
+  if (sizeof t == sizeof hd->bctx.nblocks)
+    th = hd->bctx.nblocks_high;
+  else
+    th = hd->bctx.nblocks >> 32;
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 26;
+  msb = (th << 6) | (t >> 26);
   /* add the count */
   t = lsb;
   if( (lsb += hd->bctx.count) < t )
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
index f7430ea..a6d9a80 100644
--- a/cipher/rmd160.c
+++ b/cipher/rmd160.c
@@ -155,6 +155,7 @@ _gcry_rmd160_init (void *context)
   hd->h4 = 0xC3D2E1F0;
 
   hd->bctx.nblocks = 0;
+  hd->bctx.nblocks_high = 0;
   hd->bctx.count = 0;
   hd->bctx.blocksize = 64;
   hd->bctx.bwrite = transform;
@@ -414,16 +415,21 @@ static void
 rmd160_final( void *context )
 {
   RMD160_CONTEXT *hd = context;
-  u32 t, msb, lsb;
+  u32 t, th, msb, lsb;
   byte *p;
   unsigned int burn;
 
   _gcry_md_block_write(hd, NULL, 0); /* flush */;
 
   t = hd->bctx.nblocks;
+  if (sizeof t == sizeof hd->bctx.nblocks)
+    th = hd->bctx.nblocks_high;
+  else
+    th = hd->bctx.nblocks >> 32;
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 26;
+  msb = (th << 6) | (t >> 26);
   /* add the count */
   t = lsb;
   if( (lsb += hd->bctx.count) < t )
diff --git a/cipher/sha1.c b/cipher/sha1.c
index 95591eb..025b3ab 100644
--- a/cipher/sha1.c
+++ b/cipher/sha1.c
@@ -74,6 +74,7 @@ sha1_init (void *context)
   hd->h4 = 0xc3d2e1f0;
 
   hd->bctx.nblocks = 0;
+  hd->bctx.nblocks_high = 0;
   hd->bctx.count = 0;
   hd->bctx.blocksize = 64;
   hd->bctx.bwrite = transform;
@@ -227,16 +228,21 @@ static void
 sha1_final(void *context)
 {
   SHA1_CONTEXT *hd = context;
-  u32 t, msb, lsb;
+  u32 t, th, msb, lsb;
   unsigned char *p;
   unsigned int burn;
 
   _gcry_md_block_write (hd, NULL, 0); /* flush */;
 
   t = hd->bctx.nblocks;
+  if (sizeof t == sizeof hd->bctx.nblocks)
+    th = hd->bctx.nblocks_high;
+  else
+    th = hd->bctx.nblocks >> 32;
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 26;
+  msb = (th << 6) | (t >> 26);
   /* add the count */
   t = lsb;
   if( (lsb += hd->bctx.count) < t )
diff --git a/cipher/sha256.c b/cipher/sha256.c
index d3917e4..bd5a412 100644
--- a/cipher/sha256.c
+++ b/cipher/sha256.c
@@ -70,6 +70,7 @@ sha256_init (void *context)
   hd->h7 = 0x5be0cd19;
 
   hd->bctx.nblocks = 0;
+  hd->bctx.nblocks_high = 0;
   hd->bctx.count = 0;
   hd->bctx.blocksize = 64;
   hd->bctx.bwrite = transform;
@@ -91,6 +92,7 @@ sha224_init (void *context)
   hd->h7 = 0xbefa4fa4;
 
   hd->bctx.nblocks = 0;
+  hd->bctx.nblocks_high = 0;
   hd->bctx.count = 0;
   hd->bctx.blocksize = 64;
   hd->bctx.bwrite = transform;
@@ -261,16 +263,21 @@ static void
 sha256_final(void *context)
 {
   SHA256_CONTEXT *hd = context;
-  u32 t, msb, lsb;
+  u32 t, th, msb, lsb;
   byte *p;
   unsigned int burn;
 
   _gcry_md_block_write (hd, NULL, 0); /* flush */;
 
   t = hd->bctx.nblocks;
+  if (sizeof t == sizeof hd->bctx.nblocks)
+    th = hd->bctx.nblocks_high;
+  else
+    th = hd->bctx.nblocks >> 32;
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 26;
+  msb = (th << 6) | (t >> 26);
   /* add the count */
   t = lsb;
   if ((lsb += hd->bctx.count) < t)
diff --git a/cipher/sha512.c b/cipher/sha512.c
index 97fb203..14608dc 100644
--- a/cipher/sha512.c
+++ b/cipher/sha512.c
@@ -97,6 +97,7 @@ sha512_init (void *context)
   hd->h7 = U64_C(0x5be0cd19137e2179);
 
   ctx->bctx.nblocks = 0;
+  ctx->bctx.nblocks_high = 0;
   ctx->bctx.count = 0;
   ctx->bctx.blocksize = 128;
   ctx->bctx.bwrite = transform;
@@ -122,6 +123,7 @@ sha384_init (void *context)
   hd->h7 = U64_C(0x47b5481dbefa4fa4);
 
   ctx->bctx.nblocks = 0;
+  ctx->bctx.nblocks_high = 0;
   ctx->bctx.count = 0;
   ctx->bctx.blocksize = 128;
   ctx->bctx.bwrite = transform;
@@ -515,15 +517,20 @@ sha512_final (void *context)
 {
   SHA512_CONTEXT *hd = context;
   unsigned int stack_burn_depth;
-  u64 t, msb, lsb;
+  u64 t, th, msb, lsb;
   byte *p;
 
   _gcry_md_block_write (context, NULL, 0); /* flush */ ;
 
   t = hd->bctx.nblocks;
+  /* if (sizeof t == sizeof hd->bctx.nblocks) */
+  th = hd->bctx.nblocks_high;
+  /* else */
+  /*   th = hd->bctx.nblocks >> 64; In case we ever use u128  */
+
   /* multiply by 128 to make a byte count */
   lsb = t << 7;
-  msb = t >> 57;
+  msb = (th << 7) | (t >> 57);
   /* add the count */
   t = lsb;
   if ((lsb += hd->bctx.count) < t)
diff --git a/cipher/tiger.c b/cipher/tiger.c
index a70a3f2..9b8d0ef 100644
--- a/cipher/tiger.c
+++ b/cipher/tiger.c
@@ -602,6 +602,7 @@ do_init (void *context, int variant)
   hd->c = 0xf096a5b4c3b2e187LL;
 
   hd->bctx.nblocks = 0;
+  hd->bctx.nblocks_high = 0;
   hd->bctx.count = 0;
   hd->bctx.blocksize = 64;
   hd->bctx.bwrite = transform;
@@ -735,7 +736,7 @@ static void
 tiger_final( void *context )
 {
   TIGER_CONTEXT *hd = context;
-  u32 t, msb, lsb;
+  u32 t, th, msb, lsb;
   byte *p;
   unsigned int burn;
   byte pad = hd->variant == 2? 0x80 : 0x01;
@@ -743,9 +744,14 @@ tiger_final( void *context )
   _gcry_md_block_write(hd, NULL, 0); /* flush */;
 
   t = hd->bctx.nblocks;
+  if (sizeof t == sizeof hd->bctx.nblocks)
+    th = hd->bctx.nblocks_high;
+  else
+    th = hd->bctx.nblocks >> 32;
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 26;
+  msb = (th << 6) | (t >> 26);
   /* add the count */
   t = lsb;
   if( (lsb += hd->bctx.count) < t )
diff --git a/cipher/whirlpool.c b/cipher/whirlpool.c
index 168c38f..e562781 100644
--- a/cipher/whirlpool.c
+++ b/cipher/whirlpool.c
@@ -1296,13 +1296,18 @@ whirlpool_final (void *ctx)
 {
   whirlpool_context_t *context = ctx;
   unsigned int i;
-  u64 t, lsb, msb;
+  u64 t, th, lsb, msb;
   unsigned char *length;
 
   t = context->bctx.nblocks;
+  /* if (sizeof t == sizeof context->bctx.nblocks) */
+  th = context->bctx.nblocks_high;
+  /* else */
+  /*   th = context->bctx.nblocks >> 64; In case we ever use u128 */
+
   /* multiply by 64 to make a byte count */
   lsb = t << 6;
-  msb = t >> 58;
+  msb = (th << 6) | (t >> 58);
   /* add the count */
   t = lsb;
   if ((lsb += context->bctx.count) < t)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c9ba5f4..87283f9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,7 +20,7 @@
 
 TESTS = version mpitests tsexp t-convert \
 	t-mpi-bit t-mpi-point curves \
-	prime basic keygen pubkey hmac t-kdf keygrip \
+	prime basic keygen pubkey hmac hashtest t-kdf keygrip \
 	fips186-dsa aeswrap pkcs1v2 random dsa-rfc6979 t-ed25519
 
 
@@ -36,7 +36,7 @@ AM_CFLAGS = $(GPG_ERROR_CFLAGS)
 LDADD = ../src/libgcrypt.la $(DL_LIBS) ../compat/libcompat.la $(GPG_ERROR_LIBS)
 
 EXTRA_PROGRAMS = testapi pkbench
-noinst_PROGRAMS = $(TESTS) fipsdrv rsacvt
+noinst_PROGRAMS = $(TESTS) fipsdrv rsacvt genhashdata
 
 EXTRA_DIST = README rsa-16k.key cavs_tests.sh cavs_driver.pl \
 	     pkcs1v2-oaep.h pkcs1v2-pss.h pkcs1v2-v15c.h pkcs1v2-v15s.h \
diff --git a/tests/genhashdata.c b/tests/genhashdata.c
new file mode 100644
index 0000000..8777f9c
--- /dev/null
+++ b/tests/genhashdata.c
@@ -0,0 +1,158 @@
+/* genhashdata.c - Create data for hash tests
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Results:
+
+$  for i in -64 -1 0 1 64; do ./genhashdata --gigs 256 --bytes $i|sha1sum;done
+92fc51850c7b750e6e774b75f294f6979d4059f0  -
+4bddeeb4c08683f02d4944d93dbcb02ebab50134  -
+71b923afde1c8c040884c723a2e3335b333e64c6  -
+2d99f9b5b86e9c9c937104f4242bd6b8bc0927ef  -
+a60dabe8d749f798b7ec3a684cc3eab487451482  -
+
+$ for i in -64 -1 0 1 64; do ./genhashdata --gigs 256 --bytes $i|sha224sum;done
+b5672b54d2480a5688a2dc727a1ad4db7a81ef31ce8999e0bbaeffdc  -
+814ea7159473e6ffc1c64b90026a542e13ac6980f7f3ca3c4582a9b8  -
+9ec0e1829455db8650ec7a8b06912196f97a7358bc3a73c79911cd4e  -
+e578d5d523320876565bbbc892511a485427caee6dd754d57e3e58c2  -
+ff0464df248cd298b63765bc4f87f21e25c93c657fdf3656d3c878e5  -
+
+$ for i in -64 -1 0 1 64; do ./genhashdata --gigs 256 --bytes $i|sha256sum;done
+87a9828d3de78d55d252341db2a622908c4e0ceaee9961ecf9768700fc799ec8  -
+823bf95f64ef04a4a77579c38760b1d401b56bf3a8e664bdf56ca15afb468a03  -
+2d0723878cb2c3d5c59dfad910cdb857f4430a6ba2a7d687938d7a20e63dde47  -
+5a2e21b1e79cd866acf53a2a18ca76bd4e02c4b01bf4627354171824c812d95f  -
+34444808af8e9d995e67f9e155ed94bf55f195a51dc1d8a989e6bcf95511c8a2  -
+
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define PGM "genhashdata"
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr ;
+
+  fflush (stdout);
+  fprintf (stderr, "%s: ", PGM);
+  va_start (arg_ptr, format ) ;
+  vfprintf (stderr, format, arg_ptr );
+  va_end(arg_ptr);
+  if (*format && format[strlen(format)-1] != '\n')
+    putc ('\n', stderr);
+  exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  int gigs = 0;
+  int bytes = 0;
+  char pattern[1024];
+  int i, g;
+
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGM " [options]\n"
+                 "Options:\n"
+                 "  --gigs  N     Emit N GiB of test bytes\n"
+                 "  --bytes DIFF  Stop DIFF bytes earlier or later\n",
+                 stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--gigs"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              gigs = atoi (*argv);
+              argc--; argv++;
+            }
+        }
+      else if (!strcmp (*argv, "--bytes"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              bytes = atoi (*argv);
+              argc--; argv++;
+            }
+        }
+      else if (!strncmp (*argv, "--", 2))
+        die ("unknown option '%s'", *argv);
+    }
+
+  if (gigs < 0 || gigs > 1024*1024)
+    die ("value for --gigs must be in the range 0 to %d", 1024*1024);
+  if (bytes < -1024 || bytes > 1024)
+      die ("value for --bytes must be in the range -1024 to 1024");
+  if (sizeof pattern != 1024)
+    die ("internal error");
+
+  if (argc > 1)
+    die ("arguments are not expected");
+
+  memset (pattern, 'a', sizeof pattern);
+
+  for (g=0; g < gigs; g++)
+    {
+      if (g + 1 == gigs && bytes < 0)
+        {
+          for (i = 0; i < 1024*1023; i++)
+            if (fwrite (pattern, sizeof pattern, 1, stdout) != 1)
+              die ("writing to stdout failed: %s", strerror (errno));
+          for (i = 0; i < 1023; i++)
+            if (fwrite (pattern, sizeof pattern, 1, stdout) != 1)
+              die ("writing to stdout failed: %s", strerror (errno));
+          if (fwrite (pattern, sizeof pattern + bytes, 1, stdout) != 1)
+            die ("writing to stdout failed: %s", strerror (errno));
+        }
+      else
+        {
+          for (i = 0; i < 1024*1024; i++)
+            if (fwrite (pattern, sizeof pattern, 1, stdout) != 1)
+              die ("writing to stdout failed: %s", strerror (errno));
+        }
+    }
+  if (bytes > 0)
+    if (fwrite (pattern, bytes, 1, stdout) != 1)
+      die ("writing to stdout failed: %s", strerror (errno));
+  if (fflush (stdout))
+    die ("writing to stdout failed: %s", strerror (errno));
+
+  return 0;
+}
diff --git a/tests/hashtest.c b/tests/hashtest.c
new file mode 100644
index 0000000..15310d0
--- /dev/null
+++ b/tests/hashtest.c
@@ -0,0 +1,472 @@
+/* hashtest.c - Check the hash fucntions
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../src/gcrypt-int.h"
+
+#include "stopwatch.h"
+
+#define PGM "hashtest"
+
+#define my_isascii(c) (!((c) & 0x80))
+#define digitp(p)   (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a)                     \
+                      || (*(a) >= 'A' && *(a) <= 'F')  \
+                      || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+#define xmalloc(a)    gcry_xmalloc ((a))
+#define xcalloc(a,b)  gcry_xcalloc ((a),(b))
+#define xstrdup(a)    gcry_xstrdup ((a))
+#define xfree(a)      gcry_free ((a))
+#define pass()        do { ; } while (0)
+
+static int verbose;
+static int debug;
+static int error_count;
+static int missing_test_vectors;
+
+static struct {
+  int algo;
+  int gigs;
+  int bytes;
+  const char *hex;
+} testvectors[] = {
+  { GCRY_MD_SHA1, 256, -64, "92fc51850c7b750e6e774b75f294f6979d4059f0" },
+  { GCRY_MD_SHA1, 256,  -1, "4bddeeb4c08683f02d4944d93dbcb02ebab50134" },
+  { GCRY_MD_SHA1, 256,  -0, "71b923afde1c8c040884c723a2e3335b333e64c6" },
+  { GCRY_MD_SHA1, 256,   1, "2d99f9b5b86e9c9c937104f4242bd6b8bc0927ef" },
+  { GCRY_MD_SHA1, 256,  64, "a60dabe8d749f798b7ec3a684cc3eab487451482" },
+  { GCRY_MD_SHA224, 256, -64,
+    "b5672b54d2480a5688a2dc727a1ad4db7a81ef31ce8999e0bbaeffdc" },
+  { GCRY_MD_SHA224, 256,  -1,
+    "814ea7159473e6ffc1c64b90026a542e13ac6980f7f3ca3c4582a9b8" },
+  { GCRY_MD_SHA224, 256,   0,
+    "9ec0e1829455db8650ec7a8b06912196f97a7358bc3a73c79911cd4e" },
+  { GCRY_MD_SHA224, 256,   1,
+    "e578d5d523320876565bbbc892511a485427caee6dd754d57e3e58c2" },
+  { GCRY_MD_SHA224, 256,  64,
+    "ff0464df248cd298b63765bc4f87f21e25c93c657fdf3656d3c878e5" },
+  { GCRY_MD_SHA256, 256, -64,
+    "87a9828d3de78d55d252341db2a622908c4e0ceaee9961ecf9768700fc799ec8" },
+  { GCRY_MD_SHA256, 256,  -1,
+    "823bf95f64ef04a4a77579c38760b1d401b56bf3a8e664bdf56ca15afb468a03" },
+  { GCRY_MD_SHA256, 256,   0,
+    "2d0723878cb2c3d5c59dfad910cdb857f4430a6ba2a7d687938d7a20e63dde47" },
+  { GCRY_MD_SHA256, 256,   1,
+    "5a2e21b1e79cd866acf53a2a18ca76bd4e02c4b01bf4627354171824c812d95f" },
+  { GCRY_MD_SHA256, 256,  64,
+    "34444808af8e9d995e67f9e155ed94bf55f195a51dc1d8a989e6bcf95511c8a2" },
+  { 0 }
+};
+
+
+
+
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr ;
+
+  fflush (stdout);
+  fprintf (stderr, "%s: ", PGM);
+  va_start( arg_ptr, format ) ;
+  vfprintf (stderr, format, arg_ptr );
+  va_end(arg_ptr);
+  if (*format && format[strlen(format)-1] != '\n')
+    putc ('\n', stderr);
+  exit (1);
+}
+
+static void
+fail (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  fflush (stdout);
+  fprintf (stderr, "%s: ", PGM);
+  /* if (wherestr) */
+  /*   fprintf (stderr, "%s: ", wherestr); */
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  if (*format && format[strlen(format)-1] != '\n')
+    putc ('\n', stderr);
+  error_count++;
+  if (error_count >= 50)
+    die ("stopped after 50 errors.");
+}
+
+static void
+show (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  fprintf (stderr, "%s: ", PGM);
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  if (*format && format[strlen(format)-1] != '\n')
+    putc ('\n', stderr);
+  va_end (arg_ptr);
+}
+
+
+static void
+showhex (const void *buffer, size_t buflen, const char *format, ...)
+{
+  va_list arg_ptr;
+  const unsigned char *s;
+
+  fprintf (stderr, "%s: ", PGM);
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+
+  for (s=buffer; buflen; buflen--, s++)
+    fprintf (stderr, "%02x", *s);
+  putc ('\n', stderr);
+}
+
+
+static void
+show_note (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  if (!verbose && getenv ("srcdir"))
+    fputs ("      ", stderr);  /* To align above "PASS: ".  */
+  else
+    fprintf (stderr, "%s: ", PGM);
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  if (*format && format[strlen(format)-1] != '\n')
+    putc ('\n', stderr);
+  va_end (arg_ptr);
+}
+
+/* Convert STRING consisting of hex characters into its binary
+   representation and return it as an allocated buffer. The valid
+   length of the buffer is returned at R_LENGTH.  The string is
+   delimited by end of string.  The function returns NULL on
+   error.  */
+static void *
+hex2buffer (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = xmalloc (strlen(string)/2+1);
+  length = 0;
+  for (s=string; *s; s +=2 )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        return NULL;           /* Invalid hex digits. */
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+static void
+run_selftest (int algo)
+{
+  gpg_error_t err;
+  size_t n;
+
+  n = 1;
+  err = gcry_md_algo_info (algo, GCRYCTL_SELFTEST, NULL, &n);
+  if (err && gpg_err_code (err) != GPG_ERR_NOT_IMPLEMENTED)
+    fail ("extended selftest for %s (%d) failed: %s",
+          gcry_md_algo_name (algo), algo, gpg_strerror (err));
+  else if (err && verbose)
+    show ("extended selftest for %s (%d) not implemented",
+          gcry_md_algo_name (algo), algo);
+  else if (verbose)
+    show ("extended selftest for %s (%d) passed",
+          gcry_md_algo_name (algo), algo);
+}
+
+/* Compare DIGEST of length DIGESTLEN generated using ALGO and GIGS
+   plus BYTES with the test vector and print an error message if the
+   don't match.  Return 0 on match.  */
+static int
+cmp_digest (const unsigned char *digest, size_t digestlen,
+            int algo, int gigs, int bytes)
+{
+  int idx;
+  unsigned char *tv_digest;
+  size_t tv_digestlen = 0;
+
+  for (idx=0; testvectors[idx].algo; idx++)
+    {
+      if (testvectors[idx].algo == algo
+          && testvectors[idx].gigs == gigs
+          && testvectors[idx].bytes == bytes)
+        break;
+    }
+  if (!testvectors[idx].algo)
+    {
+      show ("%d GiB %+3d %-10s warning: %s",
+            gigs, bytes, gcry_md_algo_name (algo), "no test vector");
+      missing_test_vectors++;
+      return 1;
+    }
+
+  tv_digest = hex2buffer (testvectors[idx].hex, &tv_digestlen);
+  if (tv_digestlen != digestlen) /* Ooops.  */
+    {
+      fail ("%d GiB %+3d %-10s error: %s",
+            gigs, bytes, gcry_md_algo_name (algo), "digest length mismatch");
+      xfree (tv_digest);
+      return 1;
+    }
+  if (memcmp (tv_digest, digest, tv_digestlen))
+    {
+      fail ("%d GiB %+3d %-10s error: %s",
+            gigs, bytes, gcry_md_algo_name (algo), "mismatch");
+      xfree (tv_digest);
+      return 1;
+    }
+  xfree (tv_digest);
+
+  return 0;
+}
+
+
+static void
+run_longtest (int algo, int gigs)
+{
+  gpg_error_t err;
+  gcry_md_hd_t hd;
+  gcry_md_hd_t hd_pre = NULL;
+  gcry_md_hd_t hd_pre2 = NULL;
+  gcry_md_hd_t hd_post = NULL;
+  gcry_md_hd_t hd_post2 = NULL;
+  char pattern[1024];
+  int i, g;
+  const unsigned char *digest;
+  unsigned int digestlen;
+
+  memset (pattern, 'a', sizeof pattern);
+
+  err = gcry_md_open (&hd, algo, 0);
+  if (err)
+    {
+      fail ("gcry_md_open failed for %s (%d): %s",
+            gcry_md_algo_name (algo), algo, gpg_strerror (err));
+      return;
+    }
+
+  digestlen = gcry_md_get_algo_dlen (algo);
+
+
+  for (g=0; g < gigs; g++)
+    {
+      if (g == gigs - 1)
+        {
+          for (i = 0; i < 1024*1023; i++)
+            gcry_md_write (hd, pattern, sizeof pattern);
+          for (i = 0; i < 1023; i++)
+            gcry_md_write (hd, pattern, sizeof pattern);
+          err = gcry_md_copy (&hd_pre, hd);
+          if (!err)
+            err = gcry_md_copy (&hd_pre2, hd);
+          if (err)
+            die ("gcry_md_copy failed for %s (%d): %s",
+                 gcry_md_algo_name (algo), algo, gpg_strerror (err));
+          gcry_md_write (hd, pattern, sizeof pattern);
+        }
+      else
+        {
+          for (i = 0; i < 1024*1024; i++)
+            gcry_md_write (hd, pattern, sizeof pattern);
+        }
+      if (g && !(g % 16))
+        show_note ("%d GiB so far hashed with %s", g, gcry_md_algo_name (algo));
+    }
+  if (g >= 16)
+    show_note ("%d GiB hashed with %s", g, gcry_md_algo_name (algo));
+
+  err = gcry_md_copy (&hd_post, hd);
+  if (err)
+    die ("gcry_md_copy failed for %s (%d): %s",
+         gcry_md_algo_name (algo), algo, gpg_strerror (err));
+  err = gcry_md_copy (&hd_post2, hd);
+  if (err)
+    die ("gcry_md_copy failed for %s (%d): %s",
+         gcry_md_algo_name (algo), algo, gpg_strerror (err));
+
+  gcry_md_write (hd_pre2, pattern, sizeof pattern - 64);
+  gcry_md_write (hd_pre, pattern, sizeof pattern - 1);
+  gcry_md_write (hd_post, pattern, 1);
+  gcry_md_write (hd_post2, pattern, 64);
+
+  digest = gcry_md_read (hd_pre2, algo);
+  if (cmp_digest (digest, digestlen, algo, gigs, -64) || verbose)
+    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
+             gigs, -64, gcry_md_algo_name (algo));
+  digest = gcry_md_read (hd_pre, algo);
+  if (cmp_digest (digest, digestlen, algo, gigs, -1) || verbose)
+    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
+             gigs, -1, gcry_md_algo_name (algo));
+  digest = gcry_md_read (hd, algo);
+  if (cmp_digest (digest, digestlen, algo, gigs, 0) || verbose)
+    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
+             gigs, 0, gcry_md_algo_name (algo));
+  digest = gcry_md_read (hd_post, algo);
+  if (cmp_digest (digest, digestlen, algo, gigs, 1) || verbose)
+    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
+             gigs, 1, gcry_md_algo_name (algo));
+  digest = gcry_md_read (hd_post2, algo);
+  if (cmp_digest (digest, digestlen, algo, gigs, 64) || verbose)
+    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
+             gigs, 64, gcry_md_algo_name (algo));
+
+  gcry_md_close (hd);
+  gcry_md_close (hd_pre);
+  gcry_md_close (hd_pre2);
+  gcry_md_close (hd_post);
+  gcry_md_close (hd_post2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  int gigs = 0;
+  int algo = 0;
+  int idx;
+
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGM " [options] [algos]\n"
+                 "Options:\n"
+                 "  --verbose       print timings etc.\n"
+                 "  --debug         flyswatter\n"
+                 "  --gigs N        Run a test on N GiB\n",
+                 stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--gigs"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              gigs = atoi (*argv);
+              argc--; argv++;
+            }
+        }
+      else if (!strncmp (*argv, "--", 2))
+        die ("unknown option '%s'", *argv);
+    }
+
+  if (gigs < 0 || gigs > 1024*1024)
+    die ("value for --gigs must be in the range 0 to %d", 1024*1024);
+
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch\n");
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+  /* A quick check that all given algorithms are valid.  */
+  for (idx=0; idx < argc; idx++)
+    {
+      algo = gcry_md_map_name (argv[idx]);
+      if (!algo)
+        fail ("invalid algorithm '%s'", argv[idx]);
+    }
+  if (error_count)
+    exit (1);
+
+  /* Start checking.  */
+  start_timer ();
+  if (!argc)
+    {
+      for (algo=1; algo < 400; algo++)
+        if (!gcry_md_test_algo (algo))
+          {
+            if (!gigs)
+              run_selftest (algo);
+            else
+              run_longtest (algo, gigs);
+          }
+     }
+  else
+    {
+      for (idx=0; idx < argc; idx++)
+        {
+          algo = gcry_md_map_name (argv[idx]);
+          if (!algo)
+            die ("invalid algorithm '%s'", argv[idx]);
+
+          if (!gigs)
+            run_selftest (algo);
+          else
+            run_longtest (algo, gigs);
+        }
+    }
+  stop_timer ();
+
+  if (missing_test_vectors)
+    fail ("Some test vectors are missing");
+
+  if (verbose)
+    show ("All tests completed in %s.  Errors: %d\n",
+          elapsed_time (), error_count);
+  return !!error_count;
+}

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

Summary of changes:
 cipher/hash-common.c |    6 +-
 cipher/hash-common.h |    1 +
 cipher/md.c          |   10 +-
 cipher/md4.c         |   10 +-
 cipher/md5.c         |   10 +-
 cipher/rmd160.c      |   10 +-
 cipher/sha1.c        |   10 +-
 cipher/sha256.c      |   11 +-
 cipher/sha512.c      |   11 +-
 cipher/tiger.c       |   10 +-
 cipher/whirlpool.c   |    9 +-
 tests/Makefile.am    |    4 +-
 tests/genhashdata.c  |  158 +++++++++++++++++
 tests/hashtest.c     |  472 ++++++++++++++++++++++++++++++++++++++++++++++++++
 14 files changed, 711 insertions(+), 21 deletions(-)
 create mode 100644 tests/genhashdata.c
 create mode 100644 tests/hashtest.c


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




More information about the Gnupg-commits mailing list