aboutsummaryrefslogtreecommitdiffstats
path: root/sm/encrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sm/encrypt.c')
-rw-r--r--sm/encrypt.c162
1 files changed, 96 insertions, 66 deletions
diff --git a/sm/encrypt.c b/sm/encrypt.c
index 98d3024ad..52c747321 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -186,17 +186,23 @@ ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval)
int hash_algo, cipher_algo;
unsigned int keylen;
unsigned char key[32];
- gcry_sexp_t s_data = NULL;
- gcry_sexp_t s_encr = NULL;
- gcry_buffer_t ioarray[2] = { {0}, {0} };
- unsigned char *secret; /* Alias for ioarray[0]. */
+ const unsigned char *secret;
unsigned int secretlen;
- unsigned char *pubkey; /* Alias for ioarray[1]. */
+ const unsigned char *pubkey;
unsigned int pubkeylen;
gcry_cipher_hd_t cipher_hd = NULL;
unsigned char *result = NULL;
unsigned int resultlen;
+ unsigned int nbits;
+ const struct gnupg_ecc_params *ecc;
+ gcry_mpi_t ecc_pubkey_mpi = NULL;
+ const unsigned char *ecc_pubkey;
+ size_t ecc_pubkey_len;
+ unsigned char ecc_ct[ECC_POINT_LEN_MAX];
+ unsigned char ecc_ecdh[ECC_POINT_LEN_MAX];
+ size_t ecc_ct_len, ecc_ecdh_len;
+
*r_encval = NULL;
/* Figure out the encryption and wrap algo OIDs. */
@@ -215,18 +221,25 @@ ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval)
}
/* We need to use our OpenPGP mapping to turn a curve name into its
- * canonical numerical OID. We also use this to get the size of the
- * curve which we need to figure out a suitable hash algo. We
- * should have a Libgcrypt function to do this; see bug report #4926. */
- curve = openpgp_curve_to_oid (curvebuf, &curvebits, NULL, -1);
+ * canonical name. We also use this to get the size of the curve
+ * which we need to figure out a suitable hash algo. We should have
+ * a Libgcrypt function to do this; see bug report #4926. */
+ curve = openpgp_oid_to_curve (curvebuf, 1);
+ xfree (curvebuf);
+ if (!curve)
+ {
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ log_error ("%s: invalid public key: %s\n", __func__, gpg_strerror (err));
+ goto leave;
+ }
+
+ curve = openpgp_is_curve_supported (curve, NULL, &curvebits);
if (!curve)
{
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
log_error ("%s: invalid public key: %s\n", __func__, gpg_strerror (err));
goto leave;
}
- xfree (curvebuf);
- curvebuf = NULL;
/* Our mapping matches the recommended algorithms from RFC-5753 but
* not supporting the short curves which would require 3DES. */
@@ -273,75 +286,95 @@ ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval)
keylen = 32;
}
-
- /* Create a secret and an ephemeral key. */
- {
- char *k;
- k = gcry_random_bytes_secure ((curvebits+7)/8, GCRY_STRONG_RANDOM);
- if (DBG_CRYPTO)
- log_printhex (k, (curvebits+7)/8, "ephm. k .:");
- err = gcry_sexp_build (&s_data, NULL, "%b", (int)(curvebits+7)/8, k);
- xfree (k);
- }
- if (err)
+ ecc = gnupg_get_ecc_params (curve);
+ if (!ecc)
{
- log_error ("%s: error building ephemeral secret: %s\n",
- __func__, gpg_strerror (err));
+ if (opt.verbose)
+ log_info ("%s: ECC curve %s not supported\n", __func__, curve);
+ err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
+ ecc_ct_len = ecc_ecdh_len = ecc->point_len;
- err = gcry_pk_encrypt (&s_encr, s_data, s_pkey);
- if (err)
+ err = gcry_sexp_extract_param (s_pkey, NULL, "/q",
+ &ecc_pubkey_mpi, NULL);
+ ecc_pubkey = gcry_mpi_get_opaque (ecc_pubkey_mpi, &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len != ecc->pubkey_len)
{
- log_error ("%s: error encrypting ephemeral secret: %s\n",
- __func__, gpg_strerror (err));
- goto leave;
+ if (ecc->kem_algo == GCRY_KEM_RAW_X25519
+ && ecc_pubkey_len == ecc->pubkey_len - 1)
+ /* For Curve25519, we also accept no prefix in the point
+ * representation. */
+ ;
+ else
+ {
+ 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;
+ }
}
- err = gcry_sexp_extract_param (s_encr, NULL, "&se",
- &ioarray+0, ioarray+1, NULL);
- if (err)
+
+ if (ecc->kem_algo == GCRY_KEM_RAW_X25519)
{
- log_error ("%s: error extracting ephemeral key and secret: %s\n",
- __func__, gpg_strerror (err));
- goto leave;
+ /* Note: Legacy OID is OK here. */
+ /* Optional prefix handling */
+ if (ecc_pubkey_len == 33 && *ecc_pubkey == 0x40)
+ {
+ ecc_pubkey++; /* Remove the 0x40 prefix. */
+ ecc_pubkey_len--;
+ }
}
- secret = ioarray[0].data;
- secretlen = ioarray[0].len;
- pubkey = ioarray[1].data;
- pubkeylen = ioarray[1].len;
if (DBG_CRYPTO)
{
- log_printhex (pubkey, pubkeylen, "pubkey ..:");
- log_printhex (secret, secretlen, "secret ..:");
+ log_debug ("ECC curve: %s\n", curve);
+ log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:");
}
- /* Extract X coordinate from SECRET. */
- if (secretlen < 5) /* 5 because N could be reduced to (n-1)/2. */
- err = gpg_error (GPG_ERR_BAD_DATA);
- else if (*secret == 0x04)
+ err = gcry_kem_encap (ecc->kem_algo,
+ ecc_pubkey, ecc_pubkey_len,
+ ecc_ct, ecc_ct_len,
+ ecc_ecdh, ecc_ecdh_len,
+ NULL, 0);
+ if (err)
{
- secretlen--;
- memmove (secret, secret+1, secretlen);
- if ((secretlen & 1))
- {
- err = gpg_error (GPG_ERR_BAD_DATA);
- goto leave;
- }
- secretlen /= 2;
+ if (opt.verbose)
+ log_info ("%s: gcry_kem_encap for ECC (%s) failed\n",
+ __func__, curve);
+ goto leave;
+ }
+ if (DBG_CRYPTO)
+ {
+ log_printhex (ecc_ct, ecc_ct_len, "ECC ephem:");
+ log_printhex (ecc_ecdh, ecc_ecdh_len, "ECC ecdh:");
}
- else if (*secret == 0x40 || *secret == 0x41)
+
+ if (ecc->is_weierstrauss)
{
- secretlen--;
- memmove (secret, secret+1, secretlen);
+ secret = ecc_ecdh + 1;
+ secretlen = (ecc_ecdh_len - 1) / 2;
+ pubkey = ecc_ct;
+ pubkeylen = ecc_ct_len;
}
else
- err = gpg_error (GPG_ERR_BAD_DATA);
- if (err)
- goto leave;
+ {
+ secret = ecc_ecdh;
+ secretlen = ecc_ecdh_len;
- if (DBG_CRYPTO)
- log_printhex (secret, secretlen, "ECDH X ..:");
+ if (ecc->may_have_prefix)
+ {
+ pubkeylen = ecc_ct_len + 1;
+ memmove (ecc_ct + 1, ecc_ct, ecc_ct_len);
+ ecc_ct[0] = 0x40;
+ }
+ else
+ pubkeylen = ecc_ct_len;
+
+ pubkey = ecc_ct;
+ }
err = ecdh_derive_kek (key, keylen, hash_algo, wrap_algo_str,
secret, secretlen, NULL, 0);
@@ -409,14 +442,11 @@ ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval)
__func__, gpg_strerror (err));
leave:
+ gcry_mpi_release (ecc_pubkey_mpi);
gcry_cipher_close (cipher_hd);
+ wipememory (ecc_ecdh, sizeof ecc_ecdh);
wipememory (key, sizeof key);
xfree (result);
- xfree (ioarray[0].data);
- xfree (ioarray[1].data);
- gcry_sexp_release (s_data);
- gcry_sexp_release (s_encr);
- xfree (curvebuf);
return err;
}