aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2024-03-29 04:20:17 +0000
committerNIIBE Yutaka <[email protected]>2024-03-29 04:20:17 +0000
commit5a25b27860985c916d15c490703de923ce8752e1 (patch)
treeda44b9de579ff67399bf6a7e2532a8ef518200c8
parentFix pkdecrypt.c, now works with the test vector. (diff)
downloadgnupg-5a25b27860985c916d15c490703de923ce8752e1.tar.gz
gnupg-5a25b27860985c916d15c490703de923ce8752e1.zip
Add kmac.c.gniibe/kem
Signed-off-by: NIIBE Yutaka <[email protected]>
-rw-r--r--agent/pkdecrypt.c68
-rw-r--r--common/Makefile.am4
-rw-r--r--common/kmac.c132
-rw-r--r--common/util.h6
4 files changed, 155 insertions, 55 deletions
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[6].data = "\x00\x00\x00\x01"; /* Counter */
- iov[6].off = 0;
- iov[6].len = 4;
-
- 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;
+ iov[5].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 = compute_kmac256 (kekkey, kekkeylen,
+ "OpenPGPCompositeKeyDerivationFunction", 37,
+ "KDF", 3, iov, 6);
- 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gpg-error.h>
+#include <gcrypt.h>
+#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