From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/third_party/libgcrypt/cipher/mac-poly1305.c | 364 +++++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 comm/third_party/libgcrypt/cipher/mac-poly1305.c (limited to 'comm/third_party/libgcrypt/cipher/mac-poly1305.c') diff --git a/comm/third_party/libgcrypt/cipher/mac-poly1305.c b/comm/third_party/libgcrypt/cipher/mac-poly1305.c new file mode 100644 index 0000000000..46ea735f89 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac-poly1305.c @@ -0,0 +1,364 @@ +/* mac-poly1305.c - Poly1305 based MACs + * Copyright (C) 2014 Jussi Kivilinna + * + * 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 . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mac-internal.h" +#include "poly1305-internal.h" + + +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]; + 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_MAC_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)); + else + mac_ctx = xtrycalloc (1, sizeof(*mac_ctx)); + + if (!mac_ctx) + return gpg_err_code_from_syserror (); + + 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) +{ + 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); +} + + +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.nonce_set = 0; + mac_ctx->marks.tag = 0; + + if (h->spec->algo != GCRY_MAC_POLY1305) + { + err = poly1305mac_prepare_key (h, key, keylen); + if (err) + return err; + + /* Poly1305-AES/etc also need nonce. */ + mac_ctx->marks.key_set = 1; + mac_ctx->marks.nonce_set = 0; + } + else + { + /* 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; + } + + 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; +} + + +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 || !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); +} + + +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.nonce_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 || !mac_ctx->marks.nonce_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 == 0) + return 0; + + 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, + poly1305mac_setiv, + poly1305mac_reset, + poly1305mac_write, + poly1305mac_read, + poly1305mac_verify, + poly1305mac_get_maclen, + poly1305mac_get_keylen, + NULL, + NULL, +}; + + +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 -- cgit v1.2.3