[PATCH] Add GMAC to MAC API

Jussi Kivilinna jussi.kivilinna at iki.fi
Fri Nov 22 13:20:13 CET 2013


* cipher/Makefile.am: Add 'mac-gmac.c'.
* cipher/mac-gmac.c: New.
* cipher/mac-internal.h (gcry_mac_handle): Add 'u.gcm'.
(_gcry_mac_type_spec_gmac_aes, _gcry_mac_type_spec_gmac_twofish)
(_gcry_mac_type_spec_gmac_serpent, _gcry_mac_type_spec_gmac_seed)
(_gcry_mac_type_spec_gmac_camellia): New externs.
* cipher/mac.c (mac_list): Add GMAC specifications.
* doc/gcrypt.texi: Add mention of GMAC.
* src/gcrypt.h.in (gcry_mac_algos): Add GCM algorithms.
* tests/basic.c (check_one_mac): Add support for MAC IVs.
(check_mac): Add support for MAC IVs and add GMAC test vectors.
* tests/bench-slope.c (mac_bench): Iterate algorithm numbers to 499.
* tests/benchmark.c (mac_bench): Iterate algorithm numbers to 499.
--

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/Makefile.am    |    2 -
 cipher/mac-gmac.c     |  184 +++++++++++++++++++++++++++++++++++++++++++++++++
 cipher/mac-internal.h |   23 ++++++
 cipher/mac.c          |    5 +
 doc/gcrypt.texi       |   34 +++++++--
 src/gcrypt.h.in       |    8 ++
 tests/basic.c         |   57 ++++++++++++++-
 tests/bench-slope.c   |    2 -
 tests/benchmark.c     |    2 -
 9 files changed, 302 insertions(+), 15 deletions(-)
 create mode 100644 cipher/mac-gmac.c

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index e29b28d..ff9deca 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -45,7 +45,7 @@ cipher-selftest.c cipher-selftest.h \
 pubkey.c pubkey-internal.h pubkey-util.c \
 md.c \
 mac.c mac-internal.h \
-mac-hmac.c mac-cmac.c \
+mac-hmac.c mac-cmac.c mac-gmac.c \
 kdf.c kdf-internal.h \
 hmac-tests.c \
 bithelp.h  \
diff --git a/cipher/mac-gmac.c b/cipher/mac-gmac.c
new file mode 100644
index 0000000..5b7313f
--- /dev/null
+++ b/cipher/mac-gmac.c
@@ -0,0 +1,184 @@
+/* mac-gmac.c  -  GMAC glue for MAC API
+ * 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 <errno.h>
+
+#include "g10lib.h"
+#include "cipher.h"
+#include "./mac-internal.h"
+
+
+static int
+map_mac_algo_to_cipher (int mac_algo)
+{
+  switch (mac_algo)
+    {
+    default:
+      return GCRY_CIPHER_NONE;
+    case GCRY_MAC_GMAC_AES:
+      return GCRY_CIPHER_AES;
+    case GCRY_MAC_GMAC_CAMELLIA:
+      return GCRY_CIPHER_CAMELLIA128;
+    case GCRY_MAC_GMAC_TWOFISH:
+      return GCRY_CIPHER_TWOFISH;
+    case GCRY_MAC_GMAC_SERPENT:
+      return GCRY_CIPHER_SERPENT128;
+    case GCRY_MAC_GMAC_SEED:
+      return GCRY_CIPHER_SEED;
+    }
+}
+
+
+static gcry_err_code_t
+gmac_open (gcry_mac_hd_t h)
+{
+  gcry_err_code_t err;
+  gcry_cipher_hd_t hd;
+  int secure = (h->magic == CTX_MAGIC_SECURE);
+  int cipher_algo;
+  unsigned int flags;
+
+  cipher_algo = map_mac_algo_to_cipher (h->spec->algo);
+  flags = (secure ? GCRY_CIPHER_SECURE : 0);
+
+  err = _gcry_cipher_open_internal (&hd, cipher_algo, GCRY_CIPHER_MODE_GCM,
+                                    flags);
+  if (err)
+    return err;
+
+  h->u.gmac.cipher_algo = cipher_algo;
+  h->u.gmac.ctx = hd;
+  return 0;
+}
+
+
+static void
+gmac_close (gcry_mac_hd_t h)
+{
+  _gcry_cipher_close (h->u.gmac.ctx);
+  h->u.gmac.ctx = NULL;
+}
+
+
+static gcry_err_code_t
+gmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
+{
+  return _gcry_cipher_setkey (h->u.gmac.ctx, key, keylen);
+}
+
+
+static gcry_err_code_t
+gmac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
+{
+  return _gcry_cipher_gcm_setiv (h->u.gmac.ctx, iv, ivlen);
+}
+
+
+static gcry_err_code_t
+gmac_reset (gcry_mac_hd_t h)
+{
+  return gcry_cipher_reset (h->u.gmac.ctx);
+}
+
+
+static gcry_err_code_t
+gmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
+{
+  return _gcry_cipher_gcm_authenticate (h->u.gmac.ctx, buf, buflen);
+}
+
+
+static gcry_err_code_t
+gmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen)
+{
+  if (*outlen > GCRY_GCM_BLOCK_LEN)
+    *outlen = GCRY_GCM_BLOCK_LEN;
+  return _gcry_cipher_gcm_get_tag (h->u.gmac.ctx, outbuf, *outlen);
+}
+
+
+static gcry_err_code_t
+gmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
+{
+  return _gcry_cipher_gcm_check_tag (h->u.gmac.ctx, buf, buflen);
+}
+
+
+static unsigned int
+gmac_get_maclen (int algo)
+{
+  return GCRY_GCM_BLOCK_LEN;
+}
+
+
+static unsigned int
+gmac_get_keylen (int algo)
+{
+  return _gcry_cipher_get_algo_keylen (map_mac_algo_to_cipher (algo));
+}
+
+
+static gcry_mac_spec_ops_t gmac_ops = {
+  gmac_open,
+  gmac_close,
+  gmac_setkey,
+  gmac_setiv,
+  gmac_reset,
+  gmac_write,
+  gmac_read,
+  gmac_verify,
+  gmac_get_maclen,
+  gmac_get_keylen
+};
+
+
+#if USE_AES
+gcry_mac_spec_t _gcry_mac_type_spec_gmac_aes = {
+  GCRY_MAC_GMAC_AES, {0, 1}, "GMAC_AES",
+  &gmac_ops
+};
+#endif
+#if USE_TWOFISH
+gcry_mac_spec_t _gcry_mac_type_spec_gmac_twofish = {
+  GCRY_MAC_GMAC_TWOFISH, {0, 0}, "GMAC_TWOFISH",
+  &gmac_ops
+};
+#endif
+#if USE_SERPENT
+gcry_mac_spec_t _gcry_mac_type_spec_gmac_serpent = {
+  GCRY_MAC_GMAC_SERPENT, {0, 0}, "GMAC_SERPENT",
+  &gmac_ops
+};
+#endif
+#if USE_SEED
+gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed = {
+  GCRY_MAC_GMAC_SEED, {0, 0}, "GMAC_SEED",
+  &gmac_ops
+};
+#endif
+#if USE_CAMELLIA
+gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia = {
+  GCRY_MAC_GMAC_CAMELLIA, {0, 0}, "GMAC_CAMELLIA",
+  &gmac_ops
+};
+#endif
diff --git a/cipher/mac-internal.h b/cipher/mac-internal.h
index 146b218..2a5e7c6 100644
--- a/cipher/mac-internal.h
+++ b/cipher/mac-internal.h
@@ -103,6 +103,10 @@ struct gcry_mac_handle
       int cipher_algo;
       unsigned int blklen;
     } cmac;
+    struct {
+      gcry_cipher_hd_t ctx;
+      int cipher_algo;
+    } gmac;
   } u;
 };
 
@@ -180,3 +184,22 @@ extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_idea;
 #if USE_GOST28147
 extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_gost28147;
 #endif
+
+/*
+ * The GMAC algorithm specifications (mac-gmac.c).
+ */
+#if USE_AES
+extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_aes;
+#endif
+#if USE_TWOFISH
+extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_twofish;
+#endif
+#if USE_SERPENT
+extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_serpent;
+#endif
+#if USE_SEED
+extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed;
+#endif
+#if USE_CAMELLIA
+extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia;
+#endif
diff --git a/cipher/mac.c b/cipher/mac.c
index 8d1dec0..5ac8729 100644
--- a/cipher/mac.c
+++ b/cipher/mac.c
@@ -74,21 +74,26 @@ static gcry_mac_spec_t *mac_list[] = {
 #endif
 #if USE_AES
   &_gcry_mac_type_spec_cmac_aes,
+  &_gcry_mac_type_spec_gmac_aes,
 #endif
 #if USE_TWOFISH
   &_gcry_mac_type_spec_cmac_twofish,
+  &_gcry_mac_type_spec_gmac_twofish,
 #endif
 #if USE_SERPENT
   &_gcry_mac_type_spec_cmac_serpent,
+  &_gcry_mac_type_spec_gmac_serpent,
 #endif
 #if USE_RFC2268
   &_gcry_mac_type_spec_cmac_rfc2268,
 #endif
 #if USE_SEED
   &_gcry_mac_type_spec_cmac_seed,
+  &_gcry_mac_type_spec_gmac_seed,
 #endif
 #if USE_CAMELLIA
   &_gcry_mac_type_spec_cmac_camellia,
+  &_gcry_mac_type_spec_gmac_camellia,
 #endif
 #ifdef USE_IDEA
   &_gcry_mac_type_spec_cmac_idea,
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 1f6ceec..4870a1c 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3529,6 +3529,26 @@ block cipher algorithm.
 This is CMAC message authentication algorithm based on the GOST 28147-89
 block cipher algorithm.
 
+ at item GCRY_MAC_GMAC_AES
+This is GMAC (GCM mode based MAC) message authentication algorithm based on
+the AES block cipher algorithm.
+
+ at item GCRY_MAC_GMAC_CAMELLIA
+This is GMAC message authentication algorithm based on the Camellia
+block cipher algorithm.
+
+ at item GCRY_MAC_GMAC_TWOFISH
+This is GMAC message authentication algorithm based on the Twofish
+block cipher algorithm.
+
+ at item GCRY_MAC_GMAC_SERPENT
+This is GMAC message authentication algorithm based on the Serpent
+block cipher algorithm.
+
+ at item GCRY_MAC_GMAC_SEED
+This is GMAC message authentication algorithm based on the SEED
+block cipher algorithm.
+
 @end table
 @c end table of MAC algorithms
 
@@ -3574,13 +3594,13 @@ underlying block cipher.
 @end deftypefun
 
 
- at c Some MAC algorithms need initialization vector to be set, which can be
- at c performed with function:
- at c @c
- at c @deftypefun gcry_error_t gcry_mac_setiv (gcry_mac_hd_t @var{h}, const void *@var{iv}, size_t @var{ivlen})
- at c @c
- at c Set the IV to the value of @var{iv} of length @var{ivlen} bytes.
- at c @end deftypefun
+GMAC algorithms need initialization vector to be set, which can be
+performed with function:
+
+ at deftypefun gcry_error_t gcry_mac_setiv (gcry_mac_hd_t @var{h}, const void *@var{iv}, size_t @var{ivlen})
+
+Set the IV to the value of @var{iv} of length @var{ivlen} bytes.
+ at end deftypefun
 
 
 After you are done with the MAC calculation, you should release the resources
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 24f7af6..625fa9f 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1325,7 +1325,13 @@ enum gcry_mac_algos
     GCRY_MAC_CMAC_SEED          = 208,
     GCRY_MAC_CMAC_RFC2268       = 209,
     GCRY_MAC_CMAC_IDEA          = 210,
-    GCRY_MAC_CMAC_GOST28147     = 211
+    GCRY_MAC_CMAC_GOST28147     = 211,
+
+    GCRY_MAC_GMAC_AES           = 401,
+    GCRY_MAC_GMAC_CAMELLIA      = 402,
+    GCRY_MAC_GMAC_TWOFISH       = 403,
+    GCRY_MAC_GMAC_SERPENT       = 404,
+    GCRY_MAC_GMAC_SEED          = 405
   };
 
 /* Flags used with the open function.  */
diff --git a/tests/basic.c b/tests/basic.c
index a205f48..789297f 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -4450,8 +4450,8 @@ check_hmac (void)
 
 static void
 check_one_mac (int algo, const char *data, int datalen,
-	       const char *key, int keylen, const char *expect,
-	       int test_buffering)
+	       const char *key, int keylen, const char *iv, int ivlen,
+	       const char *expect, int test_buffering)
 {
   gcry_mac_hd_t hd;
   unsigned char *p;
@@ -4487,6 +4487,16 @@ check_one_mac (int algo, const char *data, int datalen,
   if (err)
     goto out;
 
+  if (ivlen && iv)
+    {
+      err = gcry_mac_setiv (hd, iv, ivlen);
+      if (err)
+        fail("algo %d, mac gcry_mac_ivkey failed: %s\n", algo,
+             gpg_strerror (err));
+      if (err)
+        goto out;
+    }
+
   if (test_buffering)
     {
       for (i = 0; i < datalen; i++)
@@ -4550,6 +4560,7 @@ check_mac (void)
     const char *data;
     const char *key;
     const char *expect;
+    const char *iv;
   } algos[] =
     {
       { GCRY_MAC_HMAC_MD5, "what do ya want for nothing?", "Jefe",
@@ -4964,6 +4975,42 @@ check_mac (void)
         "\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" },
+      /* http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip */
+      { GCRY_MAC_GMAC_AES,
+        "",
+        "\x11\x75\x4c\xd7\x2a\xec\x30\x9b\xf5\x2f\x76\x87\x21\x2e\x89\x57",
+        "\x25\x03\x27\xc6\x74\xaa\xf4\x77\xae\xf2\x67\x57\x48\xcf\x69\x71",
+        "\x3c\x81\x9d\x9a\x9b\xed\x08\x76\x15\x03\x0b\x65" },
+      { GCRY_MAC_GMAC_AES,
+        "\x2b\x63\x26\x64\x29\x67\x4a\xb5\xe2\xea\xff\x63\x9c\x23\x14\x66"
+        "\x2f\x92\x57\x4b\x29\x8f\x57\x7a\xcf\x7d\x6f\x99\x1a\x87\x92\x1f"
+        "\xc2\x32\xea\xfc\xc7\xb1\x46\x48\x96\x63\x2d\x6c\x8a\xbe\x88\xc2"
+        "\xcc\xa4\x04\xdb\xf8\x7c\x20\x6a\x19\xd3\x73\xed\x99\x50\x17\x34"
+        "\x69\x13\x4d\x7c\x14\xc2\x84\x7d\xf2\x4a\x88\xc1\xc5\x3b\x4d\xe4"
+        "\x9d\xb3\x66\x39\x2b\x6d\xc6\x51\x27\x6e",
+        "\x0f\x3b\x17\xde\xae\x62\x13\x64\x55\x4a\xe5\x39\xdb\x09\xde\x11",
+        "\xff\xb0\xbb\x6d\xfc\x23\x58\x75\x4f\x17\x78\x48\x5b\x59\x65\x7f",
+        "\xa7\xf6\x07\x4c\xda\x56\x1c\xd2\xaa\x15\xba\x8c\x2f\xa6\x39\x42"
+        "\x59\x3e\x7c\xcf\x45\xc2\x9a\x57\xda\xd8\xa6\xe2\xea\x63\x54\xce"
+        "\x8a\xde\x39\xdd\xde\x4a\xc4\x5b\xbd\xc6\x63\xf0\xa5\x37\xc9\x48"
+        "\x18\x23\x5a\x73\xd8\xa0\x8b\xd8\x98\xab\xd0\x99\xe1\x5c\x08\x8c"
+        "\x6e\x21\x17\x5a\xf4\xe9\xa4\x99\x70\x12\x82\xed\x32\x81\x50\xa6"
+        "\xd9\x90\xe8\xec\x87\x85\xce\x26\x1b\xe1\xb8\x3f\xd8\x59\x1e\x57"
+        "\x76\x5f\x3d\xc1\x11\x3f\xd0\x2a\x40\xf5\x01\x6a\xd0\xd0\xed\xc4"
+        "\x92\x9a\x02\xe0\x17\xb2\xc5\xf4\x18\xd2\x96\xab\xd6\xc2\xea\x2e" },
+      { GCRY_MAC_GMAC_AES,
+        "\x61\x14\x60\x11\x90\xf6\xef\x5e\x59\x23\x5d\xc0\x42\x8c\x09\xe3"
+        "\x27\x0b\x19\xea",
+        "\x15\xa4\x14\x46\x6a\x7f\x90\xea\x32\xbf\xd7\xf6\xe5\x8b\xfa\x06"
+        "\xe9\x07\xfc\x41\x66\x89\xd9\x60\x39\x45\xd7\x94\x54\xd4\x23\x17",
+        "\x19\x6e\x0e\x01\x0f\x08\x56\xf9\x82\xb4\x08\x92\x41\xd6\x24\x84",
+        "\xab" },
+      { GCRY_MAC_GMAC_AES,
+        "\x8b\x5c\x12\x4b\xef\x6e\x2f\x0f\xe4\xd8\xc9\x5c\xd5\xfa\x4c\xf1",
+        "\x41\xc5\xda\x86\x67\xef\x72\x52\x20\xff\xe3\x9a\xe0\xac\x59\x0a"
+        "\xc9\xfc\xa7\x29\xab\x60\xad\xa0",
+        "\x20\x4b\xdb\x1b\xd6\x21\x54\xbf\x08\x92\x2a\xaa\x54\xee\xd7\x05",
+        "\x05\xad\x13\xa5\xe2\xc2\xab\x66\x7e\x1a\x6f\xbc" },
       { 0 },
     };
   int i;
@@ -4989,10 +5036,12 @@ check_mac (void)
 		 strlen(algos[i].key), strlen(algos[i].data));
 
       check_one_mac (algos[i].algo, algos[i].data, strlen (algos[i].data),
-		     algos[i].key, strlen(algos[i].key),
+		     algos[i].key, strlen(algos[i].key), algos[i].iv,
+		     algos[i].iv ? strlen(algos[i].iv) : 0,
 		     algos[i].expect, 0);
       check_one_mac (algos[i].algo, algos[i].data, strlen (algos[i].data),
-		     algos[i].key, strlen(algos[i].key),
+		     algos[i].key, strlen(algos[i].key), algos[i].iv,
+		     algos[i].iv ? strlen(algos[i].iv) : 0,
 		     algos[i].expect, 1);
     }
 
diff --git a/tests/bench-slope.c b/tests/bench-slope.c
index d29a4ad..fd9f64b 100644
--- a/tests/bench-slope.c
+++ b/tests/bench-slope.c
@@ -1289,7 +1289,7 @@ mac_bench (char **argv, int argc)
     }
   else
     {
-      for (i = 1; i < 400; i++)
+      for (i = 1; i < 500; i++)
 	if (!gcry_mac_test_algo (i))
 	  _mac_bench (i);
     }
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 3058bd5..8bb8584 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -457,7 +457,7 @@ mac_bench ( const char *algoname )
 
   if (!algoname)
     {
-      for (i=1; i < 400; i++)
+      for (i=1; i < 500; i++)
         if (in_fips_mode && i == GCRY_MAC_HMAC_MD5)
           ; /* Don't use MD5 in fips mode.  */
         else if ( !gcry_mac_test_algo (i) )




More information about the Gcrypt-devel mailing list