diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2014-05-11 12:00:19 +0300 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2014-05-12 20:32:43 +0300 |
commit | b8794fed68ebe7567f4617141f0996ad290d9120 (patch) | |
tree | 2fd76ce72117946cbf5991d28c3c10152c62c2e5 | |
parent | c20daeeb05329bfc6cc2c562cbd4b965291fe0e1 (diff) | |
download | libgcrypt-b8794fed68ebe7567f4617141f0996ad290d9120.tar.gz |
Add Poly1305 MAC
* cipher/Makefile.am: Add 'mac-poly1305.c', 'poly1305.c' and
'poly1305-internal.h'.
* cipher/mac-internal.h (poly1305mac_context_s): New.
(gcry_mac_handle): Add 'u.poly1305mac'.
(_gcry_mac_type_spec_poly1305mac): New.
* cipher/mac-poly1305.c: New.
* cipher/mac.c (mac_list): Add Poly1305.
* cipher/poly1305-internal.h: New.
* cipher/poly1305.c: New.
* src/gcrypt.h.in: Add 'GCRY_MAC_POLY1305'.
* tests/basic.c (check_mac): Add Poly1035 test vectors; Allow
overriding lengths of data and key buffers.
* tests/bench-slope.c (mac_bench): Increase max algo number from 500 to
600.
* tests/benchmark.c (mac_bench): Ditto.
--
Patch adds Bernstein's Poly1305 message authentication code to libgcrypt.
Implementation is based on Andrew Moon's public domain implementation
from: https://github.com/floodyberry/poly1305-opt
The algorithm added by this patch is the plain Poly1305 without AES and
takes 32-bit key that must not be reused.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
-rw-r--r-- | cipher/Makefile.am | 3 | ||||
-rw-r--r-- | cipher/mac-internal.h | 17 | ||||
-rw-r--r-- | cipher/mac-poly1305.c | 213 | ||||
-rw-r--r-- | cipher/mac.c | 1 | ||||
-rw-r--r-- | cipher/poly1305-internal.h | 93 | ||||
-rw-r--r-- | cipher/poly1305.c | 766 | ||||
-rw-r--r-- | src/gcrypt.h.in | 4 | ||||
-rw-r--r-- | tests/basic.c | 120 | ||||
-rw-r--r-- | tests/bench-slope.c | 2 | ||||
-rw-r--r-- | tests/benchmark.c | 2 |
10 files changed, 1210 insertions, 11 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 26d13d2b..a8b86e6b 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -45,7 +45,8 @@ 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-gmac.c \ +mac-hmac.c mac-cmac.c mac-gmac.c mac-poly1305.c \ +poly1305.c poly1305-internal.h \ kdf.c kdf-internal.h \ hmac-tests.c \ bithelp.h \ diff --git a/cipher/mac-internal.h b/cipher/mac-internal.h index 9895a548..81b6185d 100644 --- a/cipher/mac-internal.h +++ b/cipher/mac-internal.h @@ -17,9 +17,17 @@ * License along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> + +#include "g10lib.h" + + /* The data object used to hold a handle to an encryption object. */ struct gcry_mac_handle; +/* The data object used to hold poly1305-mac context. */ +struct poly1305mac_context_s; + /* * @@ -84,7 +92,6 @@ typedef struct gcry_mac_spec } gcry_mac_spec_t; - /* The handle structure. */ struct gcry_mac_handle { @@ -106,6 +113,9 @@ struct gcry_mac_handle gcry_cipher_hd_t ctx; int cipher_algo; } gmac; + struct { + struct poly1305mac_context_s *ctx; + } poly1305mac; } u; }; @@ -202,3 +212,8 @@ extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed; #if USE_CAMELLIA extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia; #endif + +/* + * The Poly1305 MAC algorithm specifications (mac-poly1305.c). + */ +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac; diff --git a/cipher/mac-poly1305.c b/cipher/mac-poly1305.c new file mode 100644 index 00000000..e265b642 --- /dev/null +++ b/cipher/mac-poly1305.c @@ -0,0 +1,213 @@ +/* mac-poly1305.c - Poly1305 based MACs + * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@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 "mac-internal.h" +#include "poly1305-internal.h" + + +struct poly1305mac_context_s { + poly1305_context_t ctx; + struct { + unsigned int key_set:1; + unsigned int tag:1; + } marks; + byte tag[POLY1305_TAGLEN]; + byte key[POLY1305_KEYLEN]; +}; + + +static gcry_err_code_t +poly1305mac_open (gcry_mac_hd_t h) +{ + struct poly1305mac_context_s *mac_ctx; + int secure = (h->magic == CTX_MAGIC_SECURE); + + if (secure) + mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx)); + else + mac_ctx = xtrycalloc (1, sizeof(*mac_ctx)); + + if (!mac_ctx) + return gpg_err_code_from_syserror (); + + h->u.poly1305mac.ctx = mac_ctx; + + return 0; +} + + +static void +poly1305mac_close (gcry_mac_hd_t h) +{ + xfree(h->u.poly1305mac.ctx); +} + + +static gcry_err_code_t +poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + gcry_err_code_t err; + + memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); + memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); + memset(&mac_ctx->key, 0, sizeof(mac_ctx->key)); + + mac_ctx->marks.key_set = 0; + mac_ctx->marks.tag = 0; + + if (keylen != POLY1305_KEYLEN) + return GPG_ERR_INV_KEYLEN; + + memcpy(mac_ctx->key, key, POLY1305_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; + + return 0; +} + + +static gcry_err_code_t +poly1305mac_reset (gcry_mac_hd_t h) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + + if (!mac_ctx->marks.key_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.tag = 0; + + return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); +} + + +static gcry_err_code_t +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) + return GPG_ERR_INV_STATE; + + _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen); + return 0; +} + + +static gcry_err_code_t +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) + return GPG_ERR_INV_STATE; + + if (!mac_ctx->marks.tag) + { + _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag); + + memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); + mac_ctx->marks.tag = 1; + } + + if (*outlen <= POLY1305_TAGLEN) + buf_cpy (outbuf, mac_ctx->tag, *outlen); + else + { + buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN); + *outlen = POLY1305_TAGLEN; + } + + return 0; +} + + +static gcry_err_code_t +poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + gcry_err_code_t err; + size_t outlen = 0; + + /* Check and finalize tag. */ + err = poly1305mac_read(h, NULL, &outlen); + if (err) + return err; + + if (buflen > POLY1305_TAGLEN) + return GPG_ERR_INV_LENGTH; + + return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM; +} + + +static unsigned int +poly1305mac_get_maclen (int algo) +{ + (void)algo; + + return POLY1305_TAGLEN; +} + + +static unsigned int +poly1305mac_get_keylen (int algo) +{ + (void)algo; + + return POLY1305_KEYLEN; +} + + +static gcry_mac_spec_ops_t poly1305mac_ops = { + poly1305mac_open, + poly1305mac_close, + poly1305mac_setkey, + NULL, + poly1305mac_reset, + poly1305mac_write, + poly1305mac_read, + poly1305mac_verify, + poly1305mac_get_maclen, + poly1305mac_get_keylen +}; + + +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = { + GCRY_MAC_POLY1305, {0, 0}, "POLY1305", + &poly1305mac_ops +}; diff --git a/cipher/mac.c b/cipher/mac.c index 7805467a..e5833696 100644 --- a/cipher/mac.c +++ b/cipher/mac.c @@ -101,6 +101,7 @@ static gcry_mac_spec_t *mac_list[] = { #if USE_GOST28147 &_gcry_mac_type_spec_cmac_gost28147, #endif + &_gcry_mac_type_spec_poly1305mac, NULL, }; diff --git a/cipher/poly1305-internal.h b/cipher/poly1305-internal.h new file mode 100644 index 00000000..d2c6b5cd --- /dev/null +++ b/cipher/poly1305-internal.h @@ -0,0 +1,93 @@ +/* poly1305-internal.h - Poly1305 internals + * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@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/>. + */ + +#ifndef G10_POLY1305_INTERNAL_H +#define G10_POLY1305_INTERNAL_H + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" + + +#define POLY1305_TAGLEN 16 +#define POLY1305_KEYLEN 32 + + +/* Block-size used in default implementation. */ +#define POLY1305_REF_BLOCKSIZE 16 + +/* State size of default implementation. */ +#define POLY1305_REF_STATESIZE 64 + +/* State alignment for default implementation. */ +#define POLY1305_REF_ALIGNMENT sizeof(void *) + + +/* Largest block-size used in any implementation (optimized implementations + * might use block-size multiple of 16). */ +#define POLY1305_LARGEST_BLOCKSIZE POLY1305_REF_BLOCKSIZE + +/* Largest state-size used in any implementation. */ +#define POLY1305_LARGEST_STATESIZE POLY1305_REF_STATESIZE + +/* Minimum alignment for state pointer passed to implementations. */ +#define POLY1305_STATE_ALIGNMENT POLY1305_REF_ALIGNMENT + + +typedef struct poly1305_key_s +{ + byte b[POLY1305_KEYLEN]; +} poly1305_key_t; + + +typedef struct poly1305_ops_s +{ + size_t block_size; + void (*init_ext) (void *ctx, const poly1305_key_t * key); + unsigned int (*blocks) (void *ctx, const byte * m, size_t bytes); + unsigned int (*finish_ext) (void *ctx, const byte * m, size_t remaining, + byte mac[POLY1305_TAGLEN]); +} poly1305_ops_t; + + +typedef struct poly1305_context_s +{ + byte state[POLY1305_LARGEST_STATESIZE + POLY1305_STATE_ALIGNMENT]; + byte buffer[POLY1305_LARGEST_BLOCKSIZE]; + const poly1305_ops_t *ops; + unsigned int leftover; +} poly1305_context_t; + + +gcry_err_code_t _gcry_poly1305_init (poly1305_context_t * ctx, const byte * key, + size_t keylen); + +void _gcry_poly1305_finish (poly1305_context_t * ctx, + byte mac[POLY1305_TAGLEN]); + +void _gcry_poly1305_update (poly1305_context_t * ctx, const byte * buf, + size_t buflen); + + +#endif /* G10_POLY1305_INTERNAL_H */ diff --git a/cipher/poly1305.c b/cipher/poly1305.c new file mode 100644 index 00000000..472ae42c --- /dev/null +++ b/cipher/poly1305.c @@ -0,0 +1,766 @@ +/* poly1305.c - Poly1305 internals and generic implementation + * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@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/>. + */ + +/* The code is based on public-domain Poly1305 implementation by + * Andrew Moon at + * https://github.com/floodyberry/poly1305-opt + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "poly1305-internal.h" + + +static const char *selftest (void); + + + +#ifdef HAVE_U64_TYPEDEF + +/* Reference unoptimized poly1305 implementation using 32 bit * 32 bit = 64 bit + * multiplication and 64 bit addition. + */ + +typedef struct poly1305_state_ref32_s +{ + u32 r[5]; + u32 h[5]; + u32 pad[4]; + byte final; +} poly1305_state_ref32_t; + + +static void +poly1305_init_ext_ref32 (void *state, const poly1305_key_t * key) +{ + poly1305_state_ref32_t *st = (poly1305_state_ref32_t *) state; + + gcry_assert (sizeof (*st) + POLY1305_STATE_ALIGNMENT <= + sizeof (((poly1305_context_t *) 0)->state)); + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = (buf_get_le32 (&key->b[0])) & 0x3ffffff; + st->r[1] = (buf_get_le32 (&key->b[3]) >> 2) & 0x3ffff03; + st->r[2] = (buf_get_le32 (&key->b[6]) >> 4) & 0x3ffc0ff; + st->r[3] = (buf_get_le32 (&key->b[9]) >> 6) & 0x3f03fff; + st->r[4] = (buf_get_le32 (&key->b[12]) >> 8) & 0x00fffff; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + /* save pad for later */ + st->pad[0] = buf_get_le32 (&key->b[16]); + st->pad[1] = buf_get_le32 (&key->b[20]); + st->pad[2] = buf_get_le32 (&key->b[24]); + st->pad[3] = buf_get_le32 (&key->b[28]); + + st->final = 0; +} + + +static unsigned int +poly1305_blocks_ref32 (void *state, const byte * m, size_t bytes) +{ + poly1305_state_ref32_t *st = (poly1305_state_ref32_t *) state; + const u32 hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ + u32 r0, r1, r2, r3, r4; + u32 s1, s2, s3, s4; + u32 h0, h1, h2, h3, h4; + u64 d0, d1, d2, d3, d4; + u32 c; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while (bytes >= POLY1305_REF_BLOCKSIZE) + { + /* h += m[i] */ + h0 += (buf_get_le32 (m + 0)) & 0x3ffffff; + h1 += (buf_get_le32 (m + 3) >> 2) & 0x3ffffff; + h2 += (buf_get_le32 (m + 6) >> 4) & 0x3ffffff; + h3 += (buf_get_le32 (m + 9) >> 6) & 0x3ffffff; + h4 += (buf_get_le32 (m + 12) >> 8) | hibit; + + /* h *= r */ + d0 = + ((u64) h0 * r0) + ((u64) h1 * s4) + + ((u64) h2 * s3) + ((u64) h3 * s2) + ((u64) h4 * s1); + d1 = + ((u64) h0 * r1) + ((u64) h1 * r0) + + ((u64) h2 * s4) + ((u64) h3 * s3) + ((u64) h4 * s2); + d2 = + ((u64) h0 * r2) + ((u64) h1 * r1) + + ((u64) h2 * r0) + ((u64) h3 * s4) + ((u64) h4 * s3); + d3 = + ((u64) h0 * r3) + ((u64) h1 * r2) + + ((u64) h2 * r1) + ((u64) h3 * r0) + ((u64) h4 * s4); + d4 = + ((u64) h0 * r4) + ((u64) h1 * r3) + + ((u64) h2 * r2) + ((u64) h3 * r1) + ((u64) h4 * r0); + + /* (partial) h %= p */ + c = (u32) (d0 >> 26); + h0 = (u32) d0 & 0x3ffffff; + d1 += c; + c = (u32) (d1 >> 26); + h1 = (u32) d1 & 0x3ffffff; + d2 += c; + c = (u32) (d2 >> 26); + h2 = (u32) d2 & 0x3ffffff; + d3 += c; + c = (u32) (d3 >> 26); + h3 = (u32) d3 & 0x3ffffff; + d4 += c; + c = (u32) (d4 >> 26); + h4 = (u32) d4 & 0x3ffffff; + h0 += c * 5; + c = (h0 >> 26); + h0 = h0 & 0x3ffffff; + h1 += c; + + m += POLY1305_REF_BLOCKSIZE; + bytes -= POLY1305_REF_BLOCKSIZE; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; + + return (16 * sizeof (u32) + 5 * sizeof (u64) + 5 * sizeof (void *)); +} + + +static unsigned int +poly1305_finish_ext_ref32 (void *state, const byte * m, + size_t remaining, byte mac[POLY1305_TAGLEN]) +{ + poly1305_state_ref32_t *st = (poly1305_state_ref32_t *) state; + u32 h0, h1, h2, h3, h4, c; + u32 g0, g1, g2, g3, g4; + u64 f; + u32 mask; + unsigned int burn = 0; + + /* process the remaining block */ + if (remaining) + { + byte final[POLY1305_REF_BLOCKSIZE] = { 0 }; + size_t i; + for (i = 0; i < remaining; i++) + final[i] = m[i]; + final[remaining] = 1; + st->final = 1; + burn = poly1305_blocks_ref32 (st, final, POLY1305_REF_BLOCKSIZE); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += c; + c = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += c; + c = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += c; + c = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += c * 5; + c = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + c; + c = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + c; + c = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + c; + c = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + c - (1 << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof (u32) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (u64) h0 + st->pad[0]; + h0 = (u32) f; + f = (u64) h1 + st->pad[1] + (f >> 32); + h1 = (u32) f; + f = (u64) h2 + st->pad[2] + (f >> 32); + h2 = (u32) f; + f = (u64) h3 + st->pad[3] + (f >> 32); + h3 = (u32) f; + + buf_put_le32 (mac + 0, h0); + buf_put_le32 (mac + 4, h1); + buf_put_le32 (mac + 8, h2); + buf_put_le32 (mac + 12, h3); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->r[3] = 0; + st->r[4] = 0; + st->pad[0] = 0; + st->pad[1] = 0; + st->pad[2] = 0; + st->pad[3] = 0; + + /* burn_stack */ + return (13 * sizeof (u32) + sizeof (u64) + + POLY1305_REF_BLOCKSIZE + 6 * sizeof (void *)) + burn; +} + + +static const poly1305_ops_t poly1305_default_ops = { + POLY1305_REF_BLOCKSIZE, + poly1305_init_ext_ref32, + poly1305_blocks_ref32, + poly1305_finish_ext_ref32 +}; + +#else /* !HAVE_U64_TYPEDEF */ + +/* Reference unoptimized poly1305 implementation using 8 bit * 8 bit = 16 bit + * multiplication and 16 bit addition, used when we don't have 'u64'. + */ + +typedef struct poly1305_state_ref8_t +{ + byte h[17]; + byte r[17]; + byte pad[17]; + byte final; +} poly1305_state_ref8_t; + + +static void +poly1305_init_ext_ref8 (void *state, const poly1305_key_t * key) +{ + poly1305_state_ref8_t *st = (poly1305_state_ref8_t *) state; + size_t i; + + /* h = 0 */ + for (i = 0; i < 17; i++) + st->h[i] = 0; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = key->b[0]; + st->r[1] = key->b[1]; + st->r[2] = key->b[2]; + st->r[3] = key->b[3] & 0x0f; + st->r[4] = key->b[4] & 0xfc; + st->r[5] = key->b[5]; + st->r[6] = key->b[6]; + st->r[7] = key->b[7] & 0x0f; + st->r[8] = key->b[8] & 0xfc; + st->r[9] = key->b[9]; + st->r[10] = key->b[10]; + st->r[11] = key->b[11] & 0x0f; + st->r[12] = key->b[12] & 0xfc; + st->r[13] = key->b[13]; + st->r[14] = key->b[14]; + st->r[15] = key->b[15] & 0x0f; + st->r[16] = 0; + + /* save pad for later */ + for (i = 0; i < 16; i++) + st->pad[i] = key->b[i + 16]; + st->pad[16] = 0; + + st->final = 0; +} + + +static void +poly1305_add_ref8 (byte h[17], const byte c[17]) +{ + u16 u; + unsigned int i; + for (u = 0, i = 0; i < 17; i++) + { + u += (u16) h[i] + (u16) c[i]; + h[i] = (byte) u & 0xff; + u >>= 8; + } +} + + +static void +poly1305_squeeze_ref8 (byte h[17], u32 hr[17]) +{ + u32 u; + unsigned int i; + u = 0; + for (i = 0; i < 16; i++) + { + u += hr[i]; + h[i] = (byte) u & 0xff; + u >>= 8; + } + u += hr[16]; + h[16] = (byte) u & 0x03; + u >>= 2; + u += (u << 2); /* u *= 5; */ + for (i = 0; i < 16; i++) + { + u += h[i]; + h[i] = (byte) u & 0xff; + u >>= 8; + } + h[16] += (byte) u; +} + + +static void +poly1305_freeze_ref8 (byte h[17]) +{ + static const byte minusp[17] = { + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc + }; + byte horig[17], negative; + unsigned int i; + + /* compute h + -p */ + for (i = 0; i < 17; i++) + horig[i] = h[i]; + poly1305_add_ref8 (h, minusp); + + /* select h if h < p, or h + -p if h >= p */ + negative = -(h[16] >> 7); + for (i = 0; i < 17; i++) + h[i] ^= negative & (horig[i] ^ h[i]); +} + + +static unsigned int +poly1305_blocks_ref8 (void *state, const byte * m, size_t bytes) +{ + poly1305_state_ref8_t *st = (poly1305_state_ref8_t *) state; + const byte hibit = st->final ^ 1; /* 1 << 128 */ + + while (bytes >= POLY1305_REF_BLOCKSIZE) + { + u32 hr[17], u; + byte c[17]; + unsigned int i, j; + + /* h += m */ + for (i = 0; i < 16; i++) + c[i] = m[i]; + c[16] = hibit; + poly1305_add_ref8 (st->h, c); + + /* h *= r */ + for (i = 0; i < 17; i++) + { + u = 0; + for (j = 0; j <= i; j++) + { + u += (u16) st->h[j] * st->r[i - j]; + } + for (j = i + 1; j < 17; j++) + { + u32 v = (u16) st->h[j] * st->r[i + 17 - j]; + v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */ + u += v; + } + hr[i] = u; + } + + /* (partial) h %= p */ + poly1305_squeeze_ref8 (st->h, hr); + + m += POLY1305_REF_BLOCKSIZE; + bytes -= POLY1305_REF_BLOCKSIZE; + } + + /* burn_stack */ + return (18 + 2) * sizeof (u32) + 18 + 6 * sizeof (void *) + + 6 * sizeof (void *); +} + + +static unsigned int +poly1305_finish_ext_ref8 (void *state, const byte * m, size_t remaining, + byte mac[POLY1305_TAGLEN]) +{ + poly1305_state_ref8_t *st = (poly1305_state_ref8_t *) state; + size_t i; + unsigned int burn = 0; + + /* process the remaining block */ + if (remaining) + { + byte final[POLY1305_REF_BLOCKSIZE] = { 0 }; + for (i = 0; i < remaining; i++) + final[i] = m[i]; + final[remaining] = 1; + st->final = 1; + burn = poly1305_blocks_ref8 (st, final, POLY1305_REF_BLOCKSIZE); + } + + /* fully reduce h */ + poly1305_freeze_ref8 (st->h); + + /* h = (h + pad) % (1 << 128) */ + poly1305_add_ref8 (st->h, st->pad); + for (i = 0; i < 16; i++) + mac[i] = st->h[i]; + + /* zero out the state */ + for (i = 0; i < 17; i++) + st->h[i] = 0; + for (i = 0; i < 17; i++) + st->r[i] = 0; + for (i = 0; i < 17; i++) + st->pad[i] = 0; + + /* burn_stack */ + return POLY1305_REF_BLOCKSIZE + 18 + 16 * sizeof (void *) + burn; +} + + +static const poly1305_ops_t poly1305_default_ops = { + POLY1305_REF_BLOCKSIZE, + poly1305_init_ext_ref8, + poly1305_blocks_ref8, + poly1305_finish_ext_ref8 +}; + +#endif /* HAVE_U64_TYPEDEF */ + + + +static inline void * +poly1305_get_state (poly1305_context_t * ctx) +{ + byte *c = ctx->state; + c += POLY1305_STATE_ALIGNMENT - 1; + c -= (uintptr_t) c & (POLY1305_STATE_ALIGNMENT - 1); + return c; +} + + +static void +poly1305_init (poly1305_context_t * ctx, const poly1305_key_t * key) +{ + void *state = poly1305_get_state (ctx); + + ctx->leftover = 0; + + ctx->ops->init_ext (state, key); +} + + +void +_gcry_poly1305_update (poly1305_context_t * ctx, const byte * m, size_t bytes) +{ + void *state = poly1305_get_state (ctx); + unsigned int burn = 0; + size_t block_size = ctx->ops->block_size; + + /* handle leftover */ + if (ctx->leftover) + { + size_t want = (block_size - ctx->leftover); + if (want > bytes) + want = bytes; + buf_cpy (ctx->buffer + ctx->leftover, m, want); + bytes -= want; + m += want; + ctx->leftover += want; + if (ctx->leftover < block_size) + return; + burn = ctx->ops->blocks (state, ctx->buffer, block_size); + ctx->leftover = 0; + } + + /* process full blocks */ + if (bytes >= block_size) + { + size_t want = (bytes & ~(block_size - 1)); + burn = ctx->ops->blocks (state, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) + { + buf_cpy (ctx->buffer + ctx->leftover, m, bytes); + ctx->leftover += bytes; + } + + if (burn) + _gcry_burn_stack (burn); +} + + +void +_gcry_poly1305_finish (poly1305_context_t * ctx, byte mac[POLY1305_TAGLEN]) +{ + void *state = poly1305_get_state (ctx); + unsigned int burn; + + burn = ctx->ops->finish_ext (state, ctx->buffer, ctx->leftover, mac); + + _gcry_burn_stack (burn); +} + + +gcry_err_code_t +_gcry_poly1305_init (poly1305_context_t * ctx, const byte * key, + size_t keylen) +{ + static int initialized; + static const char *selftest_failed; + poly1305_key_t keytmp; + + if (!initialized) + { + initialized = 1; + selftest_failed = selftest (); + if (selftest_failed) + log_error ("Poly1305 selftest failed (%s)\n", selftest_failed); + } + + if (keylen != POLY1305_KEYLEN) + return GPG_ERR_INV_KEYLEN; + + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + ctx->ops = &poly1305_default_ops; + + buf_cpy (keytmp.b, key, POLY1305_KEYLEN); + poly1305_init (ctx, &keytmp); + + wipememory (&keytmp, sizeof (keytmp)); + + return 0; +} + + +static void +poly1305_auth (byte mac[POLY1305_TAGLEN], const byte * m, size_t bytes, + const byte * key) +{ + poly1305_context_t ctx; + + memset (&ctx, 0, sizeof (ctx)); + + _gcry_poly1305_init (&ctx, key, POLY1305_KEYLEN); + _gcry_poly1305_update (&ctx, m, bytes); + _gcry_poly1305_finish (&ctx, mac); + + wipememory (&ctx, sizeof (ctx)); +} + + +static const char * +selftest (void) +{ + /* example from nacl */ + static const byte nacl_key[POLY1305_KEYLEN] = { + 0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91, + 0x6d, 0x11, 0xc2, 0xcb, 0x21, 0x4d, 0x3c, 0x25, + 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, + 0x2d, 0x65, 0x1f, 0xa4, 0xc8, 0xcf, 0xf8, 0x80, + }; + + static const byte nacl_msg[131] = { + 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, + 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, + 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, + 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a, + 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, + 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72, + 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, + 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, + 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, + 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, + 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, + 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, + 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, + 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, + 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, + 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, + 0xe3, 0x55, 0xa5 + }; + + static const byte nacl_mac[16] = { + 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, + 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9 + }; + + /* generates a final value of (2^130 - 2) == 3 */ + static const byte wrap_key[POLY1305_KEYLEN] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static const byte wrap_msg[16] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + static const byte wrap_mac[16] = { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + /* mac of the macs of messages of length 0 to 256, where the key and messages + * have all their values set to the length + */ + static const byte total_key[POLY1305_KEYLEN] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + static const byte total_mac[16] = { + 0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd, + 0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39 + }; + + poly1305_context_t ctx; + poly1305_context_t total_ctx; + byte all_key[POLY1305_KEYLEN]; + byte all_msg[256]; + byte mac[16]; + size_t i, j; + + memset (&ctx, 0, sizeof (ctx)); + memset (&total_ctx, 0, sizeof (total_ctx)); + + memset (mac, 0, sizeof (mac)); + poly1305_auth (mac, nacl_msg, sizeof (nacl_msg), nacl_key); + if (memcmp (nacl_mac, mac, sizeof (nacl_mac)) != 0) + return "Poly1305 test 1 failed."; + + /* SSE2/AVX have a 32 byte block size, but also support 64 byte blocks, so + * make sure everything still works varying between them */ + memset (mac, 0, sizeof (mac)); + _gcry_poly1305_init (&ctx, nacl_key, POLY1305_KEYLEN); + _gcry_poly1305_update (&ctx, nacl_msg + 0, 32); + _gcry_poly1305_update (&ctx, nacl_msg + 32, 64); + _gcry_poly1305_update (&ctx, nacl_msg + 96, 16); + _gcry_poly1305_update (&ctx, nacl_msg + 112, 8); + _gcry_poly1305_update (&ctx, nacl_msg + 120, 4); + _gcry_poly1305_update (&ctx, nacl_msg + 124, 2); + _gcry_poly1305_update (&ctx, nacl_msg + 126, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 127, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 128, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 129, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 130, 1); + _gcry_poly1305_finish (&ctx, mac); + if (memcmp (nacl_mac, mac, sizeof (nacl_mac)) != 0) + return "Poly1305 test 2 failed."; + + memset (mac, 0, sizeof (mac)); + poly1305_auth (mac, wrap_msg, sizeof (wrap_msg), wrap_key); + if (memcmp (wrap_mac, mac, sizeof (nacl_mac)) != 0) + return "Poly1305 test 3 failed."; + + _gcry_poly1305_init (&total_ctx, total_key, POLY1305_KEYLEN); + for (i = 0; i < 256; i++) + { + /* set key and message to 'i,i,i..' */ + for (j = 0; j < sizeof (all_key); j++) + all_key[j] = i; + for (j = 0; j < i; j++) + all_msg[j] = i; + poly1305_auth (mac, all_msg, i, all_key); + _gcry_poly1305_update (&total_ctx, mac, 16); + } + _gcry_poly1305_finish (&total_ctx, mac); + if (memcmp (total_mac, mac, sizeof (total_mac)) != 0) + return "Poly1305 test 4 failed."; + + return NULL; +} diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index d4e9bb2a..8648e960 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -1341,7 +1341,9 @@ enum gcry_mac_algos GCRY_MAC_GMAC_CAMELLIA = 402, GCRY_MAC_GMAC_TWOFISH = 403, GCRY_MAC_GMAC_SERPENT = 404, - GCRY_MAC_GMAC_SEED = 405 + GCRY_MAC_GMAC_SEED = 405, + + GCRY_MAC_POLY1305 = 501 }; /* Flags used with the open function. */ diff --git a/tests/basic.c b/tests/basic.c index 406d82d3..cc0f4c18 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -5041,6 +5041,8 @@ check_mac (void) const char *key; const char *expect; const char *iv; + unsigned int dlen; + unsigned int klen; } algos[] = { { GCRY_MAC_HMAC_MD5, "what do ya want for nothing?", "Jefe", @@ -5491,6 +5493,109 @@ check_mac (void) "\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" }, + /* from NaCl */ + { GCRY_MAC_POLY1305, + "\x8e\x99\x3b\x9f\x48\x68\x12\x73\xc2\x96\x50\xba\x32\xfc\x76\xce" + "\x48\x33\x2e\xa7\x16\x4d\x96\xa4\x47\x6f\xb8\xc5\x31\xa1\x18\x6a" + "\xc0\xdf\xc1\x7c\x98\xdc\xe8\x7b\x4d\xa7\xf0\x11\xec\x48\xc9\x72" + "\x71\xd2\xc2\x0f\x9b\x92\x8f\xe2\x27\x0d\x6f\xb8\x63\xd5\x17\x38" + "\xb4\x8e\xee\xe3\x14\xa7\xcc\x8a\xb9\x32\x16\x45\x48\xe5\x26\xae" + "\x90\x22\x43\x68\x51\x7a\xcf\xea\xbd\x6b\xb3\x73\x2b\xc0\xe9\xda" + "\x99\x83\x2b\x61\xca\x01\xb6\xde\x56\x24\x4a\x9e\x88\xd5\xf9\xb3" + "\x79\x73\xf6\x22\xa4\x3d\x14\xa6\x59\x9b\x1f\x65\x4c\xb4\x5a\x74" + "\xe3\x55\xa5", + "\xee\xa6\xa7\x25\x1c\x1e\x72\x91\x6d\x11\xc2\xcb\x21\x4d\x3c\x25" + "\x25\x39\x12\x1d\x8e\x23\x4e\x65\x2d\x65\x1f\xa4\xc8\xcf\xf8\x80", + "\xf3\xff\xc7\x70\x3f\x94\x00\xe5\x2a\x7d\xfb\x4b\x3d\x33\x05\xd9" }, + /* from draft-nir-cfrg-chacha20-poly1305-03 */ + { GCRY_MAC_POLY1305, + "Cryptographic Forum Research Group", + "\x85\xd6\xbe\x78\x57\x55\x6d\x33\x7f\x44\x52\xfe\x42\xd5\x06\xa8" + "\x01\x03\x80\x8a\xfb\x0d\xb2\xfd\x4a\xbf\xf6\xaf\x41\x49\xf5\x1b", + "\xa8\x06\x1d\xc1\x30\x51\x36\xc6\xc2\x2b\x8b\xaf\x0c\x01\x27\xa9" }, + { GCRY_MAC_POLY1305, + "'Twas brillig, and the slithy toves\n" + "Did gyre and gimble in the wabe:\n" + "All mimsy were the borogoves,\n" + "And the mome raths outgrabe.", + "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0" + "\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", + "\x45\x41\x66\x9a\x7e\xaa\xee\x61\xe7\x08\xdc\x7c\xbc\xc5\xeb\x62" }, + { GCRY_MAC_POLY1305, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + NULL, + 191, 32 }, + { GCRY_MAC_POLY1305, + "Any submission to the IETF intended by the Contributor for " + "publication as all or part of an IETF Internet-Draft or RFC and " + "any statement made within the context of an IETF activity is " + "considered an \"IETF Contribution\". Such statements include " + "oral statements in IETF sessions, as well as written and " + "electronic communications made at any time or place, which are " + "addressed to", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x36\xe5\xf6\xb5\xc5\xe0\x60\x70\xf0\xef\xca\x96\x22\x7a\x86\x3e", + "\x36\xe5\xf6\xb5\xc5\xe0\x60\x70\xf0\xef\xca\x96\x22\x7a\x86\x3e", + NULL, + 0, 32 }, + { GCRY_MAC_POLY1305, + "Any submission to the IETF intended by the Contributor for " + "publication as all or part of an IETF Internet-Draft or RFC and " + "any statement made within the context of an IETF activity is " + "considered an \"IETF Contribution\". Such statements include " + "oral statements in IETF sessions, as well as written and " + "electronic communications made at any time or place, which are " + "addressed to", + "\x36\xe5\xf6\xb5\xc5\xe0\x60\x70\xf0\xef\xca\x96\x22\x7a\x86\x3e" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xf3\x47\x7e\x7c\xd9\x54\x17\xaf\x89\xa6\xb8\x79\x4c\x31\x0c\xf0", + NULL, + 0, 32 }, + /* from http://cr.yp.to/mac/poly1305-20050329.pdf */ + { GCRY_MAC_POLY1305, + "\xf3\xf6", + "\x85\x1f\xc4\x0c\x34\x67\xac\x0b\xe0\x5c\xc2\x04\x04\xf3\xf7\x00" + "\x58\x0b\x3b\x0f\x94\x47\xbb\x1e\x69\xd0\x95\xb5\x92\x8b\x6d\xbc", + "\xf4\xc6\x33\xc3\x04\x4f\xc1\x45\xf8\x4f\x33\x5c\xb8\x19\x53\xde", + NULL, + 0, 32 }, + { GCRY_MAC_POLY1305, + "", + "\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", + "\xdd\x3f\xab\x22\x51\xf1\x1a\xc7\x59\xf0\x88\x71\x29\xcc\x2e\xe7", + NULL, + 0, 32 }, + { GCRY_MAC_POLY1305, + "\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", + "\x48\x44\x3d\x0b\xb0\xd2\x11\x09\xc8\x9a\x10\x0b\x5c\xe2\xc2\x08" + "\x83\x14\x9c\x69\xb5\x61\xdd\x88\x29\x8a\x17\x98\xb1\x07\x16\xef", + "\x0e\xe1\xc1\x6b\xb7\x3f\x0f\x4f\xd1\x98\x81\x75\x3c\x01\xcd\xbe", + NULL, + 0, 32 }, + { GCRY_MAC_POLY1305, + "\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", + "\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" }, { 0 }, }; int i; @@ -5500,6 +5605,8 @@ check_mac (void) for (i = 0; algos[i].algo; i++) { + size_t klen, dlen; + if (gcry_mac_test_algo (algos[i].algo)) { show_mac_not_available (algos[i].algo); @@ -5520,13 +5627,14 @@ check_mac (void) algos[i].algo, (int)strlen(algos[i].key), (int)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].iv, - algos[i].iv ? strlen(algos[i].iv) : 0, + klen = algos[i].klen ? algos[i].klen : strlen(algos[i].key); + dlen = algos[i].dlen ? algos[i].dlen : strlen (algos[i].data); + + check_one_mac (algos[i].algo, algos[i].data, dlen, algos[i].key, klen, + 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].iv, - algos[i].iv ? strlen(algos[i].iv) : 0, + check_one_mac (algos[i].algo, algos[i].data, dlen, algos[i].key, klen, + 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 bd05064c..3d8ae378 100644 --- a/tests/bench-slope.c +++ b/tests/bench-slope.c @@ -1405,7 +1405,7 @@ mac_bench (char **argv, int argc) } else { - for (i = 1; i < 500; i++) + for (i = 1; i < 600; i++) if (!gcry_mac_test_algo (i)) _mac_bench (i); } diff --git a/tests/benchmark.c b/tests/benchmark.c index 5efc083f..9fd716dd 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -461,7 +461,7 @@ mac_bench ( const char *algoname ) if (!algoname) { - for (i=1; i < 500; i++) + for (i=1; i < 600; i++) if (in_fips_mode && i == GCRY_MAC_HMAC_MD5) ; /* Don't use MD5 in fips mode. */ else if ( !gcry_mac_test_algo (i) ) |