From 94030e44aaff805d754e368507f16dd51a531b72 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 9 Jan 2014 19:14:09 +0100 Subject: 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 be 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 --- NEWS | 3 ++ 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 | 132 ++++++++++++++++++++++++++++++++++++++++++++++++-- doc/gcrypt.texi | 16 ++++++ src/cipher-proto.h | 2 +- src/gcrypt.h.in | 3 +- tests/basic.c | 53 ++++++++++++++++++++ 16 files changed, 291 insertions(+), 48 deletions(-) diff --git a/NEWS b/NEWS index 4bf4a066..5e21eb6b 100644 --- a/NEWS +++ b/NEWS @@ -8,10 +8,13 @@ Noteworthy changes in version 1.7.0 (unreleased) * Support curves GOST R 34.10-2001 and GOST R 34.10-2012. + * Add emulation from broken Whirlpool code prior to 1.6.0. + * Interface changes relative to the 1.6.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gcry_mac_get_algo NEW. GCRY_MAC_HMAC_MD2 NEW. + 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 4f72ffb2..1322f0da 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 b3326aa5..9a39733d 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, size_t nblks); 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 f4fb1294..a332e039 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. * @@ -93,9 +93,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. */ @@ -269,9 +272,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; @@ -315,7 +320,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) { @@ -371,13 +377,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; @@ -423,7 +428,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); @@ -438,7 +443,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); } } @@ -467,7 +473,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)); @@ -505,7 +511,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)); @@ -560,12 +566,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 */ @@ -642,7 +649,7 @@ md_final (gcry_md_hd_t a) { GcryDigestEntry *r; - if (a->ctx->finalized) + if (a->ctx->flags.finalized) return; if (a->bufpos) @@ -651,7 +658,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) { @@ -660,8 +667,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, @@ -864,7 +874,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))); @@ -925,7 +935,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; @@ -1158,7 +1168,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 40dc0586..72912545 100644 --- a/cipher/md4.c +++ b/cipher/md4.c @@ -69,10 +69,12 @@ static unsigned int transform ( void *c, const unsigned char *data, size_t nblks ); 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 d06d3f78..73ad968b 100644 --- a/cipher/md5.c +++ b/cipher/md5.c @@ -53,10 +53,12 @@ static unsigned int transform ( void *ctx, const unsigned char *data, size_t datalen ); 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 224694f2..1a58ba61 100644 --- a/cipher/rmd160.c +++ b/cipher/rmd160.c @@ -143,11 +143,13 @@ static unsigned int transform ( void *ctx, const unsigned char *data, size_t nblks ); -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 @@ -528,6 +536,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 889a7ea1..65bd6866 100644 --- a/cipher/sha1.c +++ b/cipher/sha1.c @@ -106,11 +106,13 @@ transform (void *c, const unsigned char *data, size_t nblks); static void -sha1_init (void *context) +sha1_init (void *context, unsigned int flags) { SHA1_CONTEXT *hd = context; unsigned int features = _gcry_get_hw_features (); + (void)flags; + hd->h0 = 0x67452301; hd->h1 = 0xefcdab89; hd->h2 = 0x98badcfe; @@ -425,7 +427,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); @@ -438,7 +440,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 601e9c0b..4efaec6f 100644 --- a/cipher/sha256.c +++ b/cipher/sha256.c @@ -92,11 +92,13 @@ transform (void *c, const unsigned char *data, size_t nblks); static void -sha256_init (void *context) +sha256_init (void *context, unsigned int flags) { SHA256_CONTEXT *hd = context; unsigned int features = _gcry_get_hw_features (); + (void)flags; + hd->h0 = 0x6a09e667; hd->h1 = 0xbb67ae85; hd->h2 = 0x3c6ef372; @@ -128,11 +130,13 @@ sha256_init (void *context) static void -sha224_init (void *context) +sha224_init (void *context, unsigned int flags) { SHA256_CONTEXT *hd = context; unsigned int features = _gcry_get_hw_features (); + (void)flags; + hd->h0 = 0xc1059ed8; hd->h1 = 0x367cd507; hd->h2 = 0x3070dd17; diff --git a/cipher/sha512.c b/cipher/sha512.c index 3474694c..92b49131 100644 --- a/cipher/sha512.c +++ b/cipher/sha512.c @@ -119,12 +119,14 @@ static unsigned int transform (void *context, const unsigned char *data, size_t nblks); 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 6d1d3422..942bbf4c 100644 --- a/cipher/stribog.c +++ b/cipher/stribog.c @@ -1198,10 +1198,12 @@ transform (void *context, const unsigned char *inbuf_arg, size_t datalen); 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 57ca8826..ffc6662c 100644 --- a/cipher/whirlpool.c +++ b/cipher/whirlpool.c @@ -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; @@ -1166,7 +1171,7 @@ whirlpool_transform (void *ctx, const unsigned char *data, size_t nblks); static void -whirlpool_init (void *ctx) +whirlpool_init (void *ctx, unsigned int flags) { whirlpool_context_t *context = ctx; @@ -1174,9 +1179,17 @@ whirlpool_init (void *ctx) 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; } + /* * Transform block. */ @@ -1295,15 +1308,120 @@ whirlpool_transform ( void *c, const unsigned char *data, size_t nblks ) return burn; } + +/* 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, 1); + 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, 1); + 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 @@ -1314,6 +1432,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 7712b80a..4a917901 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -3111,6 +3111,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}. +@item GCRY_MD_FLAG_BUGEMU1 +@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 0955ef59..82677917 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 f8318c00..b06f2592 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 697485ed..5fd71313 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"); } -- cgit v1.2.1