diff options
-rw-r--r-- | cipher/mac-internal.h | 15 | ||||
-rw-r--r-- | cipher/mac-poly1305.c | 174 | ||||
-rw-r--r-- | cipher/mac.c | 5 | ||||
-rw-r--r-- | src/gcrypt.h.in | 7 | ||||
-rw-r--r-- | tests/basic.c | 33 | ||||
-rw-r--r-- | tests/bench-slope.c | 13 | ||||
-rw-r--r-- | tests/benchmark.c | 12 |
7 files changed, 244 insertions, 15 deletions
diff --git a/cipher/mac-internal.h b/cipher/mac-internal.h index 81b6185d..f65a8ae5 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 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 diff --git a/cipher/mac.c b/cipher/mac.c index e5833696..30117b9e 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 8648e960..31450203 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 cc0f4c18..de106175 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 3d8ae378..a911ef85 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 9fd716dd..042e7214 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 (); |