From 5a25b27860985c916d15c490703de923ce8752e1 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 29 Mar 2024 13:20:17 +0900 Subject: [PATCH] Add kmac.c. Signed-off-by: NIIBE Yutaka --- agent/pkdecrypt.c | 68 ++++++----------------- common/Makefile.am | 4 +- common/kmac.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ common/util.h | 6 +++ 4 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 common/kmac.c diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index bdd982afe..22cbdd2bb 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -205,11 +205,7 @@ agent_hybrid_kem_decap (ctrl_t ctrl, const char *desc_text, int kemid, const unsigned char *mlkem_ct; unsigned char mlkem_ss[GCRY_KEM_MLKEM768_SHARED_LEN]; - gcry_buffer_t iov[13]; - unsigned char head136[2]; - unsigned char headK[3]; - const unsigned char pad[94] = { 0 }; - unsigned char right_encode_L[3]; + gcry_buffer_t iov[6]; unsigned char kekkey[32]; size_t kekkeylen = 32; /* AES-256 is mandatory */ @@ -361,68 +357,34 @@ agent_hybrid_kem_decap (ctrl_t ctrl, const char *desc_text, int kemid, // newX = bytepad(encode_string(K), 136) || X || right_encode(L) // cSHAKE256(newX,L,"KMAC",S) - iov[0].data = "KMAC"; + iov[0].data = "\x00\x00\x00\x01"; /* Counter */ iov[0].off = 0; iov[0].len = 4; - iov[1].data = "KDF"; + iov[1].data = ecc_ss; iov[1].off = 0; - iov[1].len = 3; + iov[1].len = 32; - head136[0] = 1; - head136[1] = 136; - iov[2].data = head136; + iov[2].data = (unsigned char *)ecc_ct; iov[2].off = 0; - iov[2].len = 2; + iov[2].len = 32; - headK[0] = 2; - headK[1] = (37*8)>>8; - headK[2] = (37*8)&0xff; - iov[3].data = headK; + iov[3].data = mlkem_ss; iov[3].off = 0; - iov[3].len = 3; + iov[3].len = GCRY_KEM_MLKEM768_SHARED_LEN; - iov[4].data = "OpenPGPCompositeKeyDerivationFunction"; + iov[4].data = (unsigned char *)mlkem_ct; iov[4].off = 0; - iov[4].len = 37; + iov[4].len = GCRY_KEM_MLKEM768_ENCAPS_LEN; - iov[5].data = (unsigned char *)pad; + iov[5].data = (unsigned char *)fixedinfo; iov[5].off = 0; - iov[5].len = sizeof (pad); + iov[5].len = 1; - iov[6].data = "\x00\x00\x00\x01"; /* Counter */ - iov[6].off = 0; - iov[6].len = 4; + err = compute_kmac256 (kekkey, kekkeylen, + "OpenPGPCompositeKeyDerivationFunction", 37, + "KDF", 3, iov, 6); - iov[7].data = ecc_ss; - iov[7].off = 0; - iov[7].len = 32; - - iov[8].data = (unsigned char *)ecc_ct; - iov[8].off = 0; - iov[8].len = 32; - - iov[9].data = mlkem_ss; - iov[9].off = 0; - iov[9].len = GCRY_KEM_MLKEM768_SHARED_LEN; - - iov[10].data = (unsigned char *)mlkem_ct; - iov[10].off = 0; - iov[10].len = GCRY_KEM_MLKEM768_ENCAPS_LEN; - - iov[11].data = (unsigned char *)fixedinfo; - iov[11].off = 0; - iov[11].len = 1; - - right_encode_L[0] = (kekkeylen * 8) >> 8; - right_encode_L[1] = (kekkeylen * 8) & 0xff; - right_encode_L[2] = 2; - iov[12].data = right_encode_L; - iov[12].off = 0; - iov[12].len = 3; - - err = gcry_md_hash_buffers_extract (GCRY_MD_CSHAKE256, 0, kekkey, kekkeylen, - iov, 13); mpi_release (ecc_ct_mpi); mpi_release (mlkem_ct_mpi); diff --git a/common/Makefile.am b/common/Makefile.am index d27603f96..e4dcf8ad6 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -97,8 +97,8 @@ common_sources = \ openpgp-fpr.c \ comopt.c comopt.h \ compliance.c compliance.h \ - pkscreening.c pkscreening.h - + pkscreening.c pkscreening.h \ + kmac.c if HAVE_W32_SYSTEM common_sources += w32-reg.c w32-cmdline.c diff --git a/common/kmac.c b/common/kmac.c new file mode 100644 index 000000000..0e8ff316b --- /dev/null +++ b/common/kmac.c @@ -0,0 +1,132 @@ +/* kmac.c - Keccak based MAC + * Copyright (C) 2024 g10 Code GmbH. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute and/or modify this + * part of GnuPG under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * GnuPG 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 + * General Public License for more details. + * + * You should have received a copies of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, see . + */ + +#include +#include +#include +#include +#include +#include "mischelp.h" + +#define KECCAK512_BLOCKSIZE 136 +gpg_error_t +compute_kmac256 (void *digest, size_t digestlen, + const void *key, size_t keylen, + const void *custom, size_t customlen, + gcry_buffer_t *data_iov, int data_iovlen) +{ + gpg_error_t err; + gcry_buffer_t iov[20]; + const unsigned char headPAD[2] = { 1, KECCAK512_BLOCKSIZE }; + unsigned char headK[3]; + const unsigned char pad[KECCAK512_BLOCKSIZE] = { 0 }; + unsigned char right_encode_L[3]; + unsigned int len; + int iovcnt; + + if (data_iovlen >= DIM(iov) - 6) + return gpg_error (GPG_ERR_TOO_LARGE); + + /* Check the validity conditions of NIST SP 800-185 */ + if (keylen >= 255 || customlen >= 255 || digestlen >= 255) + return gpg_error (GPG_ERR_TOO_LARGE); + + iovcnt = 0; + iov[iovcnt].data = "KMAC"; + iov[iovcnt].off = 0; + iov[iovcnt].len = 4; + iovcnt++; + + iov[iovcnt].data = (void *)custom; + iov[iovcnt].off = 0; + iov[iovcnt].len = customlen; + iovcnt++; + + iov[iovcnt].data = (void *)headPAD; + iov[iovcnt].off = 0; + iov[iovcnt].len = sizeof (headPAD); + iovcnt++; + + if (keylen < 32) + { + headK[0] = 1; + headK[1] = (keylen*8)&0xff; + iov[iovcnt].data = headK; + iov[iovcnt].off = 0; + iov[iovcnt].len = 2; + } + else + { + headK[0] = 2; + headK[1] = (keylen*8)>>8; + headK[2] = (keylen*8)&0xff; + iov[iovcnt].data = headK; + iov[iovcnt].off = 0; + iov[iovcnt].len = 3; + } + iovcnt++; + + iov[iovcnt].data = (void *)key; + iov[iovcnt].off = 0; + iov[iovcnt].len = keylen; + iovcnt++; + + len = iov[2].len + iov[3].len + iov[4].len; + len %= KECCAK512_BLOCKSIZE; + + iov[iovcnt].data = (unsigned char *)pad; + iov[iovcnt].off = 0; + iov[iovcnt].len = sizeof (pad) - len; + iovcnt++; + + memcpy (&iov[iovcnt], data_iov, data_iovlen * sizeof (gcry_buffer_t)); + iovcnt += data_iovlen; + + if (digestlen < 32) + { + right_encode_L[0] = (digestlen * 8) & 0xff; + right_encode_L[1] = 1; + } + else + { + right_encode_L[0] = (digestlen * 8) >> 8; + right_encode_L[1] = (digestlen * 8) & 0xff; + right_encode_L[2] = 2; + } + + iov[iovcnt].data = right_encode_L; + iov[iovcnt].off = 0; + iov[iovcnt].len = 3; + iovcnt++; + + err = gcry_md_hash_buffers_extract (GCRY_MD_CSHAKE256, 0, + digest, digestlen, iov, iovcnt); + return err; +} diff --git a/common/util.h b/common/util.h index 2b46ec930..f3fbfc3c8 100644 --- a/common/util.h +++ b/common/util.h @@ -298,6 +298,12 @@ char *gnupg_get_help_string (const char *key, int only_current_locale); /*-- localename.c --*/ const char *gnupg_messages_locale_name (void); +/*-- kmac.c --*/ +gpg_error_t compute_kmac256 (void *digest, size_t digestlen, + const void *key, size_t keylen, + const void *custom, size_t customlen, + gcry_buffer_t *data_iov, int data_iovlen); + /*-- miscellaneous.c --*/ /* This function is called at startup to tell libgcrypt to use our own