1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-01 22:28:02 +02:00

agent:kem: Support other ECC curves.

* agent/pkdecrypt.c (ecc_table): New.
(get_ecc_params): New.
(composite_pgp_kem_decrypt): Support other curves.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2024-04-23 14:23:27 +09:00
parent aa15272ba1
commit d5c6b52e59
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054

View File

@ -173,6 +173,64 @@ reverse_buffer (unsigned char *buffer, unsigned int length)
} }
} }
struct ecc_params
{
int name_len;
const char *curve;
size_t pubkey_len; /* Pubkey in the SEXP representation. */
size_t scalar_len;
size_t point_len;
size_t shared_len;
int hash_algo;
int algo;
int scalar_reverse;
};
static const struct ecc_params ecc_table[] =
{
{
10, "Curve25519",
33, 32, 32, 32,
GCRY_MD_SHA3_256, GCRY_KEM_RAW_X25519,
1
},
{
4, "X448",
56, 56, 56, 64,
GCRY_MD_SHA3_512, GCRY_KEM_RAW_X448,
0
},
{
15, "brainpoolP256r1",
65, 32, 65, 32,
GCRY_MD_SHA3_256, GCRY_KEM_RAW_BP256,
0
},
{
15, "brainpoolP384r1",
97, 48, 97, 64,
GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP384,
0
},
{ 0, NULL, 0, 0, 0, 0, 0, 0, 0 }
};
static const struct ecc_params *
get_ecc_params (const char *curve, size_t curve_len)
{
int i, name_len;
for (i = 0; (name_len = ecc_table[i].name_len); i++)
if (name_len == curve_len && !memcmp (ecc_table[i].curve, curve, name_len))
return &ecc_table[i];
return NULL;
}
#define ECC_SCALAR_LEN_MAX 64
#define ECC_POINT_LEN_MAX (1+2*64)
#define ECC_HASH_LEN_MAX 64
/* For composite PGP KEM (ECC+ML-KEM), decrypt CIPHERTEXT using KEM API. /* For composite PGP KEM (ECC+ML-KEM), decrypt CIPHERTEXT using KEM API.
First keygrip is for ECC, second keygrip is for PQC. CIPHERTEXT First keygrip is for ECC, second keygrip is for PQC. CIPHERTEXT
should follow the format of: should follow the format of:
@ -195,6 +253,7 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
gcry_sexp_t s_skey1 = NULL; gcry_sexp_t s_skey1 = NULL;
unsigned char *shadow_info = NULL; unsigned char *shadow_info = NULL;
gpg_error_t err = 0; gpg_error_t err = 0;
const struct ecc_params *ecc;
unsigned int nbits; unsigned int nbits;
const unsigned char *p; const unsigned char *p;
@ -206,14 +265,13 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
size_t encrypted_sessionkey_len; size_t encrypted_sessionkey_len;
gcry_mpi_t ecc_sk_mpi = NULL; gcry_mpi_t ecc_sk_mpi = NULL;
unsigned char ecc_sk[32]; unsigned char ecc_sk[ECC_SCALAR_LEN_MAX];
gcry_mpi_t ecc_pk_mpi = NULL; gcry_mpi_t ecc_pk_mpi = NULL;
unsigned char ecc_pk[32]; unsigned char ecc_pk[ECC_POINT_LEN_MAX];
gcry_mpi_t ecc_ct_mpi = NULL; gcry_mpi_t ecc_ct_mpi = NULL;
const unsigned char *ecc_ct; const unsigned char *ecc_ct;
size_t ecc_ct_len; unsigned char ecc_ecdh[ECC_POINT_LEN_MAX];
unsigned char ecc_ecdh[32]; unsigned char ecc_ss[ECC_HASH_LEN_MAX];
unsigned char ecc_ss[32];
gcry_mpi_t mlkem_sk_mpi = NULL; gcry_mpi_t mlkem_sk_mpi = NULL;
gcry_mpi_t mlkem_ct_mpi = NULL; gcry_mpi_t mlkem_ct_mpi = NULL;
@ -275,7 +333,7 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
goto leave; goto leave;
} }
/* Fistly, ECC part. FIXME: For now, we assume X25519. */ /* Firstly, ECC part. */
curve = gcry_sexp_find_token (s_skey0, "curve", 0); curve = gcry_sexp_find_token (s_skey0, "curve", 0);
if (!curve) if (!curve)
{ {
@ -286,7 +344,8 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
} }
curve_name = gcry_sexp_nth_data (curve, 1, &len); curve_name = gcry_sexp_nth_data (curve, 1, &len);
if (len != 10 || memcmp (curve_name, "Curve25519", len)) ecc = get_ecc_params (curve_name, len);
if (!ecc)
{ {
if (opt.verbose) if (opt.verbose)
log_info ("%s: curve '%s' not supported\n", __func__, curve_name); log_info ("%s: curve '%s' not supported\n", __func__, curve_name);
@ -305,45 +364,63 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits); p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits);
len = (nbits+7)/8; len = (nbits+7)/8;
if (len != 33) if (len != ecc->pubkey_len)
{ {
if (opt.verbose) if (opt.verbose)
log_info ("%s: ECC public key length invalid (%zu)\n", __func__, len); log_info ("%s: ECC public key length invalid (%zu)\n", __func__, len);
err = gpg_error (GPG_ERR_INV_DATA); err = gpg_error (GPG_ERR_INV_DATA);
goto leave; goto leave;
} }
memcpy (ecc_pk, p+1, 32); /* Remove the 0x40 prefix */ else if (len == ecc->point_len)
memcpy (ecc_pk, p, ecc->point_len);
else if (len == ecc->point_len + 1 && p[0] == 0x40)
/* Remove the 0x40 prefix (for Curve25519) */
memcpy (ecc_pk, p+1, ecc->point_len);
else
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
mpi_release (ecc_pk_mpi); mpi_release (ecc_pk_mpi);
ecc_pk_mpi = NULL;
p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits); p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits);
len = (nbits+7)/8; len = (nbits+7)/8;
if (len > 32) if (len > ecc->scalar_len)
{ {
if (opt.verbose) if (opt.verbose)
log_info ("%s: ECC secret key too long (%zu)\n", __func__, len); log_info ("%s: ECC secret key too long (%zu)\n", __func__, len);
err = gpg_error (GPG_ERR_INV_DATA); err = gpg_error (GPG_ERR_INV_DATA);
goto leave; goto leave;
} }
memset (ecc_sk, 0, 32); memset (ecc_sk, 0, ecc->scalar_len - len);
memcpy (ecc_sk + 32 - len, p, len); memcpy (ecc_sk + ecc->scalar_len - len, p, len);
reverse_buffer (ecc_sk, 32); if (ecc->scalar_reverse)
reverse_buffer (ecc_sk, ecc->scalar_len);
mpi_release (ecc_sk_mpi); mpi_release (ecc_sk_mpi);
ecc_pk_mpi = NULL;
ecc_sk_mpi = NULL; ecc_sk_mpi = NULL;
ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits); ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits);
ecc_ct_len = (nbits+7)/8; if (ecc->point_len != (nbits+7)/8)
if (ecc_ct_len != 32)
{ {
if (opt.verbose) if (opt.verbose)
log_info ("%s: ECC cipher text length invalid (%zu)\n", log_info ("%s: ECC cipher text length invalid (%zu)\n",
__func__, ecc_ct_len); __func__, ecc->point_len);
err = gpg_error (GPG_ERR_INV_DATA); err = gpg_error (GPG_ERR_INV_DATA);
goto leave; goto leave;
} }
err = gcry_kem_decap (GCRY_KEM_RAW_X25519, ecc_sk, 32, ecc_ct, ecc_ct_len, if (DBG_CRYPTO)
ecc_ecdh, 32, NULL, 0); {
log_debug ("ECC curve: %s\n", curve_name);
log_printhex (ecc_pk, ecc->pubkey_len, "ECC pubkey:");
log_printhex (ecc_sk, ecc->scalar_len, "ECC seckey:");
log_printhex (ecc_ct, ecc->point_len, "ECC ephem:");
}
err = gcry_kem_decap (ecc->algo, ecc_sk, ecc->scalar_len,
ecc_ct, ecc->point_len, ecc_ecdh, ecc->point_len, NULL, 0);
if (err) if (err)
{ {
if (opt.verbose) if (opt.verbose)
@ -351,8 +428,12 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
goto leave; goto leave;
} }
err = gnupg_ecc_kem_kdf (ecc_ss, 32, GCRY_MD_SHA3_256, if (DBG_CRYPTO)
ecc_ecdh, 32, ecc_ct, 32, ecc_pk, 32); log_printhex (ecc_ecdh, ecc->point_len, "ECC ecdh:");
err = gnupg_ecc_kem_kdf (ecc_ss, ecc->shared_len, ecc->hash_algo,
ecc_ecdh, ecc->scalar_len, ecc_ct, ecc->point_len,
ecc_pk, ecc->point_len);
if (err) if (err)
{ {
if (opt.verbose) if (opt.verbose)
@ -360,6 +441,9 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
goto leave; goto leave;
} }
if (DBG_CRYPTO)
log_printhex (ecc_ss, ecc->shared_len, "ECC shared:");
/* Secondly, PQC part. For now, we assume ML-KEM. */ /* Secondly, PQC part. For now, we assume ML-KEM. */
err = gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL); err = gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL);
if (err) if (err)