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 /cipher/mac-poly1305.c | |
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>
Diffstat (limited to 'cipher/mac-poly1305.c')
-rw-r--r-- | cipher/mac-poly1305.c | 213 |
1 files changed, 213 insertions, 0 deletions
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 +}; |