summaryrefslogtreecommitdiff
path: root/cipher/mac-poly1305.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2014-05-11 12:00:19 +0300
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2014-05-12 20:32:44 +0300
commit73b3b75c2221a6e3bed4117e0a206a1193acd2ed (patch)
tree22728ed20be334cacc83568d9121392a78eb55b7 /cipher/mac-poly1305.c
parentb8794fed68ebe7567f4617141f0996ad290d9120 (diff)
downloadlibgcrypt-73b3b75c2221a6e3bed4117e0a206a1193acd2ed.tar.gz
Add Poly1305-AES (-Camellia, etc) MACs
* 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@iki.fi>
Diffstat (limited to 'cipher/mac-poly1305.c')
-rw-r--r--cipher/mac-poly1305.c174
1 files changed, 160 insertions, 14 deletions
diff --git a/cipher/mac-poly1305.c b/cipher/mac-poly1305.c
index e265b642..76b369ac 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