[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