From da5e0bc31b4c6f16ed5ff9b35063f3b03eb7ff16 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 9 Jun 2020 15:45:51 +0900 Subject: [PATCH] gpg: Use bytes for ECDH. * g10/ecdh.c (extract_secret_x): Use byte * instead of MPI. (prepare_ecdh_with_shared_point): Use char * instead of MPI. (pk_ecdh_encrypt_with_shared_point): Likewise. (pk_ecdh_decrypt): Likewise. * g10/pkglue.h (pk_ecdh_encrypt_with_shared_point, pk_ecdh_decrypt): Change declaration. * g10/pkglue.c (get_data_from_sexp): New. (pk_encrypt): Use get_data_from_sexp instead of get_mpi_from_sexp. Follow the change of pk_ecdh_encrypt_with_shared_point. * g10/pubkey-enc.c (get_it): Follow the change of pk_ecdh_decrypt. Signed-off-by: NIIBE Yutaka --- g10/ecdh.c | 66 ++++++++++++++++++------------------------------ g10/pkglue.c | 38 ++++++++++++++++++++++++---- g10/pkglue.h | 9 ++++--- g10/pubkey-enc.c | 11 +------- 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/g10/ecdh.c b/g10/ecdh.c index d6c30c1ca..230602462 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -82,15 +82,15 @@ pk_ecdh_default_params (unsigned int qbits) } -/* Extract xcomponent from the point SHARED_MPI. POINT_NBYTES is the +/* Extract xcomponent from the point SHARED. POINT_NBYTES is the size to represent an EC point which is determined by the public key. SECRET_X_SIZE is the size of x component to represent an integer which is determined by the curve. */ static gpg_error_t -extract_secret_x (byte **r_secret_x, gcry_mpi_t shared_mpi, +extract_secret_x (byte **r_secret_x, + const char *shared, size_t nshared, size_t point_nbytes, size_t secret_x_size) { - gpg_error_t err; byte *secret_x; *r_secret_x = NULL; @@ -111,15 +111,7 @@ extract_secret_x (byte **r_secret_x, gcry_mpi_t shared_mpi, if (!secret_x) return gpg_error_from_syserror (); - err = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, point_nbytes, - &point_nbytes, shared_mpi); - if (err) - { - xfree (secret_x); - log_error ("ECDH ephemeral export of shared point failed: %s\n", - gpg_strerror (err)); - return err; - } + memcpy (secret_x, shared, nshared); /* Remove the prefix. */ if ((point_nbytes & 1)) @@ -133,7 +125,7 @@ extract_secret_x (byte **r_secret_x, gcry_mpi_t shared_mpi, log_printhex (secret_x, secret_x_size, "ECDH shared secret X is:"); *r_secret_x = secret_x; - return err; + return 0; } @@ -209,11 +201,11 @@ derive_kek (size_t kek_size, } -/* Prepare ECDH using SHARED_MPI, PK_FP fingerprint, and PKEY array. +/* Prepare ECDH using SHARED, PK_FP fingerprint, and PKEY array. Returns the cipher handle in R_HD, which needs to be closed by the caller. */ static gpg_error_t -prepare_ecdh_with_shared_point (gcry_mpi_t shared_mpi, +prepare_ecdh_with_shared_point (const char *shared, size_t nshared, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *pkey, gcry_cipher_hd_t *r_hd) { @@ -280,7 +272,7 @@ prepare_ecdh_with_shared_point (gcry_mpi_t shared_mpi, if (kek_size > secret_x_size) return gpg_error (GPG_ERR_BAD_PUBKEY); - err = extract_secret_x (&secret_x, shared_mpi, + err = extract_secret_x (&secret_x, shared, nshared, /* pkey[1] is the public point */ (mpi_get_nbits (pkey[1])+7)/8, secret_x_size); @@ -330,21 +322,20 @@ prepare_ecdh_with_shared_point (gcry_mpi_t shared_mpi, return err; } -/* Encrypts DATA using a key derived from the ECC shared point - SHARED_MPI using the FIPS SP 800-56A compliant method +/* Encrypts DATA using a key derived from the ECC shared point SHARED + using the FIPS SP 800-56A compliant method key_derivation+key_wrapping. PKEY is the public key and PK_FP the fingerprint of this public key. On success the result is stored at R_RESULT; on failure NULL is stored at R_RESULT and an error code returned. */ gpg_error_t -pk_ecdh_encrypt_with_shared_point (gcry_mpi_t shared_mpi, +pk_ecdh_encrypt_with_shared_point (const char *shared, size_t nshared, const byte pk_fp[MAX_FINGERPRINT_LEN], - gcry_mpi_t data, gcry_mpi_t *pkey, - gcry_mpi_t *r_result) + const byte *data, size_t ndata, + gcry_mpi_t *pkey, gcry_mpi_t *r_result) { gpg_error_t err; gcry_cipher_hd_t hd; - size_t nbytes; byte *data_buf; int data_buf_size; gcry_mpi_t result; @@ -352,11 +343,11 @@ pk_ecdh_encrypt_with_shared_point (gcry_mpi_t shared_mpi, *r_result = NULL; - err = prepare_ecdh_with_shared_point (shared_mpi, pk_fp, pkey, &hd); + err = prepare_ecdh_with_shared_point (shared, nshared, pk_fp, pkey, &hd); if (err) return err; - data_buf_size = (gcry_mpi_get_nbits(data)+7)/8; + data_buf_size = ndata; if ((data_buf_size & 7) != 0) { log_error ("can't use a shared secret of %d bytes for ecdh\n", @@ -377,15 +368,7 @@ pk_ecdh_encrypt_with_shared_point (gcry_mpi_t shared_mpi, /* Write data MPI into the end of data_buf. data_buf is size aeswrap data. */ - err = gcry_mpi_print (GCRYMPI_FMT_USG, in, - data_buf_size, &nbytes, data/*in*/); - if (err) - { - log_error ("ecdh failed to export DEK: %s\n", gpg_strerror (err)); - gcry_cipher_close (hd); - xfree (data_buf); - return err; - } + memcpy (in, data, ndata); if (DBG_CRYPTO) log_printhex (in, data_buf_size, "ecdh encrypting :"); @@ -497,7 +480,8 @@ pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k) /* Perform ECDH decryption. */ int pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN], - gcry_mpi_t data, gcry_mpi_t shared_mpi, gcry_mpi_t * skey) + gcry_mpi_t data, + const byte *shared, size_t nshared, gcry_mpi_t * skey) { gpg_error_t err; gcry_cipher_hd_t hd; @@ -508,16 +492,16 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN], const void *p; unsigned int nbits; - if (!data) - return gpg_error (GPG_ERR_BAD_MPI); - *r_result = NULL; - err = prepare_ecdh_with_shared_point (shared_mpi, sk_fp, skey, &hd); + err = prepare_ecdh_with_shared_point (shared, nshared, sk_fp, skey, &hd); if (err) return err; - data_buf_size = (gcry_mpi_get_nbits(data)+7)/8; + p = gcry_mpi_get_opaque (data, &nbits); + nbytes = (nbits+7)/8; + + data_buf_size = nbytes; if ((data_buf_size & 7) != 1) { log_error ("can't use a shared secret of %d bytes for ecdh\n", @@ -534,9 +518,7 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN], return err; } - p = gcry_mpi_get_opaque (data, &nbits); - nbytes = (nbits+7)/8; - if (!p || nbytes > data_buf_size || !nbytes) + if (!p) { xfree (data_buf); gcry_cipher_close (hd); diff --git a/g10/pkglue.c b/g10/pkglue.c index 741a93735..a659a5b06 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -98,6 +98,28 @@ sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos) } +static byte * +get_data_from_sexp (gcry_sexp_t sexp, const char *item, size_t *r_size) +{ + gcry_sexp_t list; + size_t valuelen; + const char *value; + byte *v; + + log_printsexp ("get_data_from_sexp:", sexp); + + list = gcry_sexp_find_token (sexp, item, 0); + log_assert (list); + value = gcry_sexp_nth_data (list, 1, &valuelen); + log_assert (value); + v = xtrymalloc (valuelen); + memcpy (v, value, valuelen); + gcry_sexp_release (list); + *r_size = valuelen; + return v; +} + + /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. @@ -382,12 +404,14 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, ; else if (algo == PUBKEY_ALGO_ECDH) { - gcry_mpi_t shared, public, result; + gcry_mpi_t public, result; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; + byte *shared; + size_t nshared; /* Get the shared point and the ephemeral public key. */ - shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG); + shared = get_data_from_sexp (s_ciph, "s", &nshared); rc = sexp_extract_param_sos (s_ciph, "e", &public); gcry_sexp_release (s_ciph); s_ciph = NULL; @@ -404,9 +428,13 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, rc = gpg_error (GPG_ERR_INV_LENGTH); if (!rc) - rc = pk_ecdh_encrypt_with_shared_point (shared, - fp, data, pkey, &result); - gcry_mpi_release (shared); + { + 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); + } + xfree (shared); if (!rc) { resarr[0] = public; diff --git a/g10/pkglue.h b/g10/pkglue.h index 099337959..308e54f9a 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -38,15 +38,18 @@ int pk_check_secret_key (pubkey_algo_t algo, gcry_mpi_t *skey); gcry_mpi_t pk_ecdh_default_params (unsigned int qbits); gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k); gpg_error_t pk_ecdh_encrypt_with_shared_point -/* */ (gcry_mpi_t shared_mpi, +/* */ (const char *shared, size_t nshared, const byte pk_fp[MAX_FINGERPRINT_LEN], - gcry_mpi_t data, gcry_mpi_t *pkey, + const byte *data, size_t ndata, + gcry_mpi_t *pkey, gcry_mpi_t *out); int pk_ecdh_encrypt (gcry_mpi_t *resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey); int pk_ecdh_decrypt (gcry_mpi_t *result, const byte sk_fp[MAX_FINGERPRINT_LEN], - gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey); + gcry_mpi_t data, + const byte *frame, size_t nframe, + gcry_mpi_t * skey); #endif /*GNUPG_G10_PKGLUE_H*/ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 9ec86df3e..38353c812 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -278,20 +278,11 @@ get_it (ctrl_t ctrl, if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { - gcry_mpi_t shared_mpi; gcry_mpi_t decoded; /* At the beginning the frame are the bytes of shared point MPI. */ - err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL); - if (err) - { - err = gpg_error (GPG_ERR_WRONG_SECKEY); - goto leave; - } - err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/, - shared_mpi, sk->pkey); - mpi_release (shared_mpi); + frame, nframe, sk->pkey); if(err) goto leave;