1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-05-24 16:43:28 +02:00

gpg: Use ECC KEM interface for decryption.

* g10/call-agent.c (agent_pkdecrypt): Use --kem=PGP for
PUBKEY_ALGO_ECDH.
* g10/pubkey-enc.c (ecdh_sexp_build): New.
(get_it): Use ecdh_sexp_build for PUBKEY_ALGO_ECDH.  And don't use
pk_ecdh_decrypt since it's done by agent.

--

GnuPG-bug-id: 7649
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2025-05-22 14:36:38 +09:00
parent 04782e7fd6
commit 07e8ca2a9b
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054
2 changed files with 83 additions and 29 deletions

View File

@ -2909,6 +2909,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
char *p, *buf, *endp;
const char *keygrip2 = NULL;
struct default_inq_parm_s dfltparm;
const char *cmdline;
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctrl = ctrl;
@ -2935,6 +2936,12 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
return gpg_error (GPG_ERR_INV_VALUE);
}
if (*keygrip2)
cmdline = "PKDECRYPT --kem=PQC-PGP";
else if (pubkey_algo == PUBKEY_ALGO_ECDH)
cmdline = "PKDECRYPT --kem=PGP";
else
cmdline = "PKDECRYPT";
err = start_agent (ctrl, 0);
if (err)
@ -2977,8 +2984,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
err = make_canon_sexp (s_ciphertext, &parm.ciphertext, &parm.ciphertextlen);
if (err)
return err;
err = assuan_transact (agent_ctx,
*keygrip2? "PKDECRYPT --kem=PQC-PGP":"PKDECRYPT",
err = assuan_transact (agent_ctx, cmdline,
put_membuf_cb, &data,
inq_ciphertext_cb, &parm,
padding_info_cb, r_padding);

View File

@ -188,6 +188,80 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
}
/* Build an SEXP to gpg-agent, for PKDECRYPT command. */
static gpg_error_t
ecdh_sexp_build (gcry_sexp_t *r_s_data, struct pubkey_enc_list *enc,
PKT_public_key *sk)
{
gpg_error_t err;
const unsigned char *oid;
const unsigned char *kdf_params_spec;
unsigned int nbits;
size_t len;
size_t oid_len;
byte fp[MAX_FINGERPRINT_LEN];
int keywrap_cipher_algo;
int kdf_hash_algo;
unsigned char *kdf_params = NULL;
int kdf_params_len = 0;
if (!gcry_mpi_get_flag (sk->pkey[0], GCRYMPI_FLAG_OPAQUE))
return gpg_error (GPG_ERR_BAD_PUBKEY);
oid = gcry_mpi_get_opaque (sk->pkey[0], &nbits);
oid_len = (nbits+7)/8;
/* In the public key part of SK, there is a specifier of KDF
parameters (namely, hash algo for KDF and symmetric algo for
wrapping key). Using this specifier (together with curve OID
of the public key and the fingerprint), we build _the_ KDF
parameters. */
if (!gcry_mpi_get_flag (sk->pkey[2], GCRYMPI_FLAG_OPAQUE))
return gpg_error (GPG_ERR_BAD_PUBKEY);
kdf_params_spec = gcry_mpi_get_opaque (sk->pkey[2], &nbits);
len = (nbits+7)/8;
fingerprint_from_pk (sk, fp, NULL);
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
if (len != 4 || kdf_params_spec[0] != 3 || kdf_params_spec[1] != 1)
return gpg_error (GPG_ERR_BAD_PUBKEY);
kdf_params_len = oid_len + 1 + 4 + 20 + 20;
kdf_params = xtrymalloc (kdf_params_len);
if (!kdf_params)
return gpg_error_from_syserror ();
memcpy (kdf_params, oid, oid_len);
kdf_params[oid_len] = PUBKEY_ALGO_ECDH;
memcpy (kdf_params + oid_len + 1, kdf_params_spec, 4);
memcpy (kdf_params + oid_len + 1 + 4, "Anonymous Sender ", 20);
memcpy (kdf_params + oid_len + 1 + 4 + 20, fp, 20);
if (DBG_CRYPTO)
log_printhex (kdf_params, kdf_params_len,
"ecdh KDF message params are:");
keywrap_cipher_algo = kdf_params_spec[3];
kdf_hash_algo = kdf_params_spec[2];
if (!enc->d.data[0] || !enc->d.data[1])
{
xfree (kdf_params);
return gpg_error (GPG_ERR_BAD_MPI);
}
err = gcry_sexp_build (r_s_data, NULL,
"(enc-val(ecc(c%d)(h%d)(e%m)(s%m)(kdf-params%b)))",
keywrap_cipher_algo, kdf_hash_algo,
enc->d.data[0], enc->d.data[1],
kdf_params_len, kdf_params);
xfree (kdf_params);
return err;
}
static gpg_error_t
get_it (ctrl_t ctrl,
struct pubkey_enc_list *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
@ -201,7 +275,6 @@ get_it (ctrl_t ctrl,
gcry_sexp_t s_data;
char *desc;
char *keygrip;
byte fp[MAX_FINGERPRINT_LEN];
if (DBG_CLOCK)
log_clock ("decryption start");
@ -231,13 +304,7 @@ get_it (ctrl_t ctrl,
enc->d.data[0]);
}
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
if (!enc->d.data[0] || !enc->d.data[1])
err = gpg_error (GPG_ERR_BAD_MPI);
else
err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))",
enc->d.data[1], enc->d.data[0]);
}
err = ecdh_sexp_build (&s_data, enc, sk);
else if (sk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
char fixedinfo[1+MAX_FINGERPRINT_LEN];
@ -270,9 +337,6 @@ get_it (ctrl_t ctrl,
if (err)
goto leave;
if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
fingerprint_from_pk (sk, fp, NULL);
/* Decrypt. */
desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1);
@ -316,22 +380,6 @@ get_it (ctrl_t ctrl,
}
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
gcry_mpi_t decoded;
/* At the beginning the frame are the bytes of shared point MPI. */
err = pk_ecdh_decrypt (&decoded, fp,
enc->d.data[1], /*encr data as an MPI*/
frame, nframe,
sk->pkey);
if(err)
goto leave;
xfree (frame);
err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded);
mpi_release (decoded);
if (err)
goto leave;
/* Now the frame are the bytes decrypted but padded session key. */
if (!nframe || nframe <= 8
|| frame[nframe-1] > nframe)