Applied pacthes from Brad Hards.
authorWerner Koch <wk@gnupg.org>
Fri, 10 Mar 2006 10:23:52 +0000 (10:23 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 10 Mar 2006 10:23:52 +0000 (10:23 +0000)
Note, that the HMAC tests for SHA-384 and SHA-512 are failing.

12 files changed:
AUTHORS
NEWS
cipher/ChangeLog
cipher/md.c
cipher/sha256.c
doc/ChangeLog
doc/gcrypt.texi
src/ChangeLog
src/cipher.h
src/gcrypt.h
tests/ChangeLog
tests/basic.c

diff --git a/AUTHORS b/AUTHORS
index b3b398d..e09fc8d 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -70,7 +70,8 @@ tests/keygen.c, tests/pubkey.c, configure.ac, acinclude.m4)
 LIBGCRYPT       Brad Hards       2006-02-09
 Assigns Past and Future Changes
 bradh@frogmouth.net
-(Added OFB mode. Changed cipher/cipher.c, test/basic.c doc/gcrypt.tex)
+(Added OFB mode. Changed cipher/cipher.c, test/basic.c doc/gcrypt.tex.
+ added SHA-224, changed cipher/sha256.c, added HMAC tests.)
 
 
 
diff --git a/NEWS b/NEWS
index ab9cd7e..d43f255 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,7 @@ Noteworthy changes in version 1.3.0 (unreleased)
 gcry_fast_random_poll  NEW
 gcry_pk_algo_name       CHANGED (minor change in respect to return value)
 gcry_cipher_algo_name   CHANGED (minor change in respect to return value)
+GCRY_MD_SHA224          NEW
 
 FIXME: Please add API changes immediatley so that we don't
        forget about them.
index 792bd82..20036e0 100644 (file)
@@ -1,3 +1,8 @@
+2006-03-10  Brad Hards  <bradh@frogmouth.net>  (wk, patch 2005-04-22)
+
+       * md.c, sha256.c:  Add support for SHA-224.
+       (sha224_init): New.
+       
 2006-01-18  Brad Hards  <bradh@frogmouth.net>  (wk 2006-03-07)
 
        * cipher.c (cipher_encrypt, cipher_decrypt, do_ofb_encrypt)
index 95dad72..3bd9427 100644 (file)
@@ -56,6 +56,7 @@ static struct digest_table_entry
 #endif
 #if USE_SHA256
     { &_gcry_digest_spec_sha256, GCRY_MD_SHA256 },
+    { &_gcry_digest_spec_sha224, GCRY_MD_SHA224 },
 #endif
 #if USE_SHA512
     { &_gcry_digest_spec_sha512, GCRY_MD_SHA512 },
index 2391a5b..754f459 100644 (file)
@@ -1,5 +1,5 @@
 /* sha256.c - SHA256 hash function
- *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2006 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
 /*  Test vectors:
     
     "abc"
-    ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad
+    SHA224: 23097d22 3405d822 8642a477 bda255b3 2aadbce4 bda0b3f7 e36c9da7
+    SHA256: ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad
 
     "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-    248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
+    SHA224: 75388b16 512776cc 5dba5da1 fd890150 b0c6455c b4f58b19 52522525
+    SHA256: 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
  
     "a" one million times
-    cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0
+    SHA224: 20794655 980c91d8 bbb4c1ea 97618a4b f03f4258 1948b2ee 4ee7ad67
+    SHA256: cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0
 
  */
 
@@ -70,6 +73,25 @@ sha256_init (void *context)
 }
 
 
+static void
+sha224_init (void *context)
+{
+  SHA256_CONTEXT *hd = context;
+
+  hd->h0 = 0xc1059ed8;
+  hd->h1 = 0x367cd507;
+  hd->h2 = 0x3070dd17;
+  hd->h3 = 0xf70e5939;
+  hd->h4 = 0xffc00b31;
+  hd->h5 = 0x68581511;
+  hd->h6 = 0x64f98fa7;
+  hd->h7 = 0xbefa4fa4;
+
+  hd->nblocks = 0;
+  hd->count = 0;
+}
+
+
 /*
   Transform the message X which consists of 16 32-bit-words. See FIPS
   180-2 for details.  */
@@ -290,7 +312,20 @@ sha256_read (void *context)
   return hd->buf;
 }
 
-static byte asn[19] = /* Object ID is  2.16.840.1.101.3.4.2.1 */
+static byte asn224[19] = /* Object ID is 2.16.840.1.101.3.4.2.4 */
+  { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
+    0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
+    0x20
+  };
+
+static gcry_md_oid_spec_t oid_spec_sha224[] =
+  {
+    /* From RFC3874, Section 4 */
+    { "2.16.840.1.101.3.4.2.4" }, 
+    { NULL },
+  };
+
+static byte asn256[19] = /* Object ID is  2.16.840.1.101.3.4.2.1 */
   { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
     0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
     0x00, 0x04, 0x20 };
@@ -302,9 +337,16 @@ static gcry_md_oid_spec_t oid_spec_sha256[] =
     { NULL },
   };
 
+gcry_md_spec_t _gcry_digest_spec_sha224 =
+  {
+    "SHA224", asn224, DIM (asn224), oid_spec_sha224, 28,
+    sha224_init, sha256_write, sha256_final, sha256_read,
+    sizeof (SHA256_CONTEXT)
+  };
+
 gcry_md_spec_t _gcry_digest_spec_sha256 =
   {
-    "SHA256", asn, DIM (asn), oid_spec_sha256, 32,
+    "SHA256", asn256, DIM (asn256), oid_spec_sha256, 32,
     sha256_init, sha256_write, sha256_final, sha256_read,
     sizeof (SHA256_CONTEXT)
   };
index e0b5411..6bc92bc 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-10  Brad Hards  <bradh@frogmouth.net> (wk, patch 2005-04-25)
+
+       * gcrypt.texi: Document SHA-224 and typo fixes.
+
 2006-01-18  Brad Hards  <bradh@frogmouth.net> (wk 2006-03-07)
 
        * gcrypt.texi (Available cipher modes): Typo fix, add a little
index fa32a3a..483dc0e 100644 (file)
@@ -845,7 +845,7 @@ This value indicates success.  The value of this error code is
 @code{0}.  Also, it is guaranteed that an error value made from the
 error code @code{0} will be @code{0} itself (as a whole).  This means
 that the error source information is lost for this error code,
-however, as this error code indicates that no error occured, this is
+however, as this error code indicates that no error occurred, this is
 generally not a problem.
 
 @item GPG_ERR_GENERAL
@@ -1630,17 +1630,21 @@ This is an reserved for the HAVAL algorithm with 5 passes and 160
 bit. It yields a message digest of 20 bytes.  Note that there is no
 implementation yet available.
 
+@item GCRY_MD_SHA224
+This is the SHA-224 algorithm which yields a message digest of 28 bytes.
+See Change Notice 1 for FIPS 180-2 for the specification.
+
 @item GCRY_MD_SHA256
 This is the SHA-256 algorithm which yields a message digest of 32 bytes.
 See FIPS 180-2 for the specification.
 
 @item GCRY_MD_SHA384
-This is reserved for SHA-2 with 384 bits. It yields a message digest of
-48 bytes.  Note that there is no implementation yet available.
+This is the SHA-384 algorithm which yields a message digest of 48 bytes.
+See FIPS 180-2 for the specification.
 
 @item GCRY_MD_SHA512
-This is reserved for SHA-2 with 512 bits. It yields a message digest of
-64 bytes.  Note that there is no implementation yet available.
+This is the SHA-384 algorithm which yields a message digest of 64 bytes.
+See FIPS 180-2 for the specification.
 
 @item GCRY_MD_CRC32
 This is the ISO 3309 and ITU-T V.42 cyclic redundancy check.  It
@@ -1665,7 +1669,7 @@ bytes.
 @section Hash algorithm modules
 
 @acronym{Libgcrypt} makes it possible to load additional `message
-digest modules'; these cipher can be used just like the message digest
+digest modules'; these digests can be used just like the message digest
 algorithms that are built into the library directly.  For an
 introduction into extension modules, see @xref{Modules}.
 
@@ -1788,8 +1792,7 @@ this is the hashed data is highly confidential.
 
 @item GCRY_MD_FLAG_HMAC
 Turn the algorithm into a HMAC message authentication algorithm.  This
-does only work if just one algorithm is enabled for the handle and
-SHA-384 and SHA512 is not used.  Note that the function
+only works if just one algorithm is enabled for the handle.  Note that the function
 @code{gcry_md_setkey} must be used to set the MAC key.  If you want CBC
 message authentication codes based on a cipher, see @xref{Working with
 cipher handles}.
@@ -1846,7 +1849,7 @@ active algorithms.
 @end deftypefun
 
 
-Often it is necessary to start hashing some data and than continue to
+Often it is necessary to start hashing some data and then continue to
 hash different data.  To avoid hashing the same data several times (which
 might not even be possible if the data is received from a pipe), a
 snapshot of the current hash context can be taken and turned into a new
@@ -1861,10 +1864,10 @@ independently using the original context.
 @end deftypefun
 
 
-Now that we have prepared everything to calculate hashes, its time to
-see how it is actually done.  There are  ways for this, one to
+Now that we have prepared everything to calculate hashes, it is time to
+see how it is actually done.  There are two ways for this, one to
 update the hash with a block of memory and one macro to update the hash
-by just one character.  Both may be used intermixed.
+by just one character.  Both methods can be used on the same hash context.
 
 @deftypefun void gcry_md_write (gcry_md_hd_t @var{h}, const void *@var{buffer}, size_t @var{length})
 
@@ -1880,10 +1883,10 @@ update the digest value.  This is an efficient function, implemented as
 a macro to buffer the data before an actual update. 
 @end deftypefun
 
-The semantics of the hash functions don't allow to read out intermediate
-message digests because the calculation must be finalized fist.  This
+The semantics of the hash functions do not provide for reading out intermediate
+message digests because the calculation must be finalized first.  This
 finalization may for example include the number of bytes hashed in the
-message digest.  
+message digest or some padding.
 
 @deftypefun void gcry_md_final (gcry_md_hd_t @var{h})
 
@@ -1913,7 +1916,7 @@ been enabled.
 Because it is often necessary to get the message digest of one block of
 memory, a fast convenience function is available for this task: 
 
-@deftypefun void gcry_md_hash_buffer (int @var{algo}, void *@var{digest}, const cvoid *@var{buffer}, size_t @var{length});
+@deftypefun void gcry_md_hash_buffer (int @var{algo}, void *@var{digest}, const void *@var{buffer}, size_t @var{length});
 
 @code{gcry_md_hash_buffer} is a shortcut function to calculate a message
 digest of a buffer.  This function does not require a context and
@@ -1932,14 +1935,14 @@ algorithm is used.
 @c ***********************************
 
 Hash algorithms are identified by internal algorithm numbers (see
-@code{gcry_md_open} for a list.  However, in most applications they are
-used by names, so 2 functions are available to map between string
+@code{gcry_md_open} for a list).  However, in most applications they are
+used by names, so two functions are available to map between string
 representations and hash algorithm identifiers.
 
 @deftypefun const char *gcry_md_algo_name (int @var{algo})
 
 Map the digest algorithm id @var{algo} to a string representation of the
-algorithm name.  For unknown algorithms this functions returns an
+algorithm name.  For unknown algorithms this function returns an
 empty string.  This function should not be used to test for the
 availability of an algorithm.
 @end deftypefun
@@ -2571,7 +2574,7 @@ The function accepts public or secret keys in @var{key}.
 @deftypefun gcry_error_t gcry_pk_testkey (gcry_sexp_t @var{key})
 
 Return zero if the private key @var{key} is `sane', an error code otherwise.
-Note, that it is not possible to chek the `saneness' of a public key.
+Note, that it is not possible to check the `saneness' of a public key.
 
 @end deftypefun
 
@@ -3545,7 +3548,7 @@ This function is used to get data from a @var{list}.  A pointer to the
 actual data with index @var{number} is returned and the length of this
 data will be stored to @var{datalen}.  If there is no data at the given
 index or the index represents another list, @code{NULL} is returned.
-@strong{Note:} The returned pointer is valid as long as @var{list} is
+@strong{Caution:} The returned pointer is valid as long as @var{list} is
 not modified or released.
 
 @noindent
@@ -3897,7 +3900,7 @@ result in @var{x}.
 @end deftypefun
 
 @node Miscellaneous
-@section Miscellanous
+@section Miscellaneous
 
 @deftypefun gcry_mpi_t gcry_mpi_set_opaque (@w{gcry_mpi_t @var{a}}, @w{void *@var{p}}, @w{unsigned int @var{nbits}})
 
@@ -4093,7 +4096,7 @@ If you require secure memory, this code should be used:
 
   /* ... */
 
-  /* Allocate a pool of 16k secure memory.  This also drops priviliges
+  /* Allocate a pool of 16k secure memory.  This also drops privileges
      on some systems. */
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
 
index d5a2825..76c4cfa 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-10  Werner Koch  <wk@g10code.com>
+
+       * gcrypt.h: Add GCRY_MD_SHA224.
+
 2005-11-02  Moritz Schulte  <moritz@g10code.com>
 
        * gcrypt.h: Update comments for functions: gcry_cipher_algo_name,
index 1e0fbb9..5422f2f 100644 (file)
@@ -67,6 +67,7 @@ extern gcry_md_spec_t _gcry_digest_spec_md4;
 extern gcry_md_spec_t _gcry_digest_spec_md5;
 extern gcry_md_spec_t _gcry_digest_spec_rmd160;
 extern gcry_md_spec_t _gcry_digest_spec_sha1;
+extern gcry_md_spec_t _gcry_digest_spec_sha224;
 extern gcry_md_spec_t _gcry_digest_spec_sha256;
 extern gcry_md_spec_t _gcry_digest_spec_sha512;
 extern gcry_md_spec_t _gcry_digest_spec_sha384;
index 63e7de9..55ab4a7 100644 (file)
@@ -1,6 +1,6 @@
 /* gcrypt.h -  GNU cryptographic library interface
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004  Free Software Foundation, Inc.
+ *               2004, 2006  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -963,7 +963,8 @@ enum gcry_md_algos
     GCRY_MD_CRC32               = 302,
     GCRY_MD_CRC32_RFC1510       = 303,
     GCRY_MD_CRC24_RFC2440       = 304,
-    GCRY_MD_WHIRLPOOL = 305
+    GCRY_MD_WHIRLPOOL = 305,
+    GCRY_MD_SHA224  = 306
   };
 
 /* Flags used with the open function.  */
index 4d78663..881cb64 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-10  Brad Hards  <bradh@frogmouth.net>  (wk, patch 2006-02-18)
+
+       * basic.c (check_one_hmac, check_hmac): New.
+
 2006-03-07  Werner Koch  <wk@g10code.com>
 
        * benchmark.c (cipher_bench): Add OFB mode.
index 29e0054..0246632 100644 (file)
@@ -113,6 +113,9 @@ check_cbc_mac_cipher (void)
   int i, blklen, keylen;
   gcry_error_t err = 0;
 
+  if (verbose)
+    fprintf (stderr, "Starting CBC MAC checks.\n");
+
   for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
     {
       err = gcry_cipher_open (&hd,
@@ -160,6 +163,10 @@ check_cbc_mac_cipher (void)
          return;
        }
 
+      if (verbose)
+       fprintf (stderr, "  checking CBC MAC for %s [%i]\n", 
+                gcry_cipher_algo_name (tv[i].algo),
+                tv[i].algo);
       err = gcry_cipher_encrypt (hd,
                                 out, blklen,
                                 tv[i].plaintext,
@@ -188,6 +195,8 @@ check_cbc_mac_cipher (void)
 
       gcry_cipher_close (hd);
     }
+  if (verbose)
+    fprintf (stderr, "Completed CBC MAC checks.\n");
 }
 
 static void
@@ -230,6 +239,8 @@ check_aes128_cbc_cts_cipher (void)
   int i;
   gcry_error_t err = 0;
 
+  if (verbose)
+    fprintf (stderr, "Starting AES128 CBC CTS checks.\n");
   err = gcry_cipher_open (&hd,
                          GCRY_CIPHER_AES,
                          GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);
@@ -259,6 +270,8 @@ check_aes128_cbc_cts_cipher (void)
          return;
        }
 
+      if (verbose)
+       fprintf (stderr, "  checking encryption for length %i\n", tv[i].inlen);
       err = gcry_cipher_encrypt (hd, out, MAX_DATA_LEN,
                                 plaintext, tv[i].inlen);
       if (err)
@@ -280,6 +293,8 @@ check_aes128_cbc_cts_cipher (void)
          gcry_cipher_close (hd);
          return;
        }
+      if (verbose)
+       fprintf (stderr, "  checking decryption for length %i\n", tv[i].inlen);
       err = gcry_cipher_decrypt (hd, out, tv[i].inlen, NULL, 0);
       if (err)
        {
@@ -294,6 +309,8 @@ check_aes128_cbc_cts_cipher (void)
     }
 
   gcry_cipher_close (hd);
+  if (verbose)
+    fprintf (stderr, "Completed AES128 CBC CTS checks.\n");
 }
 
 static void
@@ -373,6 +390,8 @@ check_ctr_cipher (void)
   int i, j, keylen, blklen;
   gcry_error_t err = 0;
 
+  if (verbose)
+    fprintf (stderr, "Starting CTR cipher checks.\n");
   for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
     {
       err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
@@ -422,6 +441,10 @@ check_ctr_cipher (void)
          return;
        }
 
+      if (verbose)
+       fprintf (stderr, "  checking CTR mode for for %s [%i]\n", 
+                gcry_cipher_algo_name (tv[i].algo),
+                tv[i].algo);
       for (j = 0; tv[i].data[j].inlen; j++)
        {
          err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
@@ -458,6 +481,8 @@ check_ctr_cipher (void)
       gcry_cipher_close (hde);
       gcry_cipher_close (hdd);
     }
+  if (verbose)
+    fprintf (stderr, "Completed CTR cipher checks.\n");
 }
 
 static void
@@ -942,10 +967,12 @@ check_ciphers (void)
   };
   int i;
 
+  if (verbose)
+    fprintf (stderr, "Starting Cipher checks.\n");
   for (i = 0; algos[i]; i++)
     {
       if (verbose)
-       fprintf (stderr, "checking `%s' [%i]\n",
+       fprintf (stderr, "  checking %s [%i]\n",
                 gcry_cipher_algo_name (algos[i]),
                 gcry_cipher_map_name (gcry_cipher_algo_name (algos[i])));
 
@@ -960,13 +987,16 @@ check_ciphers (void)
   for (i = 0; algos2[i]; i++)
     {
       if (verbose)
-       fprintf (stderr, "checking `%s'\n",
+       fprintf (stderr, "  checking `%s'\n",
                 gcry_cipher_algo_name (algos2[i]));
 
       check_one_cipher (algos2[i], GCRY_CIPHER_MODE_STREAM, 0);
     }
   /* we have now run all cipher's selftests */
 
+  if (verbose)
+    fprintf (stderr, "Completed Cipher checks.\n");
+
   /* TODO: add some extra encryption to test the higher level functions */
 }
 
@@ -1066,6 +1096,17 @@ check_digests (void)
       { GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */ ,
        "\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
        "\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
+      // From RFC3874
+      {        GCRY_MD_SHA224, "abc",
+       "\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3"
+       "\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7" },
+      {        GCRY_MD_SHA224,
+       "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+       "\x75\x38\x8b\x16\x51\x27\x76\xcc\x5d\xba\x5d\xa1\xfd\x89\x01\x50"
+       "\xb0\xc6\x45\x5c\xb4\xf5\x8b\x19\x52\x52\x25\x25" },
+      {        GCRY_MD_SHA224, "!",
+       "\x20\x79\x46\x55\x98\x0c\x91\xd8\xbb\xb4\xc1\xea\x97\x61\x8a\x4b"
+       "\xf0\x3f\x42\x58\x19\x48\xb2\xee\x4e\xe7\xad\x67" },
       {        GCRY_MD_SHA256, "abc",
        "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
        "\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
@@ -1133,23 +1174,25 @@ check_digests (void)
        "ghijklmnopqrstuvwxyz+0123456789",
        "\x46\x7D\xB8\x08\x63\xEB\xCE\x48\x8D\xF1\xCD\x12"
        "\x61\x65\x5D\xE9\x57\x89\x65\x65\x97\x5F\x91\x97" },
-#if 0
       {        GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
        "by Ross Anderson and Eli Biham",
-       "0C410A042968868A1671DA5A3FD29A725EC1E457D3CDB303" },
+       "\x0C\x41\x0A\x04\x29\x68\x86\x8A\x16\x71\xDA\x5A"
+       "\x3F\xD2\x9A\x72\x5E\xC1\xE4\x57\xD3\xCD\xB3\x03" },
       {        GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
        "by Ross Anderson and Eli Biham, proceedings of Fa"
        "st Software Encryption 3, Cambridge.",
-       "EBF591D5AFA655CE7F22894FF87F54AC89C811B6B0DA3193" },
+       "\xEB\xF5\x91\xD5\xAF\xA6\x55\xCE\x7F\x22\x89\x4F"
+       "\xF8\x7F\x54\xAC\x89\xC8\x11\xB6\xB0\xDA\x31\x93" },
       {        GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
        "by Ross Anderson and Eli Biham, proceedings of Fa"
        "st Software Encryption 3, Cambridge, 1996.",
-       "3D9AEB03D1BD1A6357B2774DFD6D5B24DD68151D503974FC" },
+       "\x3D\x9A\xEB\x03\xD1\xBD\x1A\x63\x57\xB2\x77\x4D"
+       "\xFD\x6D\x5B\x24\xDD\x68\x15\x1D\x50\x39\x74\xFC" },
       {        GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh"
        "ijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRS"
        "TUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
-       "00B83EB4E53440C5 76AC6AAEE0A74858 25FD15E70A59FFE4" },
-#endif
+       "\x00\xB8\x3E\xB4\xE5\x34\x40\xC5\x76\xAC\x6A\xAE"
+       "\xE0\xA7\x48\x58\x25\xFD\x15\xE7\x0A\x59\xFF\xE4" },
       { GCRY_MD_WHIRLPOOL, "",
        "\x19\xFA\x61\xD7\x55\x22\xA4\x66\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
        "\xC5\x30\x23\x21\x30\xD4\x07\xF8\x9A\xFE\xE0\x96\x49\x97\xF7\xA7"
@@ -1181,18 +1224,387 @@ check_digests (void)
     };
   int i;
 
+  if (verbose)
+    fprintf (stderr, "Starting hash checks.\n");
+
   for (i = 0; algos[i].md; i++)
     {
       if (verbose)
-       fprintf (stderr, "checking `%s'\n", gcry_md_algo_name (algos[i].md));
+       fprintf (stderr, "  checking %s [%i] for length %zi\n", 
+                gcry_md_algo_name (algos[i].md),
+                algos[i].md,
+                strlen(algos[i].data));
 
       check_one_md (algos[i].md, algos[i].data, strlen (algos[i].data),
                    algos[i].expect);
     }
 
-  /* TODO: test HMAC mode */
+  if (verbose)
+    fprintf (stderr, "Completed hash checks.\n");
+}
+
+static void
+check_one_hmac (int algo, char *data, int datalen, 
+               char *key, int keylen, char *expect)
+{
+  gcry_md_hd_t hd, hd2;
+  unsigned char *p;
+  int mdlen;
+  int i;
+  gcry_error_t err = 0;
+
+  err = gcry_md_open (&hd, algo, GCRY_MD_FLAG_HMAC);
+  if (err)
+    {
+      fail ("algo %d, grcy_md_open failed: %s\n", algo, gpg_strerror (err));
+      return;
+    }
+
+  mdlen = gcry_md_get_algo_dlen (algo);
+  if (mdlen < 1 || mdlen > 500)
+    {
+      fail ("algo %d, grcy_md_get_algo_dlen failed: %d\n", algo, mdlen);
+      return;
+    }
+
+  gcry_md_setkey( hd, key, keylen );
+
+  gcry_md_write (hd, data, datalen);
+
+  err = gcry_md_copy (&hd2, hd);
+  if (err)
+    {
+      fail ("algo %d, gcry_md_copy failed: %s\n", algo, gpg_strerror (err));
+    }
+
+  gcry_md_close (hd);
+
+  p = gcry_md_read (hd2, algo);
+  if (0 == p)
+    fail("algo %d, hmac gcry_md_read failed\n", 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 (hd2);
 }
 
+static void
+check_hmac (void)
+{
+  static struct algos
+  {
+    int md;
+    char *data;
+    char *key;
+    char *expect;
+  } algos[] =
+    {
+      { GCRY_MD_MD5, "what do ya want for nothing?", "Jefe",
+       "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38" },
+      { GCRY_MD_MD5,
+       "Hi There",
+       "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+       "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d" },
+      { GCRY_MD_MD5,
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd",
+       "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+       "\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6" },
+      { GCRY_MD_MD5,
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd",
+       "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+       "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+       "\x69\x7e\xaf\x0a\xca\x3a\x3a\xea\x3a\x75\x16\x47\x46\xff\xaa\x79" },
+      { GCRY_MD_MD5, "Test With Truncation",
+       "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+       "\x56\x46\x1e\xf2\x34\x2e\xdc\x00\xf9\xba\xb9\x95\x69\x0e\xfd\x4c" },
+      { GCRY_MD_MD5, "Test Using Larger Than Block-Size Key - Hash Key First",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa",
+       "\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f\x0b\x62\xe6\xce\x61\xb9\xd0\xcd" },
+      { GCRY_MD_MD5,
+       "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa",
+       "\x6f\x63\x0f\xad\x67\xcd\xa0\xee\x1f\xb1\xf5\x62\xdb\x3a\xa5\x3e", },
+      { GCRY_MD_SHA256, "what do ya want for nothing?", "Jefe",
+       "\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7\x5a"
+       "\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43" },
+      { GCRY_MD_SHA256,
+       "Hi There",
+       "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+       "\x0b\x0b\x0b",
+       "\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88"
+       "\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7" },
+      { GCRY_MD_SHA256,
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd",
+       "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+       "\xAA\xAA\xAA\xAA",
+       "\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7"
+       "\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe" },
+      { GCRY_MD_SHA256,
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd",
+       "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+       "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+       "\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08"
+       "\x3a\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b" },
+      { GCRY_MD_SHA256, 
+       "Test Using Larger Than Block-Size Key - Hash Key First",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb\xf5\xb7\x7f"
+       "\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46\x04\x0f\x0e\xe3\x7f\x54" },
+      { GCRY_MD_SHA256, 
+       "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44"
+       "\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2" },
+      { GCRY_MD_SHA224, "what do ya want for nothing?", "Jefe",
+       "\xa3\x0e\x01\x09\x8b\xc6\xdb\xbf\x45\x69\x0f\x3a\x7e\x9e\x6d\x0f"
+       "\x8b\xbe\xa2\xa3\x9e\x61\x48\x00\x8f\xd0\x5e\x44" },
+      { GCRY_MD_SHA224,
+       "Hi There",
+       "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+       "\x0b\x0b\x0b",
+       "\x89\x6f\xb1\x12\x8a\xbb\xdf\x19\x68\x32\x10\x7c\xd4\x9d\xf3\x3f\x47"
+       "\xb4\xb1\x16\x99\x12\xba\x4f\x53\x68\x4b\x22" },
+      { GCRY_MD_SHA224,
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd",
+       "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+       "\xAA\xAA\xAA\xAA",
+       "\x7f\xb3\xcb\x35\x88\xc6\xc1\xf6\xff\xa9\x69\x4d\x7d\x6a\xd2\x64"
+       "\x93\x65\xb0\xc1\xf6\x5d\x69\xd1\xec\x83\x33\xea" },
+      { GCRY_MD_SHA224,
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd",
+       "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+       "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+       "\x6c\x11\x50\x68\x74\x01\x3c\xac\x6a\x2a\xbc\x1b\xb3\x82\x62"
+       "\x7c\xec\x6a\x90\xd8\x6e\xfc\x01\x2d\xe7\xaf\xec\x5a" },
+      { GCRY_MD_SHA224, 
+       "Test Using Larger Than Block-Size Key - Hash Key First",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x95\xe9\xa0\xdb\x96\x20\x95\xad\xae\xbe\x9b\x2d\x6f\x0d\xbc\xe2"
+       "\xd4\x99\xf1\x12\xf2\xd2\xb7\x27\x3f\xa6\x87\x0e" },
+      { GCRY_MD_SHA224, 
+       "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x3a\x85\x41\x66\xac\x5d\x9f\x02\x3f\x54\xd5\x17\xd0\xb3\x9d\xbd"
+       "\x94\x67\x70\xdb\x9c\x2b\x95\xc9\xf6\xf5\x65\xd1" },
+      { GCRY_MD_SHA384, "what do ya want for nothing?", "Jefe",
+       "\xaf\x45\xd2\xe3\x76\x48\x40\x31\x61\x7f\x78\xd2\xb5\x8a\x6b\x1b"
+       "\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47\xe4\x2e\xc3\x73\x63\x22\x44\x5e"
+       "\x8e\x22\x40\xca\x5e\x69\xe2\xc7\x8b\x32\x39\xec\xfa\xb2\x16\x49" },
+      { GCRY_MD_SHA384,
+       "Hi There",
+       "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+       "\x0b\x0b\x0b",
+       "\xaf\xd0\x39\x44\xd8\x48\x95\x62\x6b\x08\x25\xf4\xab\x46\x90\x7f\x15"
+       "\xf9\xda\xdb\xe4\x10\x1e\xc6\x82\xaa\x03\x4c\x7c\xeb\xc5\x9c\xfa\xea"
+       "\x9e\xa9\x07\x6e\xde\x7f\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6" },
+      { GCRY_MD_SHA384,
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd",
+       "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+       "\xAA\xAA\xAA\xAA",
+       "\x88\x06\x26\x08\xd3\xe6\xad\x8a\x0a\xa2\xac\xe0\x14\xc8\xa8\x6f"
+       "\x0a\xa6\x35\xd9\x47\xac\x9f\xeb\xe8\x3e\xf4\xe5\x59\x66\x14\x4b"
+       "\x2a\x5a\xb3\x9d\xc1\x38\x14\xb9\x4e\x3a\xb6\xe1\x01\xa3\x4f\x27" },
+      { GCRY_MD_SHA384,
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd",
+       "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+       "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+       "\x3e\x8a\x69\xb7\x78\x3c\x25\x85\x19\x33\xab\x62\x90\xaf\x6c\xa7"
+       "\x7a\x99\x81\x48\x08\x50\x00\x9c\xc5\x57\x7c\x6e\x1f\x57\x3b\x4e"
+       "\x68\x01\xdd\x23\xc4\xa7\xd6\x79\xcc\xf8\xa3\x86\xc6\x74\xcf\xfb" },
+      { GCRY_MD_SHA384, 
+       "Test Using Larger Than Block-Size Key - Hash Key First",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x4e\xce\x08\x44\x85\x81\x3e\x90\x88\xd2\xc6\x3a\x04\x1b\xc5\xb4"
+       "\x4f\x9e\xf1\x01\x2a\x2b\x58\x8f\x3c\xd1\x1f\x05\x03\x3a\xc4\xc6"
+       "\x0c\x2e\xf6\xab\x40\x30\xfe\x82\x96\x24\x8d\xf1\x63\xf4\x49\x52" },
+      { GCRY_MD_SHA384, 
+       "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x66\x17\x17\x8e\x94\x1f\x02\x0d\x35\x1e\x2f\x25\x4e\x8f\xd3\x2c"
+       "\x60\x24\x20\xfe\xb0\xb8\xfb\x9a\xdc\xce\xbb\x82\x46\x1e\x99\xc5"
+       "\xa6\x78\xcc\x31\xe7\x99\x17\x6d\x38\x60\xe6\x11\x0c\x46\x52\x3e" },
+      { GCRY_MD_SHA512, "what do ya want for nothing?", "Jefe",
+       "\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3"
+       "\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27\x0c\xd7\xea\x25\x05\x54"
+       "\x97\x58\xbf\x75\xc0\x5a\x99\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd"
+       "\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37" },
+      { GCRY_MD_SHA512,
+       "Hi There",
+       "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+       "\x0b\x0b\x0b",
+       "\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0"
+       "\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde"
+       "\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4"
+       "\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54" },
+      { GCRY_MD_SHA512,
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+       "\xdd\xdd\xdd\xdd\xdd",
+       "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+       "\xAA\xAA\xAA\xAA",
+       "\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c\x89\x0b\xe9"
+       "\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8\x3e\x33\xb2\x27\x9d\x39"
+       "\xbf\x3e\x84\x82\x79\xa7\x22\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07"
+       "\xb9\x46\xa3\x37\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb"  },
+      { GCRY_MD_SHA512,
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+       "\xcd\xcd\xcd\xcd\xcd",
+       "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+       "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+       "\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6\x1d\x4a\xf7"
+       "\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f\x80\x50\x36\x1e\xe3\xdb"
+       "\xa9\x1c\xa5\xc1\x1a\xa2\x5e\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63"
+       "\xa5\xf1\x97\x41\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd" },
+      { GCRY_MD_SHA512, 
+       "Test Using Larger Than Block-Size Key - Hash Key First",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4"
+       "\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b\x01\x37\x83\xf8\xf3\x52"
+       "\x6b\x56\xd0\x37\xe0\x5f\x25\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52"
+       "\x95\xe6\x4f\x73\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98" },
+      { GCRY_MD_SHA512, 
+       "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+       "\xaa\xaa\xaa",
+       "\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd"
+       "\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44"
+       "\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15"
+       "\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58" },
+      {        0 },
+    };
+  int i;
+
+  if (verbose)
+    fprintf (stderr, "Starting hashed MAC checks.\n");
+
+  for (i = 0; algos[i].md; i++)
+    {
+      if (verbose)
+       fprintf (stderr, "  checking %s [%i] for length %zi\n", 
+                gcry_md_algo_name (algos[i].md),
+                algos[i].md,
+                strlen(algos[i].data));
+
+      check_one_hmac (algos[i].md, algos[i].data, strlen (algos[i].data),
+                     algos[i].key, strlen(algos[i].key),
+                     algos[i].expect);
+    }
+
+  if (verbose)
+    fprintf (stderr, "Completed hashed MAC checks.\n");
+ }
+
 /* Check that the signature SIG matches the hash HASH. PKEY is the
    public key used for the verification. BADHASH is a hasvalue which
    should; result in a bad signature status. */
@@ -1260,7 +1672,7 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
   for (dataidx = 0; datas[dataidx].data; dataidx++)
     {
       if (verbose)
-       fprintf (stderr, "signature test %d\n", dataidx);
+       fprintf (stderr, "  signature test %d\n", dataidx);
 
       rc = gcry_sexp_sscan (&hash, NULL, datas[dataidx].data,
                            strlen (datas[dataidx].data));
@@ -1334,7 +1746,8 @@ get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
 {
   gcry_sexp_t key_spec, key, pub_key, sec_key;
   int rc;
-  
+  if (verbose)
+    fprintf (stderr, "  generating RSA key:");  
   rc = gcry_sexp_new (&key_spec,
                      "(genkey (rsa (nbits 4:1024)))", 0, 1);
   if (rc)
@@ -1366,7 +1779,7 @@ check_one_pubkey_new (int n)
   do_check_one_pubkey (n, skey, pkey, NULL, FLAG_SIGN | FLAG_CRYPT);
 }
 
-/* Run all tests for the public key fucntions. */
+/* Run all tests for the public key functions. */
 static void
 check_pubkey (void)
 {
@@ -1476,12 +1889,22 @@ check_pubkey (void)
       },
     };
   int i;
-
+  if (verbose)
+    fprintf (stderr, "Starting public key checks.\n");
   for (i = 0; i < sizeof (pubkeys) / sizeof (*pubkeys); i++)
     if (pubkeys[i].id)
       check_one_pubkey (i, pubkeys[i]);
+  if (verbose)
+    fprintf (stderr, "Completed public key checks.\n");
+
+  if (verbose)
+    fprintf (stderr, "Starting additional public key checks.\n");
+  for (i = 0; i < sizeof (pubkeys) / sizeof (*pubkeys); i++)
+    if (pubkeys[i].id)
+      check_one_pubkey_new (i);
+  if (verbose)
+    fprintf (stderr, "Completed additional public key checks.\n");
 
-  check_one_pubkey_new (i);
 }
 
 int
@@ -1510,7 +1933,10 @@ main (int argc, char **argv)
   check_cfb_cipher ();
   check_ofb_cipher ();
   check_digests ();
+  check_hmac ();
   check_pubkey ();
 
+  if (verbose)
+    fprintf (stderr, "\nAll tests completed. Errors: %i\n", error_count);
   return error_count ? 1 : 0;
 }