diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index e93ac0a26..3848bcefc 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -1,473 +1,464 @@
/* pkdecrypt.c - public key decryption (well, actually using a secret key)
* Copyright (C) 2001, 2003 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* 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 copy of the GNU General Public License
* along with this program; if not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "agent.h"
#include "../common/openpgpdefs.h"
/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
Try to get the key from CTRL and write the decoded stuff back to
OUTFP. The padding information is stored at R_PADDING with -1
for not known. */
gpg_error_t
agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *ciphertext, size_t ciphertextlen,
membuf_t *outbuf, int *r_padding)
{
gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL;
unsigned char *shadow_info = NULL;
gpg_error_t err = 0;
int no_shadow_info = 0;
char *buf = NULL;
size_t len;
*r_padding = -1;
if (!ctrl->have_keygrip)
{
log_error ("speculative decryption not yet supported\n");
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
}
err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen);
if (err)
{
log_error ("failed to convert ciphertext: %s\n", gpg_strerror (err));
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
if (DBG_CRYPTO)
{
log_printhex (ctrl->keygrip, 20, "keygrip:");
log_printhex (ciphertext, ciphertextlen, "cipher: ");
}
err = agent_key_from_file (ctrl, NULL, desc_text,
NULL, &shadow_info,
CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_NO_SECKEY)
no_shadow_info = 1;
else if (err)
{
log_error ("failed to read the secret key\n");
goto leave;
}
if (shadow_info || no_shadow_info)
{ /* divert operation to the smartcard */
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
{
err = gpg_error (GPG_ERR_INV_SEXP);
goto leave;
}
if (s_skey && agent_is_tpm2_key (s_skey))
err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info,
&buf, &len, r_padding);
else
err = divert_pkdecrypt (ctrl, ctrl->keygrip, ciphertext,
&buf, &len, r_padding);
if (err)
{
/* We restore the original error (ie. no seckey) is no card
* has been found and we have no shadow key. This avoids a
* surprising "card removed" error code. */
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
&& no_shadow_info)
err = gpg_error (GPG_ERR_NO_SECKEY);
else
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
goto leave;
}
put_membuf_printf (outbuf, "(5:value%u:", (unsigned int)len);
put_membuf (outbuf, buf, len);
put_membuf (outbuf, ")", 2);
}
else
{ /* No smartcard, but a private key */
/* if (DBG_CRYPTO ) */
/* { */
/* log_debug ("skey: "); */
/* gcry_sexp_dump (s_skey); */
/* } */
err = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
if (err)
{
log_error ("decryption failed: %s\n", gpg_strerror (err));
goto leave;
}
if (DBG_CRYPTO)
{
log_debug ("plain: ");
gcry_sexp_dump (s_plain);
}
len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
log_assert (len);
buf = xmalloc (len);
len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
log_assert (len);
if (*buf == '(')
put_membuf (outbuf, buf, len);
else
{
/* Old style libgcrypt: This is only an S-expression
part. Turn it into a complete S-expression. */
put_membuf (outbuf, "(5:value", 8);
put_membuf (outbuf, buf, len);
put_membuf (outbuf, ")", 2);
}
}
leave:
gcry_sexp_release (s_skey);
gcry_sexp_release (s_plain);
gcry_sexp_release (s_cipher);
xfree (buf);
xfree (shadow_info);
return err;
}
/* Reverse BUFFER to change the endianness. */
static void
reverse_buffer (unsigned char *buffer, unsigned int length)
{
unsigned int tmp, i;
for (i=0; i < length/2; i++)
{
tmp = buffer[i];
buffer[i] = buffer[length-1-i];
buffer[length-1-i] = tmp;
}
}
/* For hybrid PGP KEM (ECC+ML-KEM), decrypt CIPHERTEXT using KEM API.
First keygrip is for ECC, second keygrip is for PQC. CIPHERTEXT
should follow the format of:
(enc-val(pqc(s%m)(e%m)(k%m))))
s: encrypted session key
e: ECDH ciphertext
k: ML-KEM ciphertext
FIXME: For now, possibile keys on smartcard are not supported.
*/
static gpg_error_t
agent_hybrid_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
gcry_sexp_t s_cipher, membuf_t *outbuf)
{
#if GCRYPT_VERSION_NUMBER >= 0x010b00
gcry_sexp_t s_skey0 = NULL;
gcry_sexp_t s_skey1 = NULL;
unsigned char *shadow_info = NULL;
gpg_error_t err = 0;
unsigned int nbits;
const unsigned char *p;
size_t len;
- gcry_mpi_t encrypted_sessionkey_mpi;
+ gcry_mpi_t encrypted_sessionkey_mpi = NULL;
const unsigned char *encrypted_sessionkey;
size_t encrypted_sessionkey_len;
- gcry_mpi_t ecc_sk_mpi;
+ gcry_mpi_t ecc_sk_mpi = NULL;
unsigned char ecc_sk[32];
- gcry_mpi_t ecc_pk_mpi;
+ gcry_mpi_t ecc_pk_mpi = NULL;
unsigned char ecc_pk[32];
- gcry_mpi_t ecc_ct_mpi;
+ gcry_mpi_t ecc_ct_mpi = NULL;
const unsigned char *ecc_ct;
size_t ecc_ct_len;
unsigned char ecc_ecdh[32];
unsigned char ecc_ss[32];
- gcry_mpi_t mlkem_sk_mpi;
- gcry_mpi_t mlkem_ct_mpi;
+ gcry_mpi_t mlkem_sk_mpi = NULL;
+ gcry_mpi_t mlkem_ct_mpi = NULL;
const unsigned char *mlkem_sk;
const unsigned char *mlkem_ct;
unsigned char mlkem_ss[GCRY_KEM_MLKEM768_SHARED_LEN];
- gcry_buffer_t iov[6];
-
- unsigned char kekkey[32];
- size_t kekkeylen = 32; /* AES-256 is mandatory */
+ unsigned char kek[32];
+ size_t kek_len = 32; /* AES-256 is mandatory */
gcry_cipher_hd_t hd;
unsigned char sessionkey[256];
size_t sessionkey_len;
const unsigned char fixedinfo[1] = { 105 };
err = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip, &shadow_info,
CACHE_MODE_NORMAL, NULL, &s_skey0, NULL, NULL);
if (err)
{
log_error ("failed to read the secret key\n");
goto leave;
}
err = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip1, &shadow_info,
CACHE_MODE_NORMAL, NULL, &s_skey1, NULL, NULL);
if (err)
{
log_error ("failed to read the another secret key\n");
goto leave;
}
/* Here assumes no smartcard, but private keys */
gcry_sexp_extract_param (s_cipher, NULL, "/e/k/s",
&ecc_ct_mpi,
&mlkem_ct_mpi,
&encrypted_sessionkey_mpi, NULL);
encrypted_sessionkey = gcry_mpi_get_opaque (encrypted_sessionkey_mpi, &nbits);
encrypted_sessionkey_len = (nbits+7)/8;
encrypted_sessionkey_len--;
if (encrypted_sessionkey[0] != encrypted_sessionkey_len)
{
err = GPG_ERR_INV_DATA;
goto leave;
}
encrypted_sessionkey++; /* Skip the length. */
if (encrypted_sessionkey[0] != CIPHER_ALGO_AES256)
{
err = GPG_ERR_INV_DATA;
goto leave;
}
encrypted_sessionkey_len--;
encrypted_sessionkey++; /* Skip the sym algo */
/* Fistly, ECC part. FIXME: For now, we assume X25519. */
gcry_sexp_extract_param (s_skey0, NULL, "/q/d",
&ecc_pk_mpi, &ecc_sk_mpi, NULL);
p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits);
len = (nbits+7)/8;
memcpy (ecc_pk, p+1, 32); /* Remove the 0x40 prefix */
p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits);
len = (nbits+7)/8;
if (len > 32)
{
err = GPG_ERR_INV_DATA;
goto leave;
}
memset (ecc_sk, 0, 32);
memcpy (ecc_sk + 32 - len, p, len);
reverse_buffer (ecc_sk, 32);
mpi_release (ecc_pk_mpi);
mpi_release (ecc_sk_mpi);
+ ecc_pk_mpi = NULL;
+ ecc_sk_mpi = NULL;
ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits);
ecc_ct_len = (nbits+7)/8;
if (ecc_ct_len != 32)
{
err = GPG_ERR_INV_DATA;
goto leave;
}
err = gcry_kem_decap (GCRY_KEM_RAW_X25519, ecc_sk, 32, ecc_ct, ecc_ct_len,
ecc_ecdh, 32, NULL, 0);
- iov[0].data = ecc_ecdh;
- iov[0].off = 0;
- iov[0].len = 32;
- iov[1].data = (unsigned char *)ecc_ct;
- iov[1].off = 0;
- iov[1].len = 32;
- iov[2].data = ecc_pk;
- iov[2].off = 0;
- iov[2].len = 32;
- gcry_md_hash_buffers (GCRY_MD_SHA3_256, 0, ecc_ss, iov, 3);
+ if (err)
+ goto leave;
+
+ err = gnupg_ecc_kem_kdf (ecc_ss, 32, GCRY_MD_SHA3_256,
+ ecc_ecdh, 32, ecc_ct, 32, ecc_pk, 32);
+
+ if (err)
+ goto leave;
/* Secondly, PQC part. For now, we assume ML-KEM. */
gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL);
mlkem_sk = gcry_mpi_get_opaque (mlkem_sk_mpi, &nbits);
len = (nbits+7)/8;
if (len != GCRY_KEM_MLKEM768_SECKEY_LEN)
{
err = GPG_ERR_INV_DATA;
goto leave;
}
mlkem_ct = gcry_mpi_get_opaque (mlkem_ct_mpi, &nbits);
len = (nbits+7)/8;
if (len != GCRY_KEM_MLKEM768_CIPHER_LEN)
{
err = GPG_ERR_INV_DATA;
goto leave;
}
err = gcry_kem_decap (GCRY_KEM_MLKEM768,
mlkem_sk, GCRY_KEM_MLKEM768_SECKEY_LEN,
mlkem_ct, GCRY_KEM_MLKEM768_CIPHER_LEN,
mlkem_ss, GCRY_KEM_MLKEM768_SHARED_LEN,
NULL, 0);
+ if (err)
+ goto leave;
mpi_release (mlkem_sk_mpi);
-
- /* Then, combine two shared secrets into one */
-
- iov[0].data = "\x00\x00\x00\x01"; /* Counter */
- iov[0].off = 0;
- iov[0].len = 4;
-
- iov[1].data = ecc_ss;
- iov[1].off = 0;
- iov[1].len = 32;
-
- iov[2].data = (unsigned char *)ecc_ct;
- iov[2].off = 0;
- iov[2].len = 32;
-
- iov[3].data = mlkem_ss;
- iov[3].off = 0;
- iov[3].len = GCRY_KEM_MLKEM768_SHARED_LEN;
-
- iov[4].data = (unsigned char *)mlkem_ct;
- iov[4].off = 0;
- iov[4].len = GCRY_KEM_MLKEM768_ENCAPS_LEN;
-
- iov[5].data = (unsigned char *)fixedinfo;
- iov[5].off = 0;
- iov[5].len = 1;
-
- err = compute_kmac256 (kekkey, kekkeylen,
- "OpenPGPCompositeKeyDerivationFunction", 37,
- "KDF", 3, iov, 6);
+ mlkem_sk_mpi = NULL;
+
+ /* Then, combine two shared secrets and ciphertexts into one KEK */
+ err = gnupg_kem_combiner (kek, kek_len,
+ ecc_ss, 32, ecc_ct, 32,
+ mlkem_ss, GCRY_KEM_MLKEM768_SHARED_LEN,
+ mlkem_ct, GCRY_KEM_MLKEM768_CIPHER_LEN,
+ fixedinfo, 1);
+ if (err)
+ {
+ log_error ("KEM combiner failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
mpi_release (ecc_ct_mpi);
mpi_release (mlkem_ct_mpi);
+ ecc_ct_mpi = NULL;
+ mlkem_ct_mpi = NULL;
if (DBG_CRYPTO)
{
- log_printhex (kekkey, kekkeylen, "KEK key: ");
+ log_printhex (kek, kek_len, "KEK key: ");
}
err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256,
GCRY_CIPHER_MODE_AESWRAP, 0);
if (err)
{
log_error ("ecdh failed to initialize AESWRAP: %s\n",
gpg_strerror (err));
- mpi_release (encrypted_sessionkey_mpi);
goto leave;
}
- err = gcry_cipher_setkey (hd, kekkey, kekkeylen);
+ err = gcry_cipher_setkey (hd, kek, kek_len);
sessionkey_len = encrypted_sessionkey_len - 8;
err = gcry_cipher_decrypt (hd, sessionkey, sessionkey_len,
encrypted_sessionkey, encrypted_sessionkey_len);
gcry_cipher_close (hd);
mpi_release (encrypted_sessionkey_mpi);
+ encrypted_sessionkey_mpi = NULL;
if (err)
{
log_error ("KEM decrypt failed: %s\n", gpg_strerror (err));
goto leave;
}
put_membuf_printf (outbuf,
"(5:value%u:", (unsigned int)sessionkey_len);
put_membuf (outbuf, sessionkey, sessionkey_len);
put_membuf (outbuf, ")", 2);
leave:
+ mpi_release (mlkem_sk_mpi);
+ mpi_release (ecc_pk_mpi);
+ mpi_release (ecc_sk_mpi);
+ mpi_release (ecc_ct_mpi);
+ mpi_release (mlkem_ct_mpi);
+ mpi_release (encrypted_sessionkey_mpi);
gcry_sexp_release (s_skey0);
gcry_sexp_release (s_skey1);
return err;
#else
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
}
/* DECRYPT the encrypted stuff (like encrypted session key) in
CIPHERTEXT using KEM API, with KEMID. Keys (or a key) are
specified in CTRL. DESC_TEXT is used to retrieve private key.
OPTION can be specified for upper layer option for KEM. Decrypted
stuff (like session key) is written to OUTBUF.
*/
gpg_error_t
agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
const unsigned char *ciphertext, size_t ciphertextlen,
const unsigned char *option, size_t optionlen,
membuf_t *outbuf)
{
gcry_sexp_t s_cipher = NULL;
gpg_error_t err = 0;
/* For now, only PQC-PGP is supported. */
if (kemid != KEM_PQC_PGP)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
(void)optionlen;
if (kemid == KEM_PQC_PGP && option)
{
log_error ("PQC-PGP requires no option\n");
return gpg_error (GPG_ERR_INV_ARG);
}
if (!ctrl->have_keygrip)
{
log_error ("speculative decryption not yet supported\n");
return gpg_error (GPG_ERR_NO_SECKEY);
}
if (!ctrl->have_keygrip1)
{
log_error ("hybrid KEM requires two KEYGRIPs\n");
return gpg_error (GPG_ERR_NO_SECKEY);
}
err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen);
if (err)
{
log_error ("failed to convert ciphertext: %s\n", gpg_strerror (err));
return gpg_error (GPG_ERR_INV_DATA);
}
if (DBG_CRYPTO)
{
log_printhex (ctrl->keygrip, 20, "keygrip:");
log_printhex (ctrl->keygrip1, 20, "keygrip1:");
log_printhex (ciphertext, ciphertextlen, "cipher: ");
}
err = agent_hybrid_pgp_kem_decrypt (ctrl, desc_text, s_cipher, outbuf);
gcry_sexp_release (s_cipher);
return err;
}
diff --git a/common/kmac.c b/common/kmac.c
index 69e18a2c3..c5de8b102 100644
--- a/common/kmac.c
+++ b/common/kmac.c
@@ -1,136 +1,209 @@
-/* kmac.c - Keccak based MAC
+/* kem.c - KEM helper functions
* 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
+static 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)
{
#if GCRYPT_VERSION_NUMBER >= 0x010b00
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_ext (GCRY_MD_CSHAKE256, 0,
digest, digestlen, iov, iovcnt);
return err;
#else
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
}
+
+/* Compute KEK (shared secret) for ECC with HASHALGO, ECDH result,
+ ciphertext in ECC_CT, public key in ECC_PK. */
+gpg_error_t
+gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
+ int hashalgo, const void *ecdh, size_t ecdh_len,
+ const void *ecc_ct, size_t ecc_ct_len,
+ const void *ecc_pk, size_t ecc_pk_len)
+{
+ gcry_buffer_t iov[3];
+ unsigned int dlen;
+
+ dlen = gcry_md_get_algo_dlen (hashalgo);
+ if (kek_len != dlen)
+ return gpg_error (GPG_ERR_INV_LENGTH);
+
+ memset (iov, 0, sizeof (iov));
+
+ iov[0].data = (unsigned char *)ecdh;
+ iov[0].len = ecdh_len;
+ iov[1].data = (unsigned char *)ecc_ct;
+ iov[1].len = ecc_ct_len;
+ iov[2].data = (unsigned char *)ecc_pk;
+ iov[2].len = ecc_pk_len;
+ gcry_md_hash_buffers (hashalgo, 0, kek, iov, 3);
+
+ return 0;
+}
+
+
+/* domSeperation */
+#define KMAC_KEY "OpenPGPCompositeKeyDerivationFunction"
+
+/* customizationString */
+#define KMAC_CUSTOM "KDF"
+
+/* Compute KEK by combining two KEMs. */
+gpg_error_t
+gnupg_kem_combiner (void *kek, size_t kek_len,
+ const void *ecc_ss, size_t ecc_ss_len,
+ const void *ecc_ct, size_t ecc_ct_len,
+ const void *mlkem_ss, size_t mlkem_ss_len,
+ const void *mlkem_ct, size_t mlkem_ct_len,
+ const void *fixedinfo, size_t fixedinfo_len)
+{
+ gpg_error_t err;
+ gcry_buffer_t iov[6];
+
+ memset (iov, 0, sizeof (iov));
+
+ iov[0].data = "\x00\x00\x00\x01"; /* Counter */
+ iov[0].len = 4;
+
+ iov[1].data = (unsigned char *)ecc_ss;
+ iov[1].len = ecc_ss_len;
+
+ iov[2].data = (unsigned char *)ecc_ct;
+ iov[2].len = ecc_ct_len;
+
+ iov[3].data = (unsigned char *)mlkem_ss;
+ iov[3].len = mlkem_ss_len;
+
+ iov[4].data = (unsigned char *)mlkem_ct;
+ iov[4].len = mlkem_ct_len;
+
+ iov[5].data = (unsigned char *)fixedinfo;
+ iov[5].len = fixedinfo_len;
+
+ err = compute_kmac256 (kek, kek_len,
+ KMAC_KEY, strlen (KMAC_KEY),
+ KMAC_CUSTOM, strlen (KMAC_CUSTOM), iov, 6);
+ return err;
+}
diff --git a/common/util.h b/common/util.h
index 7b2601db1..5c953a8a1 100644
--- a/common/util.h
+++ b/common/util.h
@@ -1,415 +1,422 @@
/* util.h - Utility functions for GnuPG
* Copyright (C) 2001, 2002, 2003, 2004, 2009 Free Software Foundation, Inc.
*
* 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 .
*/
#ifndef GNUPG_COMMON_UTIL_H
#define GNUPG_COMMON_UTIL_H
#include /* We need this for the memory function protos. */
#include /* We need errno. */
#include /* We need gpg_error_t and estream. */
/* These error codes are used but not defined in the required
* libgpg-error version. Define them here.
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
*/
#if GPG_ERROR_VERSION_NUMBER < 0x012f00 /* 1.47 */
# define GPG_ERR_BAD_PUK 320
# define GPG_ERR_NO_RESET_CODE 321
# define GPG_ERR_BAD_RESET_CODE 322
#endif
#ifndef EXTERN_UNLESS_MAIN_MODULE
# if !defined (INCLUDED_BY_MAIN_MODULE)
# define EXTERN_UNLESS_MAIN_MODULE extern
# else
# define EXTERN_UNLESS_MAIN_MODULE
# endif
#endif
/* Hash function used with libksba. */
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
/* The length of the keygrip. This is a SHA-1 hash of the key
* parameters as generated by gcry_pk_get_keygrip. */
#define KEYGRIP_LEN 20
/* The length of the unique blob identifier as used by the keyboxd.
* This is the possible truncated fingerprint of the primary key. */
#define UBID_LEN 20
/* Get all the stuff from jnlib. */
#include "../common/logging.h"
#include "../common/stringhelp.h"
#include "../common/mischelp.h"
#include "../common/strlist.h"
#include "../common/dotlock.h"
#include "../common/utf8conv.h"
#include "../common/dynload.h"
#include "../common/fwddecl.h"
#include "../common/utilproto.h"
#include "gettime.h"
/* Redefine asprintf by our estream version which uses our own memory
allocator.. */
#define asprintf gpgrt_asprintf
#define vasprintf gpgrt_vasprintf
/* Due to a bug in mingw32's snprintf related to the 'l' modifier and
for increased portability we use our snprintf on all systems. */
#undef snprintf
#define snprintf gpgrt_snprintf
/* Replacements for macros not available with libgpg-error < 1.20. */
/* We need this type even if we are not using libreadline and or we
did not include libreadline in the current file. */
#ifndef GNUPG_LIBREADLINE_H_INCLUDED
typedef char **rl_completion_func_t (const char *, int, int);
#endif /*!GNUPG_LIBREADLINE_H_INCLUDED*/
/* Handy malloc macros - please use only them. */
#define xtrymalloc(a) gcry_malloc ((a))
#define xtrymalloc_secure(a) gcry_malloc_secure ((a))
#define xtrycalloc(a,b) gcry_calloc ((a),(b))
#define xtrycalloc_secure(a,b) gcry_calloc_secure ((a),(b))
#define xtryrealloc(a,b) gcry_realloc ((a),(b))
#define xtryreallocarray(a,b,c,d) gpgrt_reallocarray ((a),(b),(c),(d))
#define xtrystrdup(a) gcry_strdup ((a))
#define xfree(a) gcry_free ((a))
#define xfree_fnc gcry_free
#define xmalloc(a) gcry_xmalloc ((a))
#define xmalloc_secure(a) gcry_xmalloc_secure ((a))
#define xcalloc(a,b) gcry_xcalloc ((a),(b))
#define xcalloc_secure(a,b) gcry_xcalloc_secure ((a),(b))
#define xrealloc(a,b) gcry_xrealloc ((a),(b))
#define xstrdup(a) gcry_xstrdup ((a))
/* See also the xreallocarray prototype below. */
/* For compatibility with gpg 1.4 we also define these: */
#define xmalloc_clear(a) gcry_xcalloc (1, (a))
#define xmalloc_secure_clear(a) gcry_xcalloc_secure (1, (a))
/* The default error source of the application. This is different
from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the
source file and thus is usable in code shared by applications.
Defined by init.c. */
extern gpg_err_source_t default_errsource;
/* Convenience function to return a gpg-error code for memory
allocation failures. This function makes sure that an error will
be returned even if accidentally ERRNO is not set. */
static inline gpg_error_t
out_of_core (void)
{
return gpg_error_from_syserror ();
}
/*-- yesno.c --*/
int answer_is_yes (const char *s);
int answer_is_yes_no_default (const char *s, int def_answer);
int answer_is_yes_no_quit (const char *s);
int answer_is_okay_cancel (const char *s, int def_answer);
/*-- xreadline.c --*/
ssize_t read_line (FILE *fp,
char **addr_of_buffer, size_t *length_of_buffer,
size_t *max_length);
/*-- sexputil.c */
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
void log_printcanon (const char *text,
const unsigned char *sexp, size_t sexplen);
void log_printsexp (const char *text, gcry_sexp_t sexp);
gpg_error_t make_canon_sexp (gcry_sexp_t sexp,
unsigned char **r_buffer, size_t *r_buflen);
gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
unsigned char **r_buffer, size_t *r_buflen);
gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
unsigned char *grip);
int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);
int cmp_canon_sexp (const unsigned char *a, size_t alen,
const unsigned char *b, size_t blen,
int (*tcmp)(void *ctx, int depth,
const unsigned char *aval, size_t avallen,
const unsigned char *bval, size_t bvallen),
void *tcmpctx);
unsigned char *make_simple_sexp_from_hexstr (const char *line,
size_t *nscanned);
int hash_algo_from_sigval (const unsigned char *sigval);
unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen,
const void *e, size_t elen,
size_t *r_len);
gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
size_t keydatalen,
unsigned char const **r_n,
size_t *r_nlen,
unsigned char const **r_e,
size_t *r_elen);
gpg_error_t get_ecc_q_from_canon_sexp (const unsigned char *keydata,
size_t keydatalen,
unsigned char const **r_q,
size_t *r_qlen);
gpg_error_t uncompress_ecc_q_in_canon_sexp (const unsigned char *keydata,
size_t keydatalen,
unsigned char **r_newkeydata,
size_t *r_newkeydatalen);
int get_pk_algo_from_key (gcry_sexp_t key);
int get_pk_algo_from_canon_sexp (const unsigned char *keydata,
size_t keydatalen);
char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
const char *pubkey_algo_to_string (int algo);
const char *hash_algo_to_string (int algo);
const char *cipher_mode_to_string (int mode);
/*-- convert.c --*/
int hex2bin (const char *string, void *buffer, size_t length);
int hexcolon2bin (const char *string, void *buffer, size_t length);
char *bin2hex (const void *buffer, size_t length, char *stringbuf);
char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
const char *hex2str (const char *hexstring,
char *buffer, size_t bufsize, size_t *buflen);
char *hex2str_alloc (const char *hexstring, size_t *r_count);
unsigned int hex2fixedbuf (const char *hexstr, void *buffer, size_t bufsize);
/*-- percent.c --*/
char *percent_plus_escape (const char *string);
char *percent_data_escape (int plus, const char *prefix,
const void *data, size_t datalen);
char *percent_plus_unescape (const char *string, int nulrepl);
char *percent_unescape (const char *string, int nulrepl);
size_t percent_plus_unescape_inplace (char *string, int nulrepl);
size_t percent_unescape_inplace (char *string, int nulrepl);
/*-- openpgp-oid.c --*/
gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
char *openpgp_oidbuf_to_str (const unsigned char *buf, size_t len);
char *openpgp_oid_to_str (gcry_mpi_t a);
int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len);
int openpgp_oid_is_ed25519 (gcry_mpi_t a);
int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
int openpgp_oid_is_cv25519 (gcry_mpi_t a);
int openpgp_oid_is_cv448 (gcry_mpi_t a);
int openpgp_oid_is_ed448 (gcry_mpi_t a);
const char *openpgp_curve_to_oid (const char *name,
unsigned int *r_nbits, int *r_algo);
const char *openpgp_oid_to_curve (const char *oid, int mode);
const char *openpgp_oid_or_name_to_curve (const char *oidname, int canon);
const char *openpgp_enum_curves (int *idxp);
const char *openpgp_is_curve_supported (const char *name,
int *r_algo, unsigned int *r_nbits);
const char *get_keyalgo_string (enum gcry_pk_algos algo,
unsigned int nbits, const char *curve);
/*-- homedir.c --*/
const char *standard_homedir (void);
void gnupg_set_homedir (const char *newdir);
void gnupg_maybe_make_homedir (const char *fname, int quiet);
const char *gnupg_homedir (void);
int gnupg_default_homedir_p (void);
const char *gnupg_registry_dir (void);
const char *gnupg_daemon_rootdir (void);
const char *gnupg_socketdir (void);
const char *gnupg_sysconfdir (void);
const char *gnupg_bindir (void);
const char *gnupg_libexecdir (void);
const char *gnupg_libdir (void);
const char *gnupg_datadir (void);
const char *gnupg_localedir (void);
const char *gpg_agent_socket_name (void);
const char *dirmngr_socket_name (void);
const char *keyboxd_socket_name (void);
char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
/* All module names. We also include gpg and gpgsm for the sake for
gpgconf. */
#define GNUPG_MODULE_NAME_AGENT 1
#define GNUPG_MODULE_NAME_PINENTRY 2
#define GNUPG_MODULE_NAME_SCDAEMON 3
#define GNUPG_MODULE_NAME_DIRMNGR 4
#define GNUPG_MODULE_NAME_PROTECT_TOOL 5
#define GNUPG_MODULE_NAME_CHECK_PATTERN 6
#define GNUPG_MODULE_NAME_GPGSM 7
#define GNUPG_MODULE_NAME_GPG 8
#define GNUPG_MODULE_NAME_CONNECT_AGENT 9
#define GNUPG_MODULE_NAME_GPGCONF 10
#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11
#define GNUPG_MODULE_NAME_GPGV 12
#define GNUPG_MODULE_NAME_KEYBOXD 13
#define GNUPG_MODULE_NAME_TPM2DAEMON 14
#define GNUPG_MODULE_NAME_CARD 15
#define GNUPG_MODULE_NAME_GPGTAR 16
const char *gnupg_module_name (int which);
void gnupg_module_name_flush_some (void);
void gnupg_set_builddir (const char *newdir);
/* A list of constants to identify protocols. This is used by tools
* which need to distinguish between the different protocols
* implemented by GnuPG. May be used as bit flags. */
#define GNUPG_PROTOCOL_OPENPGP 1 /* The one and only (gpg). */
#define GNUPG_PROTOCOL_CMS 2 /* The core of S/MIME (gpgsm) */
#define GNUPG_PROTOCOL_SSH_AGENT 4 /* Out ssh-agent implementation */
/*-- gpgrlhelp.c --*/
void gnupg_rl_initialize (void);
/*-- helpfile.c --*/
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);
+/*-- kem.c --*/
+gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
+ int hashalgo, const void *ecdh, size_t ecdh_len,
+ const void *ecc_ct, size_t ecc_ct_len,
+ const void *ecc_pk, size_t ecc_pk_len);
+
+gpg_error_t gnupg_kem_combiner (void *kek, size_t kek_len,
+ const void *ecc_ss, size_t ecc_ss_len,
+ const void *ecc_ct, size_t ecc_ct_len,
+ const void *mlkem_ss, size_t mlkem_ss_len,
+ const void *mlkem_ct, size_t mlkem_ct_len,
+ const void *fixedinfo, size_t fixedinfo_len);
/*-- miscellaneous.c --*/
/* This function is called at startup to tell libgcrypt to use our own
logging subsystem. */
void setup_libgcrypt_logging (void);
/* Print an out of core message and die. */
void xoutofcore (void);
/* Wrapper aroung gpgrt_reallocarray. Uses the gpgrt alloc function
* which redirects to the Libgcrypt versions via
* init_common_subsystems. Thus this can be used interchangeable with
* the other alloc functions. */
void *xreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size);
/* Same as estream_asprintf but die on memory failure. */
char *xasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
/* This is now an alias to estream_asprintf. */
char *xtryasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
/* Replacement for gcry_cipher_algo_name. */
const char *gnupg_cipher_algo_name (int algo);
void obsolete_option (const char *configname, unsigned int configlineno,
const char *name);
const char *print_fname_stdout (const char *s);
const char *print_fname_stdin (const char *s);
void print_utf8_buffer3 (estream_t fp, const void *p, size_t n,
const char *delim);
void print_utf8_buffer2 (estream_t fp, const void *p, size_t n, int delim);
void print_utf8_buffer (estream_t fp, const void *p, size_t n);
void print_utf8_string (estream_t stream, const char *p);
void print_hexstring (FILE *fp, const void *buffer, size_t length,
int reserved);
char *try_make_printable_string (const void *p, size_t n, int delim);
char *make_printable_string (const void *p, size_t n, int delim);
char *decode_c_string (const char *src);
int match_multistr (const char *multistr,const char *match);
int gnupg_compare_version (const char *a, const char *b);
struct debug_flags_s
{
unsigned int flag;
const char *name;
};
int parse_debug_flag (const char *string, unsigned int *debugvar,
const struct debug_flags_s *flags);
struct compatibility_flags_s
{
unsigned int flag;
const char *name;
const char *desc;
};
int parse_compatibility_flags (const char *string, unsigned int *flagvar,
const struct compatibility_flags_s *flags);
gpg_error_t b64decode (const char *string, const char *title,
void **r_buffer, size_t *r_buflen);
/*-- Simple replacement functions. */
/* We use the gnupg_ttyname macro to be safe not to run into conflicts
with an existing but broken ttyname. */
#if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME)
# define gnupg_ttyname(n) _gnupg_ttyname ((n))
/* Systems without ttyname (W32) will merely return NULL. */
static inline char *
_gnupg_ttyname (int fd)
{
(void)fd;
return NULL;
}
#else /*HAVE_TTYNAME*/
# define gnupg_ttyname(n) ttyname ((n))
#endif /*HAVE_TTYNAME */
#define gnupg_isatty(a) isatty ((a))
/*-- Macros to replace ctype ones to avoid locale problems. --*/
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define alphap(p) ((*(p) >= 'A' && *(p) <= 'Z') \
|| (*(p) >= 'a' && *(p) <= 'z'))
#define alnump(p) (alphap (p) || digitp (p))
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
/* Note this isn't identical to a C locale isspace() without \f and
\v, but works for the purposes used here. */
#define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
/* The atoi macros assume that the buffer has only valid digits. */
#define atoi_1(p) (*(p) - '0' )
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
#define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2))
#endif /*GNUPG_COMMON_UTIL_H*/