[PATCH] Add CMAC mode (Cipher-based MAC)

Jussi Kivilinna jussi.kivilinna at iki.fi
Fri Nov 1 14:35:22 CET 2013


On 31.10.2013 17:01, Werner Koch wrote:
> On Thu, 31 Oct 2013 13:41, jussi.kivilinna at iki.fi said:
>
> > Patch adds CMAC (Cipher-based MAC) mode as defined in RFC 4493 and NIST
> > Special Publication 800-38B.
> >
> > Example of usage:
> >   /* Message 1 is split to two buffers, buf1_a and buf1_b. */
> >   gcry_cipher_setkey(h, key, len(key));
>
> I wonder whether it is a good idea to put MAC algorithms into the cipher
> module.  It is a bit of surprise because a MAC has IMHO more of a hash
> algorithm than of a cipher algorithm.  Also, we already have HMAC in
> gcry_md_*.  Right, there is quite some overlap now with the
> authenticated methods.  The later are however justified in gcry_cipher
> because their main purpose is encryption.
>
> Opinions?

I actually initially made patch that adds CMAC to gcry_md_*, because HMAC
existing there already. I've attached this patch below.

Problem with this is how to define CMAC.. should it be defined as one
'hash' with some method to select underlying block cipher. How do we
map block cipher names to hash names, etc?  Or do we select limited
set of block ciphers that each provide new hash algorithm (as done in
the patch below; GCRY_MD_CMAC_AES, _DES, _CAMELLIA, selected because
existing documentation/test vectors). This obviously limits chooses
for library user. Whatever that's good or bad, I don't know.

The patch below also adds new cmac hacks to core gcry_md code which
is why I don't particularly like the approach.

Since adding GCM mode kind of adds GHASH to gcry_cipher as side product
and CBC-MAC already is provided in gcry_cipher, adding CMAC to
gcry_cipher seems much cleaner option.

-Jussi

---
 cipher/Makefile.am |    1 
 cipher/cmac.c      |  344 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 cipher/md.c        |   76 +++++++++++
 src/cipher.h       |   15 ++
 src/gcrypt.h.in    |    6 +
 tests/basic.c      |  232 +++++++++++++++++++++++++++++------
 tests/benchmark.c  |   57 ++++++++-
 7 files changed, 677 insertions(+), 54 deletions(-)
 create mode 100644 cipher/cmac.c

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 87f693e..ffe8294 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -46,6 +46,7 @@ pubkey.c pubkey-internal.h pubkey-util.c \
 md.c \
 kdf.c kdf-internal.h \
 hmac-tests.c \
+cmac.c \
 bithelp.h  \
 bufhelp.h  \
 primegen.c  \
diff --git a/cipher/cmac.c b/cipher/cmac.c
new file mode 100644
index 0000000..03994b3
--- /dev/null
+++ b/cipher/cmac.c
@@ -0,0 +1,344 @@
+/* cmac.c - CMAC, Cipher-based MAC.
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna at iki.fi>
+ *
+ * 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/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "g10lib.h"
+#include "cipher.h"
+#include "cipher-internal.h"
+#include "bufhelp.h"
+
+
+#define MAX_BLOCKSIZE 16
+#define MAX_KEYLEN 32
+
+struct cmac_context {
+  gcry_cipher_hd_t hd;
+  unsigned int blocksize, count, initialized;
+  int keylen, md_algo, secure;
+  byte buf[MAX_BLOCKSIZE], key[MAX_KEYLEN];
+  byte k[2][MAX_BLOCKSIZE];
+};
+
+
+static int
+cmac_md_to_cipher (int md_algo)
+{
+  switch (md_algo) {
+  case GCRY_MD_CMAC_AES:
+    return GCRY_CIPHER_AES;
+  case GCRY_MD_CMAC_3DES:
+    return GCRY_CIPHER_3DES;
+  case GCRY_MD_CMAC_CAMELLIA:
+    return GCRY_CIPHER_CAMELLIA128;
+  default:
+    return -1;
+  }
+}
+
+
+gcry_err_code_t
+_gcry_cmac_init (void *_ctx, int md_algo, int secure)
+{
+  struct cmac_context *ctx = _ctx;
+  gcry_err_code_t err;
+  int flags, cipher_algo;
+  unsigned int blocksize;
+
+  memset (ctx, 0, sizeof(*ctx));
+
+  flags = GCRY_CIPHER_CBC_MAC;
+  if (secure)
+    flags |= GCRY_CIPHER_SECURE;
+
+  cipher_algo = cmac_md_to_cipher(md_algo);
+  if (cipher_algo <= 0)
+    return GPG_ERR_INV_ARG;
+
+  /* Only blocksizes 8 and 16 are supported. */
+  blocksize = gcry_cipher_get_algo_blklen(cipher_algo);
+  if (blocksize != 8 && blocksize != 16)
+    return GPG_ERR_INV_ARG;
+
+  err = _gcry_cipher_open (&ctx->hd, cipher_algo, GCRY_CIPHER_MODE_CBC, flags);
+  if (err)
+    return err;
+
+  ctx->count = 0;
+  ctx->blocksize = blocksize;
+  ctx->initialized = 1;
+  ctx->keylen = -1;
+  ctx->md_algo = md_algo;
+
+  return GPG_ERR_NO_ERROR;
+}
+
+
+void
+_gcry_cmac_close (void *_ctx)
+{
+  struct cmac_context *ctx = _ctx;
+
+  if (!ctx->initialized)
+    return;
+
+  _gcry_cipher_close (ctx->hd);
+
+  wipememory (ctx, sizeof(*ctx));
+  ctx->hd = 0;
+  ctx->keylen = -1;
+  ctx->initialized = 0;
+  ctx->count = 0;
+}
+
+
+gcry_error_t
+_gcry_cmac_setkey (void *_ctx, const byte *key, unsigned int keylen)
+{
+  struct cmac_context *ctx = _ctx;
+  unsigned int blocksize = ctx->blocksize;
+  gcry_err_code_t err;
+  byte buf[MAX_BLOCKSIZE];
+  int j, i;
+  unsigned int t, bi, carry, rb;
+
+  if (!ctx->initialized || keylen > MAX_KEYLEN)
+    return GPG_ERR_INV_ARG;
+
+  err = _gcry_cipher_setkey (ctx->hd, key, keylen);
+  if (err)
+    return err;
+
+  memcpy (ctx->key, key, keylen);
+  ctx->keylen = keylen;
+
+  /* encrypt zero block */
+  memset (ctx->hd->u_iv.iv, 0, blocksize);
+  memset (buf, 0, blocksize);
+  err = _gcry_cipher_cbc_encrypt (ctx->hd, buf, blocksize, buf, blocksize);
+  if (err)
+    BUG();
+
+  rb = blocksize == 16 ? 0x87 : 0x1B /*blocksize == 8*/;
+
+  for (j = 0; j < 2; j++)
+    {
+      /* Generate subkeys K1 and K2 */
+      carry = 0;
+      for (i = blocksize - 1; i >= 0; i--)
+        {
+          bi = buf[i];
+          t = carry | (bi << 1);
+          carry = bi >> 7;
+          ctx->k[j][i] = buf[i] = t & 0xff;
+        }
+      ctx->k[j][blocksize - 1] = buf[blocksize - 1] ^= carry ? rb : 0;
+    }
+
+  /* set C_0 to zero */
+  memset (ctx->hd->u_iv.iv, 0, blocksize);
+
+  wipememory(buf, sizeof(buf));
+
+  return err;
+}
+
+
+gcry_err_code_t
+_gcry_cmac_reset (void *_ctx)
+{
+  struct cmac_context *ctx = _ctx;
+  gcry_err_code_t err;
+  int keylen, md_algo, secure;
+  byte key[MAX_KEYLEN];
+
+  keylen = ctx->keylen;
+  md_algo = ctx->md_algo;
+  secure = ctx->secure;
+  if (keylen >= 0)
+    memcpy (key, ctx->key, keylen);
+
+  if (!ctx->initialized)
+    _gcry_cmac_close (ctx);
+
+  err = _gcry_cmac_init (ctx, md_algo, secure);
+  if (err)
+    return err;
+
+  if (keylen >= 0)
+    _gcry_cmac_setkey(ctx, key, keylen);
+
+  wipememory (key, sizeof(key));
+
+  return err;
+}
+
+
+gcry_err_code_t
+_gcry_cmac_copy_context (void *_new_ctx, void *_old_ctx)
+{
+  struct cmac_context *new_ctx = _new_ctx;
+  struct cmac_context *old_ctx = _old_ctx;
+  gcry_err_code_t err;
+
+  new_ctx->hd = NULL;
+  new_ctx->initialized = 0;
+
+  err = _gcry_cmac_reset(new_ctx);
+  if (err)
+    return err;
+
+  new_ctx->count = old_ctx->count;
+  memcpy(new_ctx->buf, old_ctx->buf, sizeof(old_ctx->buf));
+
+  if (new_ctx->initialized && old_ctx->initialized)
+    memcpy(new_ctx->hd->u_iv.iv, old_ctx->hd->u_iv.iv, new_ctx->blocksize);
+
+  return err;
+}
+
+
+static void
+cmac_write (void *_ctx, const void *_buf, size_t inlen)
+{
+  struct cmac_context *ctx = _ctx;
+  unsigned int blocksize = ctx->blocksize;
+  const byte *inbuf = _buf;
+  gcry_err_code_t err;
+  byte outbuf[MAX_BLOCKSIZE];
+  unsigned int nb;
+
+  if (ctx->keylen < 0)
+    BUG();
+
+  if (!inlen || !inbuf)
+    return;
+
+  /* Last block is needed for cmac_final.  */
+  if (ctx->count + inlen <= blocksize)
+    {
+      for (; inlen && ctx->count < blocksize; inlen--)
+        ctx->buf[ctx->count++] = *inbuf++;
+      return;
+    }
+
+  if (ctx->count)
+    {
+      for (; inlen && ctx->count < blocksize; inlen--)
+        ctx->buf[ctx->count++] = *inbuf++;
+
+      err = _gcry_cipher_cbc_encrypt (ctx->hd, outbuf, blocksize, ctx->buf,
+                                      blocksize);
+      if (err)
+        BUG();
+      ctx->count = 0;
+    }
+
+  if (inlen > blocksize)
+    {
+       nb = inlen / blocksize;
+       nb -= (nb * blocksize == inlen);
+       err = _gcry_cipher_cbc_encrypt (ctx->hd, outbuf, blocksize, inbuf,
+                                       nb * blocksize);
+       if (err)
+         BUG();
+       inlen -= nb * blocksize;
+       inbuf += nb * blocksize;
+    }
+
+  if (inlen == 0)
+    BUG();
+  for (; inlen && ctx->count < blocksize; inlen--)
+    ctx->buf[ctx->count++] = *inbuf++;
+
+  wipememory(outbuf, sizeof(outbuf));
+}
+
+
+static void
+cmac_final (void *_ctx)
+{
+  struct cmac_context *ctx = _ctx;
+  unsigned int blocksize = ctx->blocksize;
+  unsigned int count = ctx->count;
+  gcry_err_code_t err;
+  byte *subkey;
+
+  if (count == blocksize)
+    subkey = ctx->k[0]; /* K1 */
+  else
+    {
+      subkey = ctx->k[1]; /* K2 */
+      ctx->buf[count++] = 0x80;
+      while (count < blocksize)
+        ctx->buf[count++] = 0;
+    }
+
+  buf_xor( ctx->buf, ctx->buf, subkey, blocksize);
+
+  err = _gcry_cipher_cbc_encrypt (ctx->hd, ctx->buf, blocksize, ctx->buf,
+                                  blocksize);
+  if (err)
+    BUG();
+
+  ctx->count = 0;
+}
+
+
+static byte *
+cmac_read (void *_ctx)
+{
+  struct cmac_context *ctx = _ctx;
+
+  return ctx->buf;
+}
+
+
+#ifdef USE_AES
+gcry_md_spec_t _gcry_digest_spec_cmac_aes =
+  {
+    GCRY_MD_CMAC_AES, {0, 0},
+    "CMAC_AES", NULL, 0, NULL, 16,
+    NULL, cmac_write, cmac_final, cmac_read,
+    sizeof (struct cmac_context)
+  };
+#endif
+
+#ifdef USE_DES
+gcry_md_spec_t _gcry_digest_spec_cmac_3des =
+  {
+    GCRY_MD_CMAC_3DES, {0, 0},
+    "CMAC_3DES", NULL, 0, NULL, 8,
+    NULL, cmac_write, cmac_final, cmac_read,
+    sizeof (struct cmac_context)
+  };
+#endif
+
+#ifdef USE_CAMELLIA
+gcry_md_spec_t _gcry_digest_spec_cmac_camellia =
+  {
+    GCRY_MD_CMAC_CAMELLIA, {0, 0},
+    "CMAC_CAMELLIA", NULL, 0, NULL, 16,
+    NULL, cmac_write, cmac_final, cmac_read,
+    sizeof (struct cmac_context)
+  };
+#endif
diff --git a/cipher/md.c b/cipher/md.c
index 5c66397..fab73db 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -76,6 +76,16 @@ static gcry_md_spec_t *digest_list[] =
 #if USE_MD4
      &_gcry_digest_spec_md4,
 #endif
+/* CMAC algorithms. */
+#if USE_AES
+     &_gcry_digest_spec_cmac_aes,
+#endif
+#if USE_DES
+     &_gcry_digest_spec_cmac_3des,
+#endif
+#if USE_CAMELLIA
+     &_gcry_digest_spec_cmac_camellia,
+#endif
     NULL
   };
 
@@ -97,6 +107,7 @@ struct gcry_md_context
   int  secure;
   FILE  *debug;
   int finalized;
+  int is_cmac;
   GcryDigestEntry *list;
   byte *macpads;
   int macpads_Bsize;             /* Blocksize as used for the HMAC pads. */
@@ -118,6 +129,16 @@ static void md_stop_debug ( gcry_md_hd_t a );
 
 

 static int
+is_algo_cmac(int algo)
+{
+  return algo == GCRY_MD_CMAC_AES ||
+         algo == GCRY_MD_CMAC_3DES ||
+         algo == GCRY_MD_CMAC_CAMELLIA;
+}
+
+
+

+static int
 map_algo (int algo)
 {
   return algo;
@@ -371,6 +392,8 @@ gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
 
   if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)))
     err = GPG_ERR_INV_ARG;
+  else if ((flags & GCRY_MD_FLAG_HMAC) && is_algo_cmac(algo))
+    err = GPG_ERR_INV_ARG;
   else
     {
       err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE),
@@ -382,7 +405,6 @@ gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
 }
 
 
-
 static gcry_err_code_t
 md_enable (gcry_md_hd_t hd, int algorithm)
 {
@@ -391,6 +413,12 @@ md_enable (gcry_md_hd_t hd, int algorithm)
   GcryDigestEntry *entry;
   gcry_err_code_t err = 0;
 
+  if (h->list != NULL && (h->is_cmac || is_algo_cmac(algorithm)))
+    return GPG_ERR_DIGEST_ALGO; /* Allow only one CMAC.  */
+
+  if (!h->is_cmac && is_algo_cmac(algorithm))
+    h->is_cmac = 1;
+
   for (entry = h->list; entry; entry = entry->next)
     if (entry->spec->algo == algorithm)
       return 0; /* Already enabled */
@@ -436,7 +464,10 @@ md_enable (gcry_md_hd_t hd, int algorithm)
 	  h->list = entry;
 
 	  /* And init this instance. */
-	  entry->spec->init (&entry->context.c);
+	  if (h->is_cmac)
+            err = _gcry_cmac_init (&entry->context.c, algorithm, h->secure);
+          else
+	    entry->spec->init (&entry->context.c);
 	}
     }
 
@@ -520,8 +551,17 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
 
           memcpy (br, ar, (sizeof (*br) + ar->spec->contextsize
                            - sizeof (ar->context)));
+
           br->next = b->list;
           b->list = br;
+
+          if (a->is_cmac)
+            {
+              err = _gcry_cmac_copy_context (br->context.c, ar->context.c);
+              if (err)
+                md_close (bhd);
+              break; /* Only one CMAC. */
+            }
         }
     }
 
@@ -560,6 +600,13 @@ gcry_md_reset (gcry_md_hd_t a)
 
   a->bufpos = a->ctx->finalized = 0;
 
+  if (a->ctx->is_cmac && a->ctx->list)
+    {
+      r = a->ctx->list;
+      _gcry_cmac_reset (&r->context.c);
+      return;
+    }
+
   for (r = a->ctx->list; r; r = r->next)
     {
       memset (r->context.c, 0, r->spec->contextsize);
@@ -579,6 +626,13 @@ md_close (gcry_md_hd_t a)
     return;
   if (a->ctx->debug)
     md_stop_debug (a);
+
+  if (a->ctx->is_cmac && a->ctx->list)
+    {
+      r = a->ctx->list;
+      _gcry_cmac_close (&r->context.c);
+    }
+
   for (r = a->ctx->list; r; r = r2)
     {
       r2 = r->next;
@@ -742,7 +796,12 @@ gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
 {
   gcry_err_code_t rc;
 
-  if (!hd->ctx->macpads)
+  if (hd->ctx->is_cmac && hd->ctx->list)
+    {
+      GcryDigestEntry *r = hd->ctx->list;
+      rc = _gcry_cmac_setkey (&r->context.c, key, keylen);
+    }
+  else if (!hd->ctx->macpads)
     rc = GPG_ERR_CONFLICT;
   else
     {
@@ -885,6 +944,8 @@ gcry_md_hash_buffer (int algo, void *digest,
    this function into a HMAC function; the first item in IOV is then
    used as the key.
 
+   For CMAC functions, the first item in IOV is used as the key.
+
    On success 0 is returned and resulting hash or HMAC is stored at
    DIGEST which must have been provided by the caller with an
    appropriate length.  */
@@ -892,7 +953,7 @@ gpg_err_code_t
 gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
                       const gcry_buffer_t *iov, int iovcnt)
 {
-  int hmac;
+  int hmac, cmac;
 
   if (!iov || iovcnt < 0)
     return GPG_ERR_INV_ARG;
@@ -900,7 +961,10 @@ gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
     return GPG_ERR_INV_ARG;
 
   hmac = !!(flags & GCRY_MD_FLAG_HMAC);
-  if (hmac && iovcnt < 1)
+  cmac = is_algo_cmac(algo);
+  if (hmac && cmac)
+    return GPG_ERR_INV_ARG;
+  if ((hmac || cmac) && iovcnt < 1)
     return GPG_ERR_INV_ARG;
 
   if (algo == GCRY_MD_SHA1 && !hmac)
@@ -927,7 +991,7 @@ gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
       if (rc)
         return rc;
 
-      if (hmac)
+      if (hmac || cmac)
         {
           rc = gcry_err_code
             (gcry_md_setkey (h, (const char*)iov[0].data + iov[0].off,
diff --git a/src/cipher.h b/src/cipher.h
index 551dc66..a7796b8 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -94,6 +94,18 @@ void _gcry_sha1_hash_buffer (void *outbuf,
 void _gcry_sha1_hash_buffers (void *outbuf,
                               const gcry_buffer_t *iov, int iovcnt);
 
+/*-- cmac.c --*/
+gcry_err_code_t _gcry_cmac_init (void *_ctx, int md_algo, int secure);
+
+void _gcry_cmac_close (void *_ctx);
+
+gcry_err_code_t _gcry_cmac_reset (void *_ctx);
+
+gcry_err_code_t _gcry_cmac_copy_context (void *_new_ctx, void *_old_ctx);
+
+gcry_error_t _gcry_cmac_setkey (void *_ctx, const byte *key,
+				unsigned int keylen);
+
 /*-- rijndael.c --*/
 void _gcry_aes_cfb_enc (void *context, unsigned char *iv,
                         void *outbuf, const void *inbuf,
@@ -233,6 +245,9 @@ extern gcry_md_spec_t _gcry_digest_spec_tiger;
 extern gcry_md_spec_t _gcry_digest_spec_tiger1;
 extern gcry_md_spec_t _gcry_digest_spec_tiger2;
 extern gcry_md_spec_t _gcry_digest_spec_whirlpool;
+extern gcry_md_spec_t _gcry_digest_spec_cmac_aes;
+extern gcry_md_spec_t _gcry_digest_spec_cmac_3des;
+extern gcry_md_spec_t _gcry_digest_spec_cmac_camellia;
 
 /* Declarations for the pubkey cipher specifications.  */
 extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 2d27fdb..ffe03f3 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1127,7 +1127,11 @@ enum gcry_md_algos
     GCRY_MD_TIGER2        = 307, /* TIGER2 variant.   */
     GCRY_MD_GOSTR3411_94  = 308, /* GOST R 34.11-94.  */
     GCRY_MD_STRIBOG256    = 309, /* GOST R 34.11-2012, 256 bit.  */
-    GCRY_MD_STRIBOG512    = 310  /* GOST R 34.11-2012, 512 bit.  */
+    GCRY_MD_STRIBOG512    = 310, /* GOST R 34.11-2012, 512 bit.  */
+    /* CMAC algorithms */
+    GCRY_MD_CMAC_AES      = 311,
+    GCRY_MD_CMAC_3DES     = 312,
+    GCRY_MD_CMAC_CAMELLIA = 313,
   };
 
 /* Flags used with the open function.  */
diff --git a/tests/basic.c b/tests/basic.c
index f89895a..0142979 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -3957,8 +3957,8 @@ check_digests (void)
 }
 
 static void
-check_one_hmac (int algo, const char *data, int datalen,
-		const char *key, int keylen, const char *expect)
+check_one_md_mac (int algo, int flags, const char *data, int datalen,
+		  const char *key, int keylen, const char *expect)
 {
   gcry_md_hd_t hd, hd2;
   unsigned char *p;
@@ -3966,7 +3966,7 @@ check_one_hmac (int algo, const char *data, int datalen,
   int i;
   gcry_error_t err = 0;
 
-  err = gcry_md_open (&hd, algo, GCRY_MD_FLAG_HMAC);
+  err = gcry_md_open (&hd, algo, flags);
   if (err)
     {
       fail ("algo %d, gcry_md_open failed: %s\n", algo, gpg_strerror (err));
@@ -4013,30 +4013,33 @@ check_one_hmac (int algo, const char *data, int datalen,
 }
 
 static void
-check_hmac (void)
+check_md_mac (void)
 {
   static const struct algos
   {
     int md;
+    int flags;
     const char *data;
     const char *key;
     const char *expect;
   } algos[] =
     {
-      { GCRY_MD_MD5, "what do ya want for nothing?", "Jefe",
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
+	"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,
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
 	"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,
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
 	"\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,
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4044,10 +4047,12 @@ check_hmac (void)
 	"\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",
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
+	"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",
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
+	"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"
@@ -4055,7 +4060,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_MD5, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4064,16 +4069,18 @@ check_hmac (void)
 	"\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",
+      { GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC,
+	"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,
+      { GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC,
 	"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,
+      { GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4082,7 +4089,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4091,7 +4098,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4104,7 +4111,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4117,16 +4124,18 @@ check_hmac (void)
 	"\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",
+      { GCRY_MD_SHA224, GCRY_MD_FLAG_HMAC,
+	"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,
+      { GCRY_MD_SHA224, GCRY_MD_FLAG_HMAC,
 	"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,
+      { GCRY_MD_SHA224, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4135,7 +4144,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA224, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4144,7 +4153,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA224, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4157,7 +4166,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA224, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4170,18 +4179,19 @@ check_hmac (void)
 	"\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",
+      { GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC,
+	"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,
+      { GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC,
 	"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,
+      { GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4191,7 +4201,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4201,7 +4211,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4215,7 +4225,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4229,12 +4239,14 @@ check_hmac (void)
 	"\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",
+      { GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC,
+	"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,
+      { GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC,
 	"Hi There",
 	"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
 	"\x0b\x0b\x0b",
@@ -4242,7 +4254,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4253,7 +4265,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC,
 	"\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"
@@ -4264,7 +4276,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4279,7 +4291,7 @@ check_hmac (void)
 	"\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,
+      { GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC,
 	"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"
@@ -4294,6 +4306,146 @@ check_hmac (void)
 	"\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" },
+      /* CMAC AES and DES test vectors from
+         http://web.archive.org/web/20130930212819/http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf */
+      { GCRY_MD_CMAC_AES, 0,
+	"",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\xbb\x1d\x69\x29\xe9\x59\x37\x28\x7f\xa3\x7d\x12\x9b\x75\x67\x46" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\x07\x0a\x16\xb4\x6b\x4d\x41\x44\xf7\x9b\xdd\x9d\xd0\x4a\x28\x7c" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+	"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\xdf\xa6\x67\x47\xde\x9a\xe6\x30\x30\xca\x32\x61\x14\x97\xc8\x27" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+	"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+	"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\x51\xf0\xbe\xbf\x7e\x3b\x9d\x92\xfc\x49\x74\x17\x79\x36\x3c\xfe" },
+      { GCRY_MD_CMAC_AES, 0,
+	"",
+	"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+	"\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+	"\xd1\x7d\xdf\x46\xad\xaa\xcd\xe5\x31\xca\xc4\x83\xde\x7a\x93\x67" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+	"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+	"\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+	"\x9e\x99\xa7\xbf\x31\xe7\x10\x90\x06\x62\xf6\x5e\x61\x7c\x51\x84" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+	"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
+	"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+	"\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+	"\x8a\x1d\xe5\xbe\x2e\xb3\x1a\xad\x08\x9a\x82\xe6\xee\x90\x8b\x0e" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+	"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+	"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+	"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+	"\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+	"\xa1\xd5\xdf\x0e\xed\x79\x0f\x79\x4d\x77\x58\x96\x59\xf3\x9a\x11" },
+      { GCRY_MD_CMAC_AES, 0,
+	"",
+	"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+	"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+	"\x02\x89\x62\xf6\x1b\x7b\xf8\x9e\xfc\x6b\x55\x1f\x46\x67\xd9\x83" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+	"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+	"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+	"\x28\xa7\x02\x3f\x45\x2e\x8f\x82\xbd\x4b\xf2\x8d\x8c\x37\xc3\x5c" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+	"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
+	"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+	"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+	"\xaa\xf3\xd8\xf1\xde\x56\x40\xc2\x32\xf5\xb1\x69\xb9\xc9\x11\xe6" },
+      { GCRY_MD_CMAC_AES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+	"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+	"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+	"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+	"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+	"\xe1\x99\x21\x90\x54\x9f\x6e\xd5\x69\x6a\x2c\x05\x6c\x31\x54\x10" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"",
+	"\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
+	"\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5",
+	"\xb7\xa6\x88\xe1\x22\xff\xaf\x95" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96",
+	"\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
+	"\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5",
+	"\x8e\x8f\x29\x31\x36\x28\x37\x97" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57",
+	"\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
+	"\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5",
+	"\x74\x3d\xdb\xe0\xce\x2d\xc2\xed" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+	"\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
+	"\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5",
+	"\x33\xe6\xb1\x09\x24\x00\xea\xe5" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"",
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38"
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5",
+	"\xbd\x2e\xbf\x9a\x3b\xa0\x03\x61" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96",
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38"
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5",
+	"\x4f\xf2\xab\x81\x3c\x53\xce\x83" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57",
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38"
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5",
+	"\x62\xdd\x1b\x47\x19\x02\xbd\x4e" },
+      { GCRY_MD_CMAC_3DES, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+	"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38"
+	"\x4c\xf1\x51\x34\xa2\x85\x0d\xd5",
+	"\x31\xb1\xe4\x31\xda\xbc\x4e\xb8" },
+      /* CMAC Camellia test vectors from
+         http://tools.ietf.org/html/draft-kato-ipsec-camellia-cmac96and128-05 */
+      { GCRY_MD_CMAC_CAMELLIA, 0,
+	"",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\xba\x92\x57\x82\xaa\xa1\xf5\xd9\xa0\x0f\x89\x64\x80\x94\xfc\x71" },
+      { GCRY_MD_CMAC_CAMELLIA, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\x6d\x96\x28\x54\xa3\xb9\xfd\xa5\x6d\x7d\x45\xa9\x5e\xe1\x79\x93" },
+      { GCRY_MD_CMAC_CAMELLIA, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+        "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\x5c\x18\xd1\x19\xcc\xd6\x76\x61\x44\xac\x18\x66\x13\x1d\x9f\x22" },
+      { GCRY_MD_CMAC_CAMELLIA, 0,
+	"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+        "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+        "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+	"\xc2\x69\x9a\x6e\xba\x55\xce\x9d\x93\x9a\x8a\x4e\x19\x46\x6e\xe9" },
       {	0 },
     };
   int i;
@@ -4318,14 +4470,14 @@ check_hmac (void)
 		 algos[i].md,
 		 strlen(algos[i].key), 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);
+      check_one_md_mac (algos[i].md, algos[i].flags, 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 hash value which
@@ -5282,7 +5434,7 @@ main (int argc, char **argv)
       check_cipher_modes ();
       check_bulk_cipher_modes ();
       check_digests ();
-      check_hmac ();
+      check_md_mac ();
       check_pubkey ();
     }
 
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 8326ab2..7d4d2bb 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -328,15 +328,19 @@ md_bench ( const char *algoname )
 {
   int algo;
   gcry_md_hd_t hd;
-  int i, j, repcount;
+  int i, j, repcount, cmac;
   char buf_base[1000+15];
   size_t bufsize = 1000;
   char *buf;
   char *largebuf_base;
   char *largebuf;
   char digest[512/8];
+  unsigned int keylen;
+  char key[192/8];
   gcry_error_t err = GPG_ERR_NO_ERROR;
 
+  cmac = 0;
+
   if (!algoname)
     {
       for (i=1; i < 400; i++)
@@ -366,7 +370,25 @@ md_bench ( const char *algoname )
   for (i=0; i < bufsize; i++)
     buf[i] = i;
 
-  printf ("%-12s", gcry_md_algo_name (algo));
+  printf ("%-13s", gcry_md_algo_name (algo));
+
+  /* CMAC algorithms require key.  */
+  if (algo == GCRY_MD_CMAC_AES ||
+      algo == GCRY_MD_CMAC_3DES ||
+      algo == GCRY_MD_CMAC_CAMELLIA)
+    {
+      keylen = ((algo == GCRY_MD_CMAC_3DES) ? 192 : 128) / 8;
+      cmac = 1;
+      for (i = 0; i < keylen; i++)
+        key[i] = i ^ 0xff;
+      err = gcry_md_setkey (hd, key, keylen);
+      if (err)
+        {
+          fprintf (stderr, PGM ": could not set key for CMAC algorithm `%s'\n",
+		   algoname);
+          exit (1);
+        }
+    }
 
   start_timer ();
   for (repcount=0; repcount < hash_repetitions; repcount++)
@@ -423,11 +445,32 @@ md_bench ( const char *algoname )
 
   for (i=0; i < 10000; i++)
     largebuf[i] = i;
-  start_timer ();
-  for (repcount=0; repcount < hash_repetitions; repcount++)
-    for (i=0; i < 100; i++)
-      gcry_md_hash_buffer (algo, digest, largebuf, 10000);
-  stop_timer ();
+  if (cmac)
+    {
+      gcry_buffer_t iovs[2];
+
+      iovs[0].data = key;
+      iovs[0].off = 0;
+      iovs[0].len = keylen;
+
+      iovs[1].data = largebuf;
+      iovs[1].off = 0;
+      iovs[1].len = 10000;
+
+      start_timer ();
+      for (repcount=0; repcount < hash_repetitions; repcount++)
+        for (i=0; i < 100; i++)
+            gcry_md_hash_buffers (algo, 0, digest, iovs, 2);
+      stop_timer ();
+    }
+  else
+    {
+      start_timer ();
+      for (repcount=0; repcount < hash_repetitions; repcount++)
+        for (i=0; i < 100; i++)
+          gcry_md_hash_buffer (algo, digest, largebuf, 10000);
+      stop_timer ();
+    }
   printf (" %s", elapsed_time ());
   free (largebuf_base);
 




More information about the Gcrypt-devel mailing list