[PATCH 2/3] Add Poly1305-AES (-Camellia, etc) MACs
Jussi Kivilinna
jussi.kivilinna at iki.fi
Sat May 10 23:56:38 CEST 2014
* cipher/mac-internal.h (_gcry_mac_type_spec_poly1305_aes)
(_gcry_mac_type_spec_poly1305_camellia)
(_gcry_mac_type_spec_poly1305_twofish)
(_gcry_mac_type_spec_poly1305_serpent)
(_gcry_mac_type_spec_poly1305_seed): New.
* cipher/mac-poly1305.c (poly1305mac_context_s): Add 'hd' and
'nonce_set'.
(poly1305mac_open, poly1305mac_close, poly1305mac_setkey): Add handling
for Poly1305-*** MACs.
(poly1305mac_prepare_key, poly1305mac_setiv): New.
(poly1305mac_reset, poly1305mac_write, poly1305mac_read): Add handling
for 'nonce_set'.
(poly1305mac_ops): Add 'poly1305mac_setiv'.
(_gcry_mac_type_spec_poly1305_aes)
(_gcry_mac_type_spec_poly1305_camellia)
(_gcry_mac_type_spec_poly1305_twofish)
(_gcry_mac_type_spec_poly1305_serpent)
(_gcry_mac_type_spec_poly1305_seed): New.
* cipher/mac.c (mac_list): Add Poly1305-AES, Poly1305-Twofish,
Poly1305-Serpent, Poly1305-SEED and Poly1305-Camellia.
* src/gcrypt.h.in: Add 'GCRY_MAC_POLY1305_AES',
'GCRY_MAC_POLY1305_CAMELLIA', 'GCRY_MAC_POLY1305_TWOFISH',
'GCRY_MAC_POLY1305_SERPENT' and 'GCRY_MAC_POLY1305_SEED'.
* tests/basic.c (check_mac): Add Poly1305-AES test vectors.
* tests/bench-slope.c (bench_mac_init): Set IV for Poly1305-*** MACs.
* tests/bench-slope.c (mac_bench): Set IV for Poly1305-*** MACs.
--
Patch adds Bernstein's Poly1305-AES message authentication code to libgcrypt
and other variants of Poly1305-<128-bit block cipher>.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/mac-internal.h | 15 ++++
cipher/mac-poly1305.c | 174 +++++++++++++++++++++++++++++++++++++++++++++----
cipher/mac.c | 5 +
src/gcrypt.h.in | 7 ++
tests/basic.c | 33 +++++++++
tests/bench-slope.c | 13 ++++
tests/benchmark.c | 12 +++
7 files changed, 244 insertions(+), 15 deletions(-)
diff --git a/cipher/mac-internal.h b/cipher/mac-internal.h
index 81b6185..f65a8ae 100644
--- a/cipher/mac-internal.h
+++ b/cipher/mac-internal.h
@@ -217,3 +217,18 @@ extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia;
* The Poly1305 MAC algorithm specifications (mac-poly1305.c).
*/
extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac;
+#if USE_AES
+extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes;
+#endif
+#if USE_CAMELLIA
+extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia;
+#endif
+#if USE_TWOFISH
+extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish;
+#endif
+#if USE_SERPENT
+extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent;
+#endif
+#if USE_SEED
+extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed;
+#endif
diff --git a/cipher/mac-poly1305.c b/cipher/mac-poly1305.c
index e265b64..76b369a 100644
--- a/cipher/mac-poly1305.c
+++ b/cipher/mac-poly1305.c
@@ -30,8 +30,10 @@
struct poly1305mac_context_s {
poly1305_context_t ctx;
+ gcry_cipher_hd_t hd;
struct {
unsigned int key_set:1;
+ unsigned int nonce_set:1;
unsigned int tag:1;
} marks;
byte tag[POLY1305_TAGLEN];
@@ -44,6 +46,9 @@ poly1305mac_open (gcry_mac_hd_t h)
{
struct poly1305mac_context_s *mac_ctx;
int secure = (h->magic == CTX_MAGIC_SECURE);
+ unsigned int flags = (secure ? GCRY_CIPHER_SECURE : 0);
+ gcry_err_code_t err;
+ int cipher_algo;
if (secure)
mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx));
@@ -55,14 +60,71 @@ poly1305mac_open (gcry_mac_hd_t h)
h->u.poly1305mac.ctx = mac_ctx;
+ switch (h->spec->algo)
+ {
+ default:
+ /* already checked. */
+ case GCRY_MAC_POLY1305:
+ /* plain Poly1305. */
+ cipher_algo = -1;
+ return 0;
+ case GCRY_MAC_POLY1305_AES:
+ cipher_algo = GCRY_CIPHER_AES;
+ break;
+ case GCRY_MAC_POLY1305_CAMELLIA:
+ cipher_algo = GCRY_CIPHER_CAMELLIA128;
+ break;
+ case GCRY_MAC_POLY1305_TWOFISH:
+ cipher_algo = GCRY_CIPHER_TWOFISH;
+ break;
+ case GCRY_MAC_POLY1305_SERPENT:
+ cipher_algo = GCRY_CIPHER_SERPENT128;
+ break;
+ case GCRY_MAC_POLY1305_SEED:
+ cipher_algo = GCRY_CIPHER_SEED;
+ break;
+ }
+
+ err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo,
+ GCRY_CIPHER_MODE_ECB, flags);
+ if (err)
+ goto err_free;
+
return 0;
+
+err_free:
+ xfree(h->u.poly1305mac.ctx);
+ return err;
}
static void
poly1305mac_close (gcry_mac_hd_t h)
{
- xfree(h->u.poly1305mac.ctx);
+ struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
+
+ if (h->spec->algo != GCRY_MAC_POLY1305)
+ _gcry_cipher_close (mac_ctx->hd);
+
+ xfree(mac_ctx);
+}
+
+
+static gcry_err_code_t
+poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
+{
+ struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
+ size_t block_keylen = keylen - 16;
+
+ /* Need at least 16 + 1 byte key. */
+ if (keylen <= 16)
+ return GPG_ERR_INV_KEYLEN;
+
+ /* For Poly1305-AES, first part of key is passed to Poly1305 as is. */
+ memcpy (mac_ctx->key, key + block_keylen, 16);
+
+ /* Remaining part is used as key for the block cipher. */
+ return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen);
}
@@ -77,22 +139,74 @@ poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
mac_ctx->marks.key_set = 0;
+ mac_ctx->marks.nonce_set = 0;
mac_ctx->marks.tag = 0;
- if (keylen != POLY1305_KEYLEN)
- return GPG_ERR_INV_KEYLEN;
-
- memcpy(mac_ctx->key, key, POLY1305_KEYLEN);
+ if (h->spec->algo != GCRY_MAC_POLY1305)
+ {
+ err = poly1305mac_prepare_key (h, key, keylen);
+ if (err)
+ return err;
- err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
- if (err)
+ /* Poly1305-AES/etc also need nonce. */
+ mac_ctx->marks.key_set = 1;
+ mac_ctx->marks.nonce_set = 0;
+ }
+ else
{
- memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
- return err;
+ /* For plain Poly1305, key is the nonce and setup is complete now. */
+
+ if (keylen != POLY1305_KEYLEN)
+ return GPG_ERR_INV_KEYLEN;
+
+ memcpy (mac_ctx->key, key, keylen);
+
+ err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
+ if (err)
+ {
+ memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
+ return err;
+ }
+
+ mac_ctx->marks.key_set = 1;
+ mac_ctx->marks.nonce_set = 1;
}
- mac_ctx->marks.key_set = 1;
+ return 0;
+}
+
+
+static gcry_err_code_t
+poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
+{
+ struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
+ gcry_err_code_t err;
+
+ if (h->spec->algo == GCRY_MAC_POLY1305)
+ return GPG_ERR_INV_ARG;
+
+ if (ivlen != 16)
+ return GPG_ERR_INV_ARG;
+ if (!mac_ctx->marks.key_set)
+ return 0;
+
+ memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
+ memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
+ mac_ctx->marks.nonce_set = 0;
+ mac_ctx->marks.tag = 0;
+
+ /* Prepare second part of the poly1305 key. */
+
+ err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16);
+ if (err)
+ return err;
+
+ err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
+ if (err)
+ return err;
+
+ mac_ctx->marks.nonce_set = 1;
return 0;
}
@@ -102,13 +216,14 @@ poly1305mac_reset (gcry_mac_hd_t h)
{
struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
- if (!mac_ctx->marks.key_set)
+ if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
return GPG_ERR_INV_STATE;
memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
mac_ctx->marks.key_set = 1;
+ mac_ctx->marks.nonce_set = 1;
mac_ctx->marks.tag = 0;
return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
@@ -120,7 +235,8 @@ poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
{
struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
- if (!mac_ctx->marks.key_set || mac_ctx->marks.tag)
+ if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set ||
+ mac_ctx->marks.tag)
return GPG_ERR_INV_STATE;
_gcry_poly1305_update (&mac_ctx->ctx, buf, buflen);
@@ -133,7 +249,7 @@ poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen)
{
struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
- if (!mac_ctx->marks.key_set)
+ if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
return GPG_ERR_INV_STATE;
if (!mac_ctx->marks.tag)
@@ -197,7 +313,7 @@ static gcry_mac_spec_ops_t poly1305mac_ops = {
poly1305mac_open,
poly1305mac_close,
poly1305mac_setkey,
- NULL,
+ poly1305mac_setiv,
poly1305mac_reset,
poly1305mac_write,
poly1305mac_read,
@@ -211,3 +327,33 @@ gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = {
GCRY_MAC_POLY1305, {0, 0}, "POLY1305",
&poly1305mac_ops
};
+#if USE_AES
+gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = {
+ GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES",
+ &poly1305mac_ops
+};
+#endif
+#if USE_CAMELLIA
+gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = {
+ GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA",
+ &poly1305mac_ops
+};
+#endif
+#if USE_TWOFISH
+gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = {
+ GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH",
+ &poly1305mac_ops
+};
+#endif
+#if USE_SERPENT
+gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = {
+ GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT",
+ &poly1305mac_ops
+};
+#endif
+#if USE_SEED
+gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = {
+ GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED",
+ &poly1305mac_ops
+};
+#endif
diff --git a/cipher/mac.c b/cipher/mac.c
index e583369..30117b9 100644
--- a/cipher/mac.c
+++ b/cipher/mac.c
@@ -75,14 +75,17 @@ static gcry_mac_spec_t *mac_list[] = {
#if USE_AES
&_gcry_mac_type_spec_cmac_aes,
&_gcry_mac_type_spec_gmac_aes,
+ &_gcry_mac_type_spec_poly1305mac_aes,
#endif
#if USE_TWOFISH
&_gcry_mac_type_spec_cmac_twofish,
&_gcry_mac_type_spec_gmac_twofish,
+ &_gcry_mac_type_spec_poly1305mac_twofish,
#endif
#if USE_SERPENT
&_gcry_mac_type_spec_cmac_serpent,
&_gcry_mac_type_spec_gmac_serpent,
+ &_gcry_mac_type_spec_poly1305mac_serpent,
#endif
#if USE_RFC2268
&_gcry_mac_type_spec_cmac_rfc2268,
@@ -90,10 +93,12 @@ static gcry_mac_spec_t *mac_list[] = {
#if USE_SEED
&_gcry_mac_type_spec_cmac_seed,
&_gcry_mac_type_spec_gmac_seed,
+ &_gcry_mac_type_spec_poly1305mac_seed,
#endif
#if USE_CAMELLIA
&_gcry_mac_type_spec_cmac_camellia,
&_gcry_mac_type_spec_gmac_camellia,
+ &_gcry_mac_type_spec_poly1305mac_camellia,
#endif
#ifdef USE_IDEA
&_gcry_mac_type_spec_cmac_idea,
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 8648e96..3145020 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1343,7 +1343,12 @@ enum gcry_mac_algos
GCRY_MAC_GMAC_SERPENT = 404,
GCRY_MAC_GMAC_SEED = 405,
- GCRY_MAC_POLY1305 = 501
+ GCRY_MAC_POLY1305 = 501,
+ GCRY_MAC_POLY1305_AES = 502,
+ GCRY_MAC_POLY1305_CAMELLIA = 503,
+ GCRY_MAC_POLY1305_TWOFISH = 504,
+ GCRY_MAC_POLY1305_SERPENT = 505,
+ GCRY_MAC_POLY1305_SEED = 506
};
/* Flags used with the open function. */
diff --git a/tests/basic.c b/tests/basic.c
index cc0f4c1..de10617 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -5596,6 +5596,39 @@ check_mac (void)
"\x12\x97\x6a\x08\xc4\x42\x6d\x0c\xe8\xa8\x24\x07\xc4\xf4\x82\x07"
"\x80\xf8\xc2\x0a\xa7\x12\x02\xd1\xe2\x91\x79\xcb\xcb\x55\x5a\x57",
"\x51\x54\xad\x0d\x2c\xb2\x6e\x01\x27\x4f\xc5\x11\x48\x49\x1f\x1b" },
+ /* from http://cr.yp.to/mac/poly1305-20050329.pdf */
+ { GCRY_MAC_POLY1305_AES,
+ "\xf3\xf6",
+ "\xec\x07\x4c\x83\x55\x80\x74\x17\x01\x42\x5b\x62\x32\x35\xad\xd6"
+ "\x85\x1f\xc4\x0c\x34\x67\xac\x0b\xe0\x5c\xc2\x04\x04\xf3\xf7\x00",
+ "\xf4\xc6\x33\xc3\x04\x4f\xc1\x45\xf8\x4f\x33\x5c\xb8\x19\x53\xde",
+ "\xfb\x44\x73\x50\xc4\xe8\x68\xc5\x2a\xc3\x27\x5c\xf9\xd4\x32\x7e",
+ 0, 32 },
+ { GCRY_MAC_POLY1305_AES,
+ "",
+ "\x75\xde\xaa\x25\xc0\x9f\x20\x8e\x1d\xc4\xce\x6b\x5c\xad\x3f\xbf"
+ "\xa0\xf3\x08\x00\x00\xf4\x64\x00\xd0\xc7\xe9\x07\x6c\x83\x44\x03",
+ "\xdd\x3f\xab\x22\x51\xf1\x1a\xc7\x59\xf0\x88\x71\x29\xcc\x2e\xe7",
+ "\x61\xee\x09\x21\x8d\x29\xb0\xaa\xed\x7e\x15\x4a\x2c\x55\x09\xcc",
+ 0, 32 },
+ { GCRY_MAC_POLY1305_AES,
+ "\x66\x3c\xea\x19\x0f\xfb\x83\xd8\x95\x93\xf3\xf4\x76\xb6\xbc\x24"
+ "\xd7\xe6\x79\x10\x7e\xa2\x6a\xdb\x8c\xaf\x66\x52\xd0\x65\x61\x36",
+ "\x6a\xcb\x5f\x61\xa7\x17\x6d\xd3\x20\xc5\xc1\xeb\x2e\xdc\xdc\x74"
+ "\x48\x44\x3d\x0b\xb0\xd2\x11\x09\xc8\x9a\x10\x0b\x5c\xe2\xc2\x08",
+ "\x0e\xe1\xc1\x6b\xb7\x3f\x0f\x4f\xd1\x98\x81\x75\x3c\x01\xcd\xbe",
+ "\xae\x21\x2a\x55\x39\x97\x29\x59\x5d\xea\x45\x8b\xc6\x21\xff\x0e",
+ 0, 32 },
+ { GCRY_MAC_POLY1305_AES,
+ "\xab\x08\x12\x72\x4a\x7f\x1e\x34\x27\x42\xcb\xed\x37\x4d\x94\xd1"
+ "\x36\xc6\xb8\x79\x5d\x45\xb3\x81\x98\x30\xf2\xc0\x44\x91\xfa\xf0"
+ "\x99\x0c\x62\xe4\x8b\x80\x18\xb2\xc3\xe4\xa0\xfa\x31\x34\xcb\x67"
+ "\xfa\x83\xe1\x58\xc9\x94\xd9\x61\xc4\xcb\x21\x09\x5c\x1b\xf9",
+ "\xe1\xa5\x66\x8a\x4d\x5b\x66\xa5\xf6\x8c\xc5\x42\x4e\xd5\x98\x2d"
+ "\x12\x97\x6a\x08\xc4\x42\x6d\x0c\xe8\xa8\x24\x07\xc4\xf4\x82\x07",
+ "\x51\x54\xad\x0d\x2c\xb2\x6e\x01\x27\x4f\xc5\x11\x48\x49\x1f\x1b",
+ "\x9a\xe8\x31\xe7\x43\x97\x8d\x3a\x23\x52\x7c\x71\x28\x14\x9e\x3a",
+ 0, 32 },
{ 0 },
};
int i;
diff --git a/tests/bench-slope.c b/tests/bench-slope.c
index 3d8ae37..a911ef8 100644
--- a/tests/bench-slope.c
+++ b/tests/bench-slope.c
@@ -1316,6 +1316,19 @@ bench_mac_init (struct bench_obj *obj)
exit (1);
}
+ switch (mode->algo)
+ {
+ default:
+ break;
+ case GCRY_MAC_POLY1305_AES:
+ case GCRY_MAC_POLY1305_CAMELLIA:
+ case GCRY_MAC_POLY1305_TWOFISH:
+ case GCRY_MAC_POLY1305_SERPENT:
+ case GCRY_MAC_POLY1305_SEED:
+ gcry_mac_setiv (hd, key, 16);
+ break;
+ }
+
obj->priv = hd;
return 0;
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 9fd716d..042e721 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -509,6 +509,18 @@ mac_bench ( const char *algoname )
for (i=0; i < bufsize; i++)
buf[i] = i;
+ if (algo >= GCRY_MAC_POLY1305_AES && algo <= GCRY_MAC_POLY1305_SEED)
+ {
+ static const char iv[16] = { 1, 2, 3, 4, };
+ err = gcry_mac_setiv(hd, iv, sizeof(iv));
+ if (err)
+ {
+ fprintf (stderr, PGM ": error setting nonce for mac algorithm `%s': %s\n",
+ algoname, gpg_strerror (err));
+ exit (1);
+ }
+ }
+
printf ("%-20s", gcry_mac_algo_name (algo));
start_timer ();
More information about the Gcrypt-devel
mailing list