[git] GCRYPT - branch, LIBGCRYPT-1-6-BRANCH, updated. libgcrypt-1.6.0-11-g77f2879

by Werner Koch cvs at cvs.gnupg.org
Mon Jan 20 10:08:23 CET 2014


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, LIBGCRYPT-1-6-BRANCH has been updated
       via  77f28793481d1f41755242377164e4caaa1d106d (commit)
      from  ead3a097a9ee5908e562e6ec683707c38191acf3 (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 77f28793481d1f41755242377164e4caaa1d106d
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jan 9 19:14:09 2014 +0100

    md: Add Whirlpool bug emulation feature.
    
    * src/gcrypt.h.in (GCRY_MD_FLAG_BUGEMU1): New.
    * src/cipher-proto.h (gcry_md_init_t): Add arg FLAGS.  Change all code
    to implement that flag.
    * cipher/md.c (gcry_md_context):  Replace SECURE and FINALIZED by bit
    field FLAGS.  Add flag BUGEMU1.  Change all users.
    (md_open): Replace args SECURE and HMAC by FLAGS.  Init flags.bugemu1.
    (_gcry_md_open): Add for GCRY_MD_FLAG_BUGEMU1.
    (md_enable): Pass bugemu1 flag to the hash init function.
    (_gcry_md_reset): Ditto.
    --
    
    This problem is for example exhibited in the Linux cryptsetup tool.
    See https://bbs.archlinux.org/viewtopic.php?id=175737 .  It has
    been tracked down by Milan Broz.
    
    The suggested way of using the flag is:
    
      if (whirlpool_bug_assumed)
        {
    #if GCRYPT_VERSION_NUMBER >= 0x010601
          err = gcry_md_open (&hd, GCRY_MD_WHIRLPOOL, GCRY_MD_FLAG_BUGEMU1)
          if (gpg_err_code (err) == GPG_ERR_INV_ARG)
             error ("Need at least Libggcrypt 1.6.1 for the fix");
          else
             {
                do_hash (hd);
                gcry_md_close (hd);
              }
    #endif
        }
    
    Signed-off-by: Werner Koch <wk at gnupg.org>
    (cherry picked from commit 94030e44aaff805d754e368507f16dd51a531b72)
    
    Reolved conflicts:
    	NEWS
    	cipher/whirlpool.c: Remove NBLOCKS arg from whirlpool_transform.

diff --git a/NEWS b/NEWS
index 97fb089..9c3df10 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,12 @@ Noteworthy changes in version 1.6.1 (unreleased)
 
  * Fix build problem on NetBSD.
 
+ * Add emulation for broken Whirlpool code prior to 1.6.0.
+
+ * Interface changes relative to the 1.6.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ GCRY_MD_FLAG_BUGEMU1            NEW.
+
 
 Noteworthy changes in version 1.6.0 (2013-12-16)
 ------------------------------------------------
diff --git a/cipher/crc.c b/cipher/crc.c
index 4f72ffb..1322f0d 100644
--- a/cipher/crc.c
+++ b/cipher/crc.c
@@ -149,9 +149,12 @@ CRC_CONTEXT;
 /* CRC32 */
 
 static void
-crc32_init (void *context)
+crc32_init (void *context, unsigned int flags)
 {
   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+
+  (void)flags;
+
   ctx->CRC = 0 ^ 0xffffffffL;
 }
 
@@ -184,9 +187,12 @@ crc32_final (void *context)
 
 /* CRC32 a'la RFC 1510 */
 static void
-crc32rfc1510_init (void *context)
+crc32rfc1510_init (void *context, unsigned int flags)
 {
   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+
+  (void)flags;
+
   ctx->CRC = 0;
 }
 
@@ -237,9 +243,12 @@ crc32rfc1510_final (void *context)
 #define CRC24_POLY 0x1864cfbL
 
 static void
-crc24rfc2440_init (void *context)
+crc24rfc2440_init (void *context, unsigned int flags)
 {
   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+
+  (void)flags;
+
   ctx->CRC = CRC24_INIT;
 }
 
diff --git a/cipher/gostr3411-94.c b/cipher/gostr3411-94.c
index 1267216..5486964 100644
--- a/cipher/gostr3411-94.c
+++ b/cipher/gostr3411-94.c
@@ -44,10 +44,12 @@ static unsigned int
 transform (void *c, const unsigned char *data);
 
 static void
-gost3411_init (void *context)
+gost3411_init (void *context, unsigned int flags)
 {
   GOSTR3411_CONTEXT *hd = context;
 
+  (void)flags;
+
   memset (&hd->hd, 0, sizeof(hd->hd));
   memset (hd->h, 0, 32);
   memset (hd->sigma, 0, 32);
diff --git a/cipher/md.c b/cipher/md.c
index 1b59765..22da30a 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1,7 +1,7 @@
 /* md.c  -  message digest dispatcher
  * Copyright (C) 1998, 1999, 2002, 2003, 2006,
  *               2008 Free Software Foundation, Inc.
- * Copyright (C) 2013 g10 Code GmbH
+ * Copyright (C) 2013, 2014 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -94,9 +94,12 @@ struct gcry_md_context
 {
   int  magic;
   size_t actual_handle_size;     /* Allocated size of this handle. */
-  int  secure;
   FILE  *debug;
-  int finalized;
+  struct {
+    unsigned int secure: 1;
+    unsigned int finalized:1;
+    unsigned int bugemu1:1;
+  } flags;
   GcryDigestEntry *list;
   byte *macpads;
   int macpads_Bsize;             /* Blocksize as used for the HMAC pads. */
@@ -270,9 +273,11 @@ check_digest_algo (int algorithm)
  * may be 0.
  */
 static gcry_err_code_t
-md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
+md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = 0;
+  int secure = !!(flags & GCRY_MD_FLAG_SECURE);
+  int hmac =   !!(flags & GCRY_MD_FLAG_HMAC);
   int bufsize = secure ? 512 : 1024;
   struct gcry_md_context *ctx;
   gcry_md_hd_t hd;
@@ -316,7 +321,8 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
       memset (hd->ctx, 0, sizeof *hd->ctx);
       ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
       ctx->actual_handle_size = n + sizeof (struct gcry_md_context);
-      ctx->secure = secure;
+      ctx->flags.secure = secure;
+      ctx->flags.bugemu1 = !!(flags & GCRY_MD_FLAG_BUGEMU1);
 
       if (hmac)
 	{
@@ -372,13 +378,12 @@ _gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
   gcry_err_code_t rc;
   gcry_md_hd_t hd;
 
-  if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)))
+  if ((flags & ~(GCRY_MD_FLAG_SECURE
+                 | GCRY_MD_FLAG_HMAC
+                 | GCRY_MD_FLAG_BUGEMU1)))
     rc = GPG_ERR_INV_ARG;
   else
-    {
-      rc = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE),
-                    (flags & GCRY_MD_FLAG_HMAC));
-    }
+    rc = md_open (&hd, algo, flags);
 
   *h = rc? NULL : hd;
   return rc;
@@ -424,7 +429,7 @@ md_enable (gcry_md_hd_t hd, int algorithm)
                      - sizeof (entry->context));
 
       /* And allocate a new list entry. */
-      if (h->secure)
+      if (h->flags.secure)
 	entry = xtrymalloc_secure (size);
       else
 	entry = xtrymalloc (size);
@@ -439,7 +444,8 @@ md_enable (gcry_md_hd_t hd, int algorithm)
 	  h->list = entry;
 
 	  /* And init this instance. */
-	  entry->spec->init (&entry->context.c);
+	  entry->spec->init (&entry->context.c,
+                             h->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0);
 	}
     }
 
@@ -468,7 +474,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
     md_write (ahd, NULL, 0);
 
   n = (char *) ahd->ctx - (char *) ahd;
-  if (a->secure)
+  if (a->flags.secure)
     bhd = xtrymalloc_secure (n + sizeof (struct gcry_md_context));
   else
     bhd = xtrymalloc (n + sizeof (struct gcry_md_context));
@@ -506,7 +512,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
     {
       for (ar = a->list; ar; ar = ar->next)
         {
-          if (a->secure)
+          if (a->flags.secure)
             br = xtrymalloc_secure (sizeof *br
                                     + ar->spec->contextsize
                                     - sizeof(ar->context));
@@ -561,12 +567,13 @@ _gcry_md_reset (gcry_md_hd_t a)
 
   /* Note: We allow this even in fips non operational mode.  */
 
-  a->bufpos = a->ctx->finalized = 0;
+  a->bufpos = a->ctx->flags.finalized = 0;
 
   for (r = a->ctx->list; r; r = r->next)
     {
       memset (r->context.c, 0, r->spec->contextsize);
-      (*r->spec->init) (&r->context.c);
+      (*r->spec->init) (&r->context.c,
+                        a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0);
     }
   if (a->ctx->macpads)
     md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */
@@ -643,7 +650,7 @@ md_final (gcry_md_hd_t a)
 {
   GcryDigestEntry *r;
 
-  if (a->ctx->finalized)
+  if (a->ctx->flags.finalized)
     return;
 
   if (a->bufpos)
@@ -652,7 +659,7 @@ md_final (gcry_md_hd_t a)
   for (r = a->ctx->list; r; r = r->next)
     (*r->spec->final) (&r->context.c);
 
-  a->ctx->finalized = 1;
+  a->ctx->flags.finalized = 1;
 
   if (a->ctx->macpads)
     {
@@ -661,8 +668,11 @@ md_final (gcry_md_hd_t a)
       byte *p = md_read (a, algo);
       size_t dlen = md_digest_length (algo);
       gcry_md_hd_t om;
-      gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0);
+      gcry_err_code_t err;
 
+      err = md_open (&om, algo,
+                     ((a->ctx->flags.secure? GCRY_MD_FLAG_SECURE:0)
+                      | (a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0)));
       if (err)
 	_gcry_fatal_error (err, NULL);
       md_write (om,
@@ -865,7 +875,7 @@ _gcry_md_hash_buffer (int algo, void *digest,
             }
         }
 
-      err = md_open (&h, algo, 0, 0);
+      err = md_open (&h, algo, 0);
       if (err)
 	log_bug ("gcry_md_open failed for algo %d: %s",
                  algo, gpg_strerror (gcry_error(err)));
@@ -926,7 +936,7 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
             }
         }
 
-      rc = md_open (&h, algo, 0, hmac);
+      rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0));
       if (rc)
         return rc;
 
@@ -1159,7 +1169,7 @@ _gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
   switch (cmd)
     {
     case GCRYCTL_IS_SECURE:
-      *nbytes = h->ctx->secure;
+      *nbytes = h->ctx->flags.secure;
       break;
 
     case GCRYCTL_IS_ALGO_ENABLED:
diff --git a/cipher/md4.c b/cipher/md4.c
index b9a1a95..624ae99 100644
--- a/cipher/md4.c
+++ b/cipher/md4.c
@@ -69,10 +69,12 @@ static unsigned int
 transform ( void *c, const unsigned char *data );
 
 static void
-md4_init( void *context )
+md4_init (void *context, unsigned int flags)
 {
   MD4_CONTEXT *ctx = context;
 
+  (void)flags;
+
   ctx->A = 0x67452301;
   ctx->B = 0xefcdab89;
   ctx->C = 0x98badcfe;
diff --git a/cipher/md5.c b/cipher/md5.c
index 79b6e87..b0187c9 100644
--- a/cipher/md5.c
+++ b/cipher/md5.c
@@ -53,10 +53,12 @@ static unsigned int
 transform ( void *ctx, const unsigned char *data );
 
 static void
-md5_init( void *context )
+md5_init( void *context, unsigned int flags)
 {
   MD5_CONTEXT *ctx = context;
 
+  (void)flags;
+
   ctx->A = 0x67452301;
   ctx->B = 0xefcdab89;
   ctx->C = 0x98badcfe;
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
index a6d9a80..08e8cb0 100644
--- a/cipher/rmd160.c
+++ b/cipher/rmd160.c
@@ -143,11 +143,13 @@
 static unsigned int
 transform ( void *ctx, const unsigned char *data );
 
-void
-_gcry_rmd160_init (void *context)
+static void
+rmd160_init (void *context, unsigned int flags)
 {
   RMD160_CONTEXT *hd = context;
 
+  (void)flags;
+
   hd->h0 = 0x67452301;
   hd->h1 = 0xEFCDAB89;
   hd->h2 = 0x98BADCFE;
@@ -162,6 +164,12 @@ _gcry_rmd160_init (void *context)
 }
 
 
+void
+_gcry_rmd160_init (void *context)
+{
+  rmd160_init (context, 0);
+}
+
 
 /****************
  * Transform the message X which consists of 16 32-bit-words
@@ -512,6 +520,6 @@ gcry_md_spec_t _gcry_digest_spec_rmd160 =
   {
     GCRY_MD_RMD160, {0, 0},
     "RIPEMD160", asn, DIM (asn), oid_spec_rmd160, 20,
-    _gcry_rmd160_init, _gcry_md_block_write, rmd160_final, rmd160_read,
+    rmd160_init, _gcry_md_block_write, rmd160_final, rmd160_read,
     sizeof (RMD160_CONTEXT)
   };
diff --git a/cipher/sha1.c b/cipher/sha1.c
index 18b6daa..2e0b030 100644
--- a/cipher/sha1.c
+++ b/cipher/sha1.c
@@ -74,10 +74,12 @@ transform (void *c, const unsigned char *data);
 
 
 static void
-sha1_init (void *context)
+sha1_init (void *context, unsigned int flags)
 {
   SHA1_CONTEXT *hd = context;
 
+  (void)flags;
+
   hd->h0 = 0x67452301;
   hd->h1 = 0xefcdab89;
   hd->h2 = 0x98badcfe;
@@ -337,7 +339,7 @@ _gcry_sha1_hash_buffer (void *outbuf, const void *buffer, size_t length)
 {
   SHA1_CONTEXT hd;
 
-  sha1_init (&hd);
+  sha1_init (&hd, 0);
   _gcry_md_block_write (&hd, buffer, length);
   sha1_final (&hd);
   memcpy (outbuf, hd.bctx.buf, 20);
@@ -350,7 +352,7 @@ _gcry_sha1_hash_buffers (void *outbuf, const gcry_buffer_t *iov, int iovcnt)
 {
   SHA1_CONTEXT hd;
 
-  sha1_init (&hd);
+  sha1_init (&hd, 0);
   for (;iovcnt > 0; iov++, iovcnt--)
     _gcry_md_block_write (&hd,
                           (const char*)iov[0].data + iov[0].off, iov[0].len);
diff --git a/cipher/sha256.c b/cipher/sha256.c
index f3c1d62..d92303c 100644
--- a/cipher/sha256.c
+++ b/cipher/sha256.c
@@ -70,10 +70,12 @@ transform (void *c, const unsigned char *data);
 
 
 static void
-sha256_init (void *context)
+sha256_init (void *context, unsigned int flags)
 {
   SHA256_CONTEXT *hd = context;
 
+  (void)flags;
+
   hd->h0 = 0x6a09e667;
   hd->h1 = 0xbb67ae85;
   hd->h2 = 0x3c6ef372;
@@ -96,10 +98,12 @@ sha256_init (void *context)
 
 
 static void
-sha224_init (void *context)
+sha224_init (void *context, unsigned int flags)
 {
   SHA256_CONTEXT *hd = context;
 
+  (void)flags;
+
   hd->h0 = 0xc1059ed8;
   hd->h1 = 0x367cd507;
   hd->h2 = 0x3070dd17;
diff --git a/cipher/sha512.c b/cipher/sha512.c
index 586c809..26ed031 100644
--- a/cipher/sha512.c
+++ b/cipher/sha512.c
@@ -119,12 +119,14 @@ static unsigned int
 transform (void *context, const unsigned char *data);
 
 static void
-sha512_init (void *context)
+sha512_init (void *context, unsigned int flags)
 {
   SHA512_CONTEXT *ctx = context;
   SHA512_STATE *hd = &ctx->state;
   unsigned int features = _gcry_get_hw_features ();
 
+  (void)flags;
+
   hd->h0 = U64_C(0x6a09e667f3bcc908);
   hd->h1 = U64_C(0xbb67ae8584caa73b);
   hd->h2 = U64_C(0x3c6ef372fe94f82b);
@@ -157,12 +159,14 @@ sha512_init (void *context)
 }
 
 static void
-sha384_init (void *context)
+sha384_init (void *context, unsigned int flags)
 {
   SHA512_CONTEXT *ctx = context;
   SHA512_STATE *hd = &ctx->state;
   unsigned int features = _gcry_get_hw_features ();
 
+  (void)flags;
+
   hd->h0 = U64_C(0xcbbb9d5dc1059ed8);
   hd->h1 = U64_C(0x629a292a367cd507);
   hd->h2 = U64_C(0x9159015a3070dd17);
diff --git a/cipher/stribog.c b/cipher/stribog.c
index a3cab36..297b64a 100644
--- a/cipher/stribog.c
+++ b/cipher/stribog.c
@@ -1198,10 +1198,12 @@ transform64 (void *context, const unsigned char *inbuf_arg);
 
 
 static void
-stribog_init_512 (void *context)
+stribog_init_512 (void *context, unsigned int flags)
 {
   STRIBOG_CONTEXT *hd = context;
 
+  (void)flags;
+
   memset (hd, 0, sizeof (*hd));
 
   hd->bctx.blocksize = 64;
@@ -1209,10 +1211,11 @@ stribog_init_512 (void *context)
 }
 
 static void
-stribog_init_256 (void *context)
+stribog_init_256 (void *context, unsigned int flags)
 {
   STRIBOG_CONTEXT *hd = context;
-  stribog_init_512 (context);
+
+  stribog_init_512 (context, flags);
   memset (hd->h, 1, 64);
 }
 
diff --git a/cipher/whirlpool.c b/cipher/whirlpool.c
index e562781..338d44e 100644
--- a/cipher/whirlpool.c
+++ b/cipher/whirlpool.c
@@ -46,7 +46,7 @@
 /* Number of rounds.  */
 #define R 10
 
-

+
 
 /* Types.  */
 typedef u64 whirlpool_block_t[BLOCK_SIZE / 8];
@@ -54,6 +54,11 @@ typedef u64 whirlpool_block_t[BLOCK_SIZE / 8];
 typedef struct {
   gcry_md_block_ctx_t bctx;
   whirlpool_block_t hash_state;
+  int use_bugemu;
+  struct {
+    size_t count;
+    unsigned char length[32];
+  } bugemu;
 } whirlpool_context_t;
 
 

@@ -1158,25 +1163,8 @@ static const u64 C7[256] =
     U64_C (0xf8c7f8933fed6bf8), U64_C (0x86228644a411c286),
   };
 
-

-
-static unsigned int
-whirlpool_transform (void *ctx, const unsigned char *data);
 
 

-
-static void
-whirlpool_init (void *ctx)
-{
-  whirlpool_context_t *context = ctx;
-
-  memset (context, 0, sizeof (*context));
-
-  context->bctx.blocksize = BLOCK_SIZE;
-  context->bctx.bwrite = whirlpool_transform;
-}
-
-
 /*
  * Transform block.
  */
@@ -1280,15 +1268,139 @@ whirlpool_transform (void *ctx, const unsigned char *data)
                         4 * sizeof(void*);
 }
 
+
+static void
+whirlpool_init (void *ctx, unsigned int flags)
+{
+  whirlpool_context_t *context = ctx;
+
+  memset (context, 0, sizeof (*context));
+
+  context->bctx.blocksize = BLOCK_SIZE;
+  context->bctx.bwrite = whirlpool_transform;
+  if ((flags & GCRY_MD_FLAG_BUGEMU1))
+    {
+      memset (&context->bugemu, 0, sizeof context->bugemu);
+      context->use_bugemu = 1;
+    }
+  else
+    context->use_bugemu = 0;
+}
+
+
+/* Bug compatibility Whirlpool version.  */
+static void
+whirlpool_add_bugemu (whirlpool_context_t *context,
+                      const void *buffer_arg, size_t buffer_n)
+{
+  const unsigned char *buffer = buffer_arg;
+  u64 buffer_size;
+  unsigned int carry;
+  unsigned int i;
+
+  buffer_size = buffer_n;
+
+  if (context->bugemu.count == BLOCK_SIZE)
+    {
+      /* Flush the buffer.  */
+      whirlpool_transform (context, context->bctx.buf);
+      context->bugemu.count = 0;
+    }
+  if (! buffer)
+    return; /* Nothing to add.  */
+
+  if (context->bugemu.count)
+    {
+      while (buffer_n && (context->bugemu.count < BLOCK_SIZE))
+	{
+	  context->bctx.buf[context->bugemu.count++] = *buffer++;
+	  buffer_n--;
+	}
+      whirlpool_add_bugemu (context, NULL, 0);
+      if (!buffer_n)
+        return; /* Done.  This is the bug we emulate.  */
+    }
+
+  while (buffer_n >= BLOCK_SIZE)
+    {
+      whirlpool_transform (context, buffer);
+      context->bugemu.count = 0;
+      buffer_n -= BLOCK_SIZE;
+      buffer += BLOCK_SIZE;
+    }
+  while (buffer_n && (context->bugemu.count < BLOCK_SIZE))
+    {
+      context->bctx.buf[context->bugemu.count++] = *buffer++;
+      buffer_n--;
+    }
+
+  /* Update bit counter.  */
+  carry = 0;
+  buffer_size <<= 3;
+  for (i = 1; i <= 32; i++)
+    {
+      if (! (buffer_size || carry))
+	break;
+
+      carry += context->bugemu.length[32 - i] + (buffer_size & 0xFF);
+      context->bugemu.length[32 - i] = carry;
+      buffer_size >>= 8;
+      carry >>= 8;
+    }
+  gcry_assert (! (buffer_size || carry));
+}
+
+
+/* Bug compatibility Whirlpool version.  */
+static void
+whirlpool_final_bugemu (void *ctx)
+{
+  whirlpool_context_t *context = ctx;
+  unsigned int i;
+
+  /* Flush.  */
+  whirlpool_add_bugemu (context, NULL, 0);
+
+  /* Pad.  */
+  context->bctx.buf[context->bugemu.count++] = 0x80;
+
+  if (context->bugemu.count > 32)
+    {
+      /* An extra block is necessary.  */
+      while (context->bugemu.count < 64)
+	context->bctx.buf[context->bugemu.count++] = 0;
+      whirlpool_add_bugemu (context, NULL, 0);
+    }
+  while (context->bugemu.count < 32)
+    context->bctx.buf[context->bugemu.count++] = 0;
+
+  /* Add length of message.  */
+  memcpy (context->bctx.buf + context->bugemu.count,
+          context->bugemu.length, 32);
+  context->bugemu.count += 32;
+  whirlpool_add_bugemu (context, NULL, 0);
+
+  block_to_buffer (context->bctx.buf, context->hash_state, i);
+}
+
+
 static void
 whirlpool_write (void *ctx, const void *buffer, size_t buffer_n)
 {
   whirlpool_context_t *context = ctx;
-  u64 old_nblocks = context->bctx.nblocks;
 
-  _gcry_md_block_write (context, buffer, buffer_n);
+  if (context->use_bugemu)
+    {
+      whirlpool_add_bugemu (context, buffer, buffer_n);
+    }
+  else
+    {
+      u64 old_nblocks = context->bctx.nblocks;
+
+      _gcry_md_block_write (context, buffer, buffer_n);
 
-  gcry_assert (old_nblocks <= context->bctx.nblocks);
+      gcry_assert (old_nblocks <= context->bctx.nblocks);
+    }
 }
 
 static void
@@ -1299,6 +1411,12 @@ whirlpool_final (void *ctx)
   u64 t, th, lsb, msb;
   unsigned char *length;
 
+  if (context->use_bugemu)
+    {
+      whirlpool_final_bugemu (ctx);
+      return;
+    }
+
   t = context->bctx.nblocks;
   /* if (sizeof t == sizeof context->bctx.nblocks) */
   th = context->bctx.nblocks_high;
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 7af1706..c2534a2 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3194,6 +3194,22 @@ The size of the MAC is equal to the message digest of the underlying
 hash algorithm.  If you want CBC message authentication codes based on
 a cipher, see @xref{Working with cipher handles}.
 
+ at item GCRY_MD_FLAG_BUGEMU1
+ at cindex bug emulation
+Versions of Libgcrypt before 1.6.0 had a bug in the Whirlpool code
+which led to a wrong result for certain input sizes and write
+patterns.  Using this flag emulates that bug.  This may for example be
+useful for applications which use Whirlpool as part of their key
+generation.  It is strongly suggested to use this flag only if really
+needed and if possible to the data should be re-processed using the
+regular Whirlpool algorithm.
+
+Note that this flag works for the entire hash context.  If needed
+arises it may be used to enable bug emulation for other hash
+algorithms.  Thus you should not use this flag for a multi-algorithm
+hash context.
+
+
 @end table
 @c begin table of hash flags
 
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index 0955ef5..8267791 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -204,7 +204,7 @@ typedef struct gcry_cipher_spec
  */
 
 /* Type for the md_init function.  */
-typedef void (*gcry_md_init_t) (void *c);
+typedef void (*gcry_md_init_t) (void *c, unsigned int flags);
 
 /* Type for the md_write function.  */
 typedef void (*gcry_md_write_t) (void *c, const void *buf, size_t nbytes);
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 5c771e5..9e94e87 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1151,7 +1151,8 @@ enum gcry_md_algos
 enum gcry_md_flags
   {
     GCRY_MD_FLAG_SECURE = 1,  /* Allocate all buffers in "secure" memory.  */
-    GCRY_MD_FLAG_HMAC   = 2   /* Make an HMAC out of this algorithm.  */
+    GCRY_MD_FLAG_HMAC   = 2,  /* Make an HMAC out of this algorithm.  */
+    GCRY_MD_FLAG_BUGEMU1 = 0x0100
   };
 
 /* (Forward declaration.)  */
diff --git a/tests/basic.c b/tests/basic.c
index 0eb8215..97276d0 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -4046,6 +4046,7 @@ check_digests (void)
 #endif
       {	0 }
     };
+  gcry_error_t err;
   int i;
 
   if (verbose)
@@ -4074,6 +4075,58 @@ check_digests (void)
                           algos[i].expect);
     }
 
+  /* Check the Whirlpool bug emulation.  */
+  if (!gcry_md_test_algo (GCRY_MD_WHIRLPOOL) && !in_fips_mode)
+    {
+      static const char expect[] =
+        "\x35\x28\xd6\x4c\x56\x2c\x55\x2e\x3b\x91\x93\x95\x7b\xdd\xcc\x6e"
+        "\x6f\xb7\xbf\x76\x22\x9c\xc6\x23\xda\x3e\x09\x9b\x36\xe8\x6d\x76"
+        "\x2f\x94\x3b\x0c\x63\xa0\xba\xa3\x4d\x66\x71\xe6\x5d\x26\x67\x28"
+        "\x36\x1f\x0e\x1a\x40\xf0\xce\x83\x50\x90\x1f\xfa\x3f\xed\x6f\xfd";
+      gcry_md_hd_t hd;
+      int algo = GCRY_MD_WHIRLPOOL;
+      unsigned char *p;
+      int mdlen;
+
+      err = gcry_md_open (&hd, GCRY_MD_WHIRLPOOL, GCRY_MD_FLAG_BUGEMU1);
+      if (err)
+        {
+          fail ("algo %d, gcry_md_open failed: %s\n", algo, gpg_strerror (err));
+          goto leave;
+        }
+
+      mdlen = gcry_md_get_algo_dlen (algo);
+      if (mdlen < 1 || mdlen > 500)
+        {
+          fail ("algo %d, gcry_md_get_algo_dlen failed: %d\n", algo, mdlen);
+          gcry_md_close (hd);
+          goto leave;
+        }
+
+      /* Hash 62 byes in chunks.  */
+      gcry_md_write (hd, "1234567890", 10);
+      gcry_md_write (hd, "1234567890123456789012345678901234567890123456789012",
+                     52);
+
+      p = gcry_md_read (hd, algo);
+
+      if (memcmp (p, expect, mdlen))
+        {
+          printf ("computed: ");
+          for (i = 0; i < mdlen; i++)
+            printf ("%02x ", p[i] & 0xFF);
+          printf ("\nexpected: ");
+          for (i = 0; i < mdlen; i++)
+            printf ("%02x ", expect[i] & 0xFF);
+          printf ("\n");
+
+          fail ("algo %d, digest mismatch\n", algo);
+        }
+
+      gcry_md_close (hd);
+    }
+
+ leave:
   if (verbose)
     fprintf (stderr, "Completed hash checks.\n");
 }

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

Summary of changes:
 NEWS                  |    6 ++
 cipher/crc.c          |   15 ++++-
 cipher/gostr3411-94.c |    4 +-
 cipher/md.c           |   56 ++++++++++-------
 cipher/md4.c          |    4 +-
 cipher/md5.c          |    4 +-
 cipher/rmd160.c       |   14 ++++-
 cipher/sha1.c         |    8 ++-
 cipher/sha256.c       |    8 ++-
 cipher/sha512.c       |    8 ++-
 cipher/stribog.c      |    9 ++-
 cipher/whirlpool.c    |  160 ++++++++++++++++++++++++++++++++++++++++++-------
 doc/gcrypt.texi       |   16 +++++
 src/cipher-proto.h    |    2 +-
 src/gcrypt.h.in       |    3 +-
 tests/basic.c         |   53 ++++++++++++++++
 16 files changed, 305 insertions(+), 65 deletions(-)


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




More information about the Gnupg-commits mailing list