1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-03 16:53:03 +01:00

Experiment with new KEM API of libgcrypt for Curve25519.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2024-01-24 16:36:21 +09:00
parent ccfbb9ebdf
commit eaa3be7ff2
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054

View File

@ -430,6 +430,7 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_sexp_t s_data = NULL; gcry_sexp_t s_data = NULL;
gcry_sexp_t s_pkey = NULL; gcry_sexp_t s_pkey = NULL;
int rc; int rc;
int with_ecdh_cv25519 = 0;
/* Make a sexp from pkey. */ /* Make a sexp from pkey. */
if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
@ -451,6 +452,127 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
rc = gcry_sexp_build (&s_data, NULL, "%m", data); rc = gcry_sexp_build (&s_data, NULL, "%m", data);
} }
else if (algo == PUBKEY_ALGO_ECDH) else if (algo == PUBKEY_ALGO_ECDH)
{
with_ecdh_cv25519 = openpgp_oid_is_cv25519 (pkey[0]);
if (with_ecdh_cv25519)
{
unsigned char ephemkey[GCRY_KEM_ECC_X25519_ENCAPS_LEN+1];
unsigned int nbits;
const byte *oid;
const byte *pubkey;
const byte *kek_params;
unsigned char kdf_params[256];
size_t oidlen;
size_t pubkeylen;
size_t kdf_params_size;
byte fp[MAX_FINGERPRINT_LEN];
byte *kekkey;
size_t kekkeylen;
int kdf_encr_algo;
gcry_cipher_hd_t hd;
oid = gcry_mpi_get_opaque (pkey[0], &nbits);
oidlen = (nbits + 7) / 8;
pubkey = (const byte *)gcry_mpi_get_opaque (pkey[1], &nbits) + 1;
pubkeylen = (nbits + 7) / 8 - 1;
/*FIXME check pubkeylen == GCRY_KEM_ECC_X25519_PUBKEY_LEN */
(void)pubkeylen;
kek_params = gcry_mpi_get_opaque (pkey[2], &nbits);
/*FIXME check nbits good: 4-byte long*/
kdf_encr_algo = kek_params[3];
if (kdf_encr_algo != CIPHER_ALGO_AES
&& kdf_encr_algo != CIPHER_ALGO_AES192
&& kdf_encr_algo != CIPHER_ALGO_AES256)
return gpg_error (GPG_ERR_BAD_PUBKEY);
kekkeylen = gcry_cipher_get_algo_keylen (kdf_encr_algo);
kekkey = xtrymalloc_secure (kekkeylen);
if (!kekkey)
return gpg_error_from_syserror ();
fingerprint_from_pk (pk, fp, NULL);
memcpy (kdf_params, oid, oidlen);
kdf_params_size = oidlen;
kdf_params[kdf_params_size++] = PUBKEY_ALGO_ECDH;
memcpy (kdf_params + kdf_params_size, kek_params, 4);
kdf_params_size += 4;
memcpy (kdf_params + kdf_params_size, "Anonymous Sender ", 20);
kdf_params_size += 20;
memcpy (kdf_params + kdf_params_size, fp, 20);
kdf_params_size += 20;
rc = gcry_kem_encap (GCRY_KEM_PGP_X25519,
pubkey, GCRY_KEM_ECC_X25519_PUBKEY_LEN,
ephemkey+1, GCRY_KEM_ECC_X25519_ENCAPS_LEN,
kekkey, kekkeylen,
kdf_params, kdf_params_size);
if (rc)
{
xfree (kekkey);
return rc;
}
rc = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
if (rc)
{
log_error ("ecdh failed to initialize AESWRAP: %s\n",
gpg_strerror (rc));
xfree (kekkey);
return rc;
}
rc = gcry_cipher_setkey (hd, kekkey, kekkeylen);
xfree (kekkey);
if (rc)
{
gcry_cipher_close (hd);
log_error ("ecdh failed in gcry_cipher_setkey: %s\n",
gpg_strerror (rc));
return rc;
}
{
byte *data_buf;
int data_buf_size;
byte *p = gcry_mpi_get_opaque (data, &nbits);
size_t ndata = (nbits + 7)/8;
byte *in;
gcry_mpi_t result;
data_buf_size = ndata;
data_buf = xtrymalloc_secure (1 + 2*data_buf_size + 8);
if (!data_buf)
return gpg_error_from_syserror ();
in = data_buf + 1 + data_buf_size + 8;
memcpy (in, p, ndata);
gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8,
in, data_buf_size);
memset (in, 0, data_buf_size);
gcry_cipher_close (hd);
data_buf[0] = data_buf_size+8;
result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0]));
if (!result)
{
rc = gpg_error_from_syserror ();
xfree (data_buf);
return rc;
}
ephemkey[0] = 0x40;
resarr[0] = gcry_mpi_set_opaque_copy (NULL, ephemkey,
sizeof (ephemkey) * 8);
resarr[1] = result;
rc = 0;
}
return rc;
}
else
{ {
gcry_mpi_t k; gcry_mpi_t k;
@ -464,7 +586,7 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
else else
{ {
int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]); int with_djb_tweak_flag = with_ecdh_cv25519;
/* Now use the ephemeral secret to compute the shared point. */ /* Now use the ephemeral secret to compute the shared point. */
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
@ -480,6 +602,7 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_mpi_release (k); gcry_mpi_release (k);
} }
} }
}
else else
rc = gpg_error (GPG_ERR_PUBKEY_ALGO); rc = gpg_error (GPG_ERR_PUBKEY_ALGO);