aboutsummaryrefslogtreecommitdiffstats
path: root/g10/pkglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/pkglue.c')
-rw-r--r--g10/pkglue.c593
1 files changed, 483 insertions, 110 deletions
diff --git a/g10/pkglue.c b/g10/pkglue.c
index f18313913..f4efa8fc5 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -1,6 +1,7 @@
/* pkglue.c - public key operations glue code
* Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2024 g10 Code GmbH.
*
* This file is part of GnuPG.
*
@@ -16,6 +17,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
@@ -30,6 +32,12 @@
#include "main.h"
#include "options.h"
+
+/* Maximum buffer sizes required for ECC KEM. */
+#define ECC_POINT_LEN_MAX (1+2*64)
+#define ECC_HASH_LEN_MAX 64
+
+
/* FIXME: Better change the function name because mpi_ is used by
gcrypt macros. */
gcry_mpi_t
@@ -415,140 +423,505 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
}
+#if GCRY_KEM_MLKEM1024_ENCAPS_LEN < GCRY_KEM_MLKEM768_ENCAPS_LEN \
+ || GCRY_KEM_MLKEM1024_SHARED_LEN < GCRY_KEM_MLKEM768_SHARED_LEN
+# error Bad Kyber constants in Libgcrypt
+#endif
-
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- * PK is only required to compute the fingerprint for ECDH.
- */
-int
-pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
- PKT_public_key *pk, gcry_mpi_t *pkey)
+/* Core of the encryption for KEM algorithms. See pk_decrypt for a
+ * description of the arguments. */
+static gpg_error_t
+do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
+ gcry_mpi_t *resarr)
{
- gcry_sexp_t s_ciph = NULL;
+ gpg_error_t err;
+ int i;
+ unsigned int nbits, n;
gcry_sexp_t s_data = NULL;
- gcry_sexp_t s_pkey = NULL;
- int rc;
-
- /* Make a sexp from pkey. */
- if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
- {
- rc = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(elg(p%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2]);
- /* Put DATA into a simplified S-expression. */
- if (!rc)
- rc = gcry_sexp_build (&s_data, NULL, "%m", data);
- }
- else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
+ gcry_cipher_hd_t hd = NULL;
+ char *ecc_oid = NULL;
+ enum gcry_kem_algos kyber_algo, ecc_algo;
+
+ const unsigned char *ecc_pubkey;
+ size_t ecc_pubkey_len;
+ const unsigned char *kyber_pubkey;
+ size_t kyber_pubkey_len;
+ const unsigned char *seskey;
+ size_t seskey_len;
+ unsigned char *enc_seskey = NULL;
+ size_t enc_seskey_len;
+ int ecc_hash_algo;
+
+ unsigned char ecc_ct[ECC_POINT_LEN_MAX];
+ unsigned char ecc_ecdh[ECC_POINT_LEN_MAX];
+ unsigned char ecc_ss[ECC_HASH_LEN_MAX];
+ size_t ecc_ct_len, ecc_ecdh_len, ecc_ss_len;
+
+ unsigned char kyber_ct[GCRY_KEM_MLKEM1024_ENCAPS_LEN];
+ unsigned char kyber_ss[GCRY_KEM_MLKEM1024_SHARED_LEN];
+ size_t kyber_ct_len, kyber_ss_len;
+
+ char fixedinfo[1+MAX_FINGERPRINT_LEN];
+ int fixedlen;
+
+ unsigned char kek[32]; /* AES-256 is mandatory. */
+ size_t kek_len = 32;
+
+ /* For later error checking we make sure the array is cleared. */
+ resarr[0] = resarr[1] = resarr[2] = NULL;
+
+ /* As of now we use KEM only for the combined Kyber and thus a
+ * second public key is expected. Right now we take the keys
+ * directly from the PK->data elements. */
+
+ ecc_oid = openpgp_oid_to_str (pk->pkey[0]);
+ if (!ecc_oid)
{
- rc = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(rsa(n%m)(e%m)))",
- pkey[0], pkey[1]);
- /* Put DATA into a simplified S-expression. */
- if (!rc)
- rc = gcry_sexp_build (&s_data, NULL, "%m", data);
+ err = gpg_error_from_syserror ();
+ log_error ("%s: error getting OID for ECC key\n", __func__);
+ goto leave;
}
- else if (algo == PUBKEY_ALGO_ECDH)
+ ecc_algo = openpgp_oid_to_kem_algo (ecc_oid);
+ if (ecc_algo == GCRY_KEM_RAW_X25519)
{
- gcry_mpi_t k;
-
- rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
- if (!rc)
+ if (!strcmp (ecc_oid, "1.3.6.1.4.1.3029.1.5.1"))
+ log_info ("Warning: "
+ "legacy OID for cv25519 accepted during develpment\n");
+ ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len == 33 && *ecc_pubkey == 0x40)
{
- char *curve;
-
- curve = openpgp_oid_to_str (pkey[0]);
- if (!curve)
- rc = gpg_error_from_syserror ();
- else
- {
- int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]);
-
- /* Now use the ephemeral secret to compute the shared point. */
- rc = gcry_sexp_build (&s_pkey, NULL,
- with_djb_tweak_flag ?
- "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))"
- : "(public-key(ecdh(curve%s)(q%m)))",
- curve, pkey[1]);
- xfree (curve);
- /* Put K into a simplified S-expression. */
- if (!rc)
- rc = gcry_sexp_build (&s_data, NULL, "%m", k);
- }
- gcry_mpi_release (k);
+ ecc_pubkey++; /* Remove the 0x40 prefix. */
+ ecc_pubkey_len--;
}
- }
- else
- rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
-
- /* Pass it to libgcrypt. */
- if (!rc)
- rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
-
- gcry_sexp_release (s_data);
- gcry_sexp_release (s_pkey);
-
- if (rc)
- ;
- else if (algo == PUBKEY_ALGO_ECDH)
- {
- gcry_mpi_t public, result;
- byte fp[MAX_FINGERPRINT_LEN];
- byte *shared;
- size_t nshared;
-
- /* Get the shared point and the ephemeral public key. */
- shared = get_data_from_sexp (s_ciph, "s", &nshared);
- if (!shared)
+ if (ecc_pubkey_len != 32)
{
- rc = gpg_error_from_syserror ();
+ if (opt.verbose)
+ log_info ("%s: ECC public key length invalid (%zu)\n",
+ __func__, ecc_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
- rc = sexp_extract_param_sos (s_ciph, "e", &public);
- gcry_sexp_release (s_ciph);
- s_ciph = NULL;
- if (DBG_CRYPTO)
+ ecc_ct_len = ecc_ecdh_len = 32;
+ ecc_ss_len = 32;
+ ecc_hash_algo = GCRY_MD_SHA3_256;
+ }
+ else if (ecc_algo == GCRY_KEM_RAW_X448)
+ {
+ ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len != 56)
{
- log_debug ("ECDH ephemeral key:");
- gcry_mpi_dump (public);
- log_printf ("\n");
+ if (opt.verbose)
+ log_info ("%s: ECC public key length invalid (%zu)\n",
+ __func__, ecc_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
}
-
- result = NULL;
- fingerprint_from_pk (pk, fp, NULL);
-
- if (!rc)
+ ecc_ct_len = ecc_ecdh_len = 56;
+ ecc_ss_len = 64;
+ ecc_hash_algo = GCRY_MD_SHA3_512;
+ }
+ else if (ecc_algo == GCRY_KEM_RAW_BP256)
+ {
+ ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len != 65)
{
- unsigned int nbits;
- byte *p = gcry_mpi_get_opaque (data, &nbits);
- rc = pk_ecdh_encrypt_with_shared_point (shared, nshared, fp, p,
- (nbits+7)/8, pkey, &result);
+ if (opt.verbose)
+ log_info ("%s: ECC public key length invalid (%zu)\n",
+ __func__, ecc_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
}
- xfree (shared);
- if (!rc)
+ ecc_ct_len = ecc_ecdh_len = 65;
+ ecc_ss_len = 32;
+ ecc_hash_algo = GCRY_MD_SHA3_256;
+ }
+ else if (ecc_algo == GCRY_KEM_RAW_BP384)
+ {
+ ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len != 97)
{
- resarr[0] = public;
- resarr[1] = result;
+ if (opt.verbose)
+ log_info ("%s: ECC public key length invalid (%zu)\n",
+ __func__, ecc_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
}
- else
+ ecc_ct_len = ecc_ecdh_len = 97;
+ ecc_ss_len = 64;
+ ecc_hash_algo = GCRY_MD_SHA3_512;
+ }
+ else if (ecc_algo == GCRY_KEM_RAW_BP512)
+ {
+ ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len != 129)
{
- gcry_mpi_release (public);
- gcry_mpi_release (result);
+ if (opt.verbose)
+ log_info ("%s: ECC public key length invalid (%zu)\n",
+ __func__, ecc_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
}
+ ecc_ct_len = ecc_ecdh_len = 129;
+ ecc_ss_len = 64;
+ ecc_hash_algo = GCRY_MD_SHA3_512;
}
- else /* Elgamal or RSA case. */
- { /* Fixme: Add better error handling or make gnupg use
- S-expressions directly. */
- resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
- if (!is_RSA (algo))
- resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
+ else
+ {
+ if (opt.verbose)
+ log_info ("%s: ECC curve %s not supported\n", __func__, ecc_oid);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
+ }
+
+
+ if (DBG_CRYPTO)
+ {
+ log_debug ("ECC curve: %s\n", ecc_oid);
+ log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:");
}
+ err = gcry_kem_encap (ecc_algo,
+ ecc_pubkey, ecc_pubkey_len,
+ ecc_ct, ecc_ct_len,
+ ecc_ecdh, ecc_ecdh_len,
+ NULL, 0);
+ if (err)
+ {
+ if (opt.verbose)
+ log_info ("%s: gcry_kem_encap for ECC (%s) failed\n",
+ __func__, ecc_oid);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ {
+ log_printhex (ecc_ct, ecc_ct_len, "ECC ephem:");
+ log_printhex (ecc_ecdh, ecc_ecdh_len, "ECC ecdh:");
+ }
+ err = gnupg_ecc_kem_kdf (ecc_ss, ecc_ss_len,
+ ecc_hash_algo,
+ ecc_ecdh, ecc_ecdh_len,
+ ecc_ct, ecc_ct_len,
+ ecc_pubkey, ecc_pubkey_len);
+ if (err)
+ {
+ if (opt.verbose)
+ log_info ("%s: kdf for ECC failed\n", __func__);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ log_printhex (ecc_ss, ecc_ss_len, "ECC shared:");
+
+ kyber_pubkey = gcry_mpi_get_opaque (pk->pkey[2], &nbits);
+ kyber_pubkey_len = (nbits+7)/8;
+ if (kyber_pubkey_len == GCRY_KEM_MLKEM768_PUBKEY_LEN)
+ {
+ kyber_algo = GCRY_KEM_MLKEM768;
+ kyber_ct_len = GCRY_KEM_MLKEM768_ENCAPS_LEN;
+ kyber_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN;
+ }
+ else if (kyber_pubkey_len == GCRY_KEM_MLKEM1024_PUBKEY_LEN)
+ {
+ kyber_algo = GCRY_KEM_MLKEM1024;
+ kyber_ct_len = GCRY_KEM_MLKEM1024_ENCAPS_LEN;
+ kyber_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN;
+ }
+ else
+ {
+ if (opt.verbose)
+ log_info ("%s: Kyber public key length invalid (%zu)\n",
+ __func__, kyber_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ log_printhex (kyber_pubkey, kyber_pubkey_len, "|!trunc|Kyber pubkey:");
+
+ err = gcry_kem_encap (kyber_algo,
+ kyber_pubkey, kyber_pubkey_len,
+ kyber_ct, kyber_ct_len,
+ kyber_ss, kyber_ss_len,
+ NULL, 0);
+ if (err)
+ {
+ if (opt.verbose)
+ log_info ("%s: gcry_kem_encap for ECC failed\n", __func__);
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ {
+ log_printhex (kyber_ct, kyber_ct_len, "|!trunc|Kyber ephem:");
+ log_printhex (kyber_ss, kyber_ss_len, "Kyber shared:");
+ }
+
+
+ fixedinfo[0] = seskey_algo;
+ v5_fingerprint_from_pk (pk, fixedinfo+1, NULL);
+ fixedlen = 33;
+
+ err = gnupg_kem_combiner (kek, kek_len,
+ ecc_ss, ecc_ss_len, ecc_ct, ecc_ct_len,
+ kyber_ss, kyber_ss_len, kyber_ct, kyber_ct_len,
+ fixedinfo, fixedlen);
+ if (err)
+ {
+ if (opt.verbose)
+ log_info ("%s: KEM combiner failed\n", __func__);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ log_printhex (kek, kek_len, "KEK:");
+
+ err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256,
+ GCRY_CIPHER_MODE_AESWRAP, 0);
+ if (!err)
+ err = gcry_cipher_setkey (hd, kek, kek_len);
+ if (err)
+ {
+ if (opt.verbose)
+ log_error ("%s: failed to initialize AESWRAP: %s\n", __func__,
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ err = gcry_sexp_build (&s_data, NULL, "%m", data);
+ if (err)
+ goto leave;
+
+ n = gcry_cipher_get_algo_keylen (seskey_algo);
+ seskey = gcry_mpi_get_opaque (data, &nbits);
+ seskey_len = (nbits+7)/8;
+ if (seskey_len != n)
+ {
+ if (opt.verbose)
+ log_info ("%s: session key length %zu"
+ " does not match the length for algo %d\n",
+ __func__, seskey_len, seskey_algo);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ log_printhex (seskey, seskey_len, "seskey:");
+
+ enc_seskey_len = 1 + seskey_len + 8;
+ enc_seskey = xtrymalloc (enc_seskey_len);
+ if (!enc_seskey || enc_seskey_len > 254)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ enc_seskey[0] = enc_seskey_len - 1;
+ err = gcry_cipher_encrypt (hd, enc_seskey+1, enc_seskey_len-1,
+ seskey, seskey_len);
+ if (err)
+ {
+ log_error ("%s: wrapping session key failed\n", __func__);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ log_printhex (enc_seskey, enc_seskey_len, "enc_seskey:");
+
+ resarr[0] = gcry_mpi_set_opaque_copy (NULL, ecc_ct, 8 * ecc_ct_len);
+ if (resarr[0])
+ resarr[1] = gcry_mpi_set_opaque_copy (NULL, kyber_ct, 8 * kyber_ct_len);
+ if (resarr[1])
+ resarr[2] = gcry_mpi_set_opaque_copy (NULL, enc_seskey, 8 * enc_seskey_len);
+ if (!resarr[0] || !resarr[1] || !resarr[2])
+ {
+ err = gpg_error_from_syserror ();
+ for (i=0; i < 3; i++)
+ gcry_mpi_release (resarr[i]), resarr[i] = NULL;
+ }
+
+ leave:
+ wipememory (ecc_ct, sizeof ecc_ct);
+ wipememory (ecc_ecdh, sizeof ecc_ecdh);
+ wipememory (ecc_ss, sizeof ecc_ss);
+ wipememory (kyber_ct, sizeof kyber_ct);
+ wipememory (kyber_ss, sizeof kyber_ss);
+ wipememory (kek, kek_len);
+ xfree (enc_seskey);
+ gcry_cipher_close (hd);
+ xfree (ecc_oid);
+ return err;
+}
+
+
+/* Core of the encryption for the ECDH algorithms. See pk_decrypt for
+ * a description of the arguments. */
+static gpg_error_t
+do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
+{
+ gcry_mpi_t *pkey = pk->pkey;
+ gcry_sexp_t s_ciph = NULL;
+ gcry_sexp_t s_data = NULL;
+ gcry_sexp_t s_pkey = NULL;
+ gpg_error_t err;
+ gcry_mpi_t k = NULL;
+ char *curve = NULL;
+ int with_djb_tweak_flag;
+ gcry_mpi_t public = NULL;
+ gcry_mpi_t result = NULL;
+ byte fp[MAX_FINGERPRINT_LEN];
+ byte *shared = NULL;
+ byte *p;
+ size_t nshared;
+ unsigned int nbits;
+
+ err = pk_ecdh_generate_ephemeral_key (pkey, &k);
+ if (err)
+ goto leave;
+
+ curve = openpgp_oid_to_str (pkey[0]);
+ if (!curve)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]);
+
+ /* Now use the ephemeral secret to compute the shared point. */
+ err = gcry_sexp_build (&s_pkey, NULL,
+ with_djb_tweak_flag ?
+ "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))"
+ : "(public-key(ecdh(curve%s)(q%m)))",
+ curve, pkey[1]);
+ if (err)
+ goto leave;
+
+ /* Put K into a simplified S-expression. */
+ err = gcry_sexp_build (&s_data, NULL, "%m", k);
+ if (err)
+ goto leave;
+
+ /* Run encryption. */
+ err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
+ if (err)
+ goto leave;
+
+ gcry_sexp_release (s_data); s_data = NULL;
+ gcry_sexp_release (s_pkey); s_pkey = NULL;
+
+
+ /* Get the shared point and the ephemeral public key. */
+ shared = get_data_from_sexp (s_ciph, "s", &nshared);
+ if (!shared)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ err = sexp_extract_param_sos (s_ciph, "e", &public);
+ gcry_sexp_release (s_ciph); s_ciph = NULL;
+ if (DBG_CRYPTO)
+ {
+ log_debug ("ECDH ephemeral key:");
+ gcry_mpi_dump (public);
+ log_printf ("\n");
+ }
+
+ fingerprint_from_pk (pk, fp, NULL);
+
+ p = gcry_mpi_get_opaque (data, &nbits);
+ result = NULL;
+ err = pk_ecdh_encrypt_with_shared_point (shared, nshared, fp, p,
+ (nbits+7)/8, pkey, &result);
+ if (err)
+ goto leave;
+
+ resarr[0] = public; public = NULL;
+ resarr[1] = result; result = NULL;
+
leave:
+ gcry_mpi_release (public);
+ gcry_mpi_release (result);
+ xfree (shared);
gcry_sexp_release (s_ciph);
- return rc;
+ gcry_sexp_release (s_data);
+ gcry_sexp_release (s_pkey);
+ xfree (curve);
+ gcry_mpi_release (k);
+ return err;
+}
+
+
+/* Core of the encryption for RSA and Elgamal algorithms. See
+ * pk_decrypt for a description of the arguments. */
+static gpg_error_t
+do_encrypt_rsa_elg (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
+{
+ pubkey_algo_t algo = pk->pubkey_algo;
+ gcry_mpi_t *pkey = pk->pkey;
+ gcry_sexp_t s_ciph = NULL;
+ gcry_sexp_t s_data = NULL;
+ gcry_sexp_t s_pkey = NULL;
+ gpg_error_t err;
+
+ if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
+ err = gcry_sexp_build (&s_pkey, NULL,
+ "(public-key(elg(p%m)(g%m)(y%m)))",
+ pkey[0], pkey[1], pkey[2]);
+ else
+ err = gcry_sexp_build (&s_pkey, NULL,
+ "(public-key(rsa(n%m)(e%m)))",
+ pkey[0], pkey[1]);
+ if (err)
+ goto leave;
+
+ err = gcry_sexp_build (&s_data, NULL, "%m", data);
+ if (err)
+ goto leave;
+
+ err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
+ if (err)
+ goto leave;
+
+ gcry_sexp_release (s_data); s_data = NULL;
+ gcry_sexp_release (s_pkey); s_pkey = NULL;
+
+ resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
+ if (!is_RSA (algo))
+ resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
+
+ leave:
+ gcry_sexp_release (s_data);
+ gcry_sexp_release (s_pkey);
+ gcry_sexp_release (s_ciph);
+ return err;
+}
+
+
+/*
+ * Emulate our old PK interface here - sometime in the future we might
+ * change the internal design to directly fit to libgcrypt. PK is is
+ * the OpenPGP public key packet, DATA is an MPI with the to be
+ * encrypted data, and RESARR receives the encrypted data. RESARRAY
+ * is expected to be an two item array which will be filled with newly
+ * allocated MPIs. SESKEY_ALGO is required for public key algorithms
+ * which do not encode it in DATA.
+ */
+gpg_error_t
+pk_encrypt (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
+ gcry_mpi_t *resarr)
+{
+ pubkey_algo_t algo = pk->pubkey_algo;
+
+ if (algo == PUBKEY_ALGO_KYBER)
+ return do_encrypt_kem (pk, data, seskey_algo, resarr);
+ else if (algo == PUBKEY_ALGO_ECDH)
+ return do_encrypt_ecdh (pk, data, resarr);
+ else if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
+ return do_encrypt_rsa_elg (pk, data, resarr);
+ else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
+ return do_encrypt_rsa_elg (pk, data, resarr);
+ else
+ return gpg_error (GPG_ERR_PUBKEY_ALGO);
}