mirror of
git://git.gnupg.org/gnupg.git
synced 2025-05-24 16:43:28 +02:00
gpg,agent: Clean up around using ECC KEM.
* common/util.h (gnupg_ecc_kem_kdf): Change the last two args. * common/kem.c (gnupg_ecc_kem_kdf): The last arguments are KDF_PARAMS and its length. * agent/pkdecrypt.c (composite_pgp_kem_decrypt): Follow the change. * g10/pkglue.c (do_encrypt_kem): Follow the change. * g10/ecdh.c (extract_secret_x, derive_kek): Remove. (gnupg_ecc_6637_kdf): Remove. (ecc_build_kdf_params): Rename from build_kdf_params, changing arguments. * g10/pkglue.c (do_encrypt_ecdh): Refactor by ecc_build_kdf_params and gnupg_ecc_kem_kdf. * g10/pkglue.h (pk_ecdh_decrypt, gnupg_ecc_6637_kdf): Remove. (ecc_build_kdf_params): New. * g10/pubkey-enc.c (ecdh_sexp_build): Use ecc_build_kdf_params. -- GnuPG-bug-id: 7649 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
parent
37bec0df7b
commit
681d754043
@ -648,7 +648,7 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
|
||||
ecc_shared_len = gcry_md_get_algo_dlen (ecc_hashalgo);
|
||||
err = gnupg_ecc_kem_kdf (ecc_ss, ecc_shared_len, ecc_hashalgo,
|
||||
ecc_ecdh, ecc_point_len, ecc_ct, ecc_point_len,
|
||||
ecc_pk, ecc_point_len, NULL);
|
||||
ecc_pk, ecc_point_len, NULL, 0);
|
||||
if (err)
|
||||
{
|
||||
if (opt.verbose)
|
||||
@ -891,7 +891,9 @@ ecc_kem_decrypt (ctrl_t ctrl, const char *desc_text,
|
||||
x-component from the point. */
|
||||
ecc_ecdh + 1 : ecc_ecdh,
|
||||
ecc->scalar_len, ecc_ct, ecc_point_len,
|
||||
ecc_pk, ecc_point_len, &kdf_params);
|
||||
ecc_pk, ecc_point_len,
|
||||
(char *)kdf_params.data+kdf_params.off,
|
||||
kdf_params.len);
|
||||
if (err)
|
||||
{
|
||||
if (opt.verbose)
|
||||
|
@ -156,7 +156,7 @@ gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
|
||||
int hashalgo, const void *ecdh, size_t ecdh_len,
|
||||
const void *ecc_ct, size_t ecc_ct_len,
|
||||
const void *ecc_pk, size_t ecc_pk_len,
|
||||
gcry_buffer_t *kdf_params)
|
||||
unsigned char *kdf_params, size_t kdf_params_len)
|
||||
{
|
||||
if (kdf_params)
|
||||
{
|
||||
@ -168,8 +168,7 @@ gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
|
||||
param[0] = kek_len;
|
||||
err = gcry_kdf_open (&hd, GCRY_KDF_ONESTEP_KDF, hashalgo, param, 1,
|
||||
ecdh, ecdh_len, NULL, 0, NULL, 0,
|
||||
(char *)kdf_params->data+kdf_params->off,
|
||||
kdf_params->len);
|
||||
kdf_params, kdf_params_len);
|
||||
if (!err)
|
||||
{
|
||||
gcry_kdf_compute (hd, NULL);
|
||||
|
@ -306,7 +306,8 @@ gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
|
||||
int hashalgo, const void *ecdh, size_t ecdh_len,
|
||||
const void *ecc_ct, size_t ecc_ct_len,
|
||||
const void *ecc_pk, size_t ecc_pk_len,
|
||||
gcry_buffer_t *kdf_params);
|
||||
unsigned char *kdf_params,
|
||||
size_t kdf_params_len);
|
||||
|
||||
gpg_error_t gnupg_kem_combiner (void *kek, size_t kek_len,
|
||||
const void *ecc_ss, size_t ecc_ss_len,
|
||||
|
448
g10/ecdh.c
448
g10/ecdh.c
@ -79,62 +79,6 @@ pk_ecdh_default_params (unsigned int qbits)
|
||||
}
|
||||
|
||||
|
||||
/* 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,
|
||||
const char *shared, size_t nshared,
|
||||
size_t point_nbytes, size_t secret_x_size)
|
||||
{
|
||||
byte *secret_x;
|
||||
|
||||
*r_secret_x = NULL;
|
||||
|
||||
/* Extract X from the result. It must be in the format of:
|
||||
04 || X || Y
|
||||
40 || X
|
||||
41 || X
|
||||
|
||||
Since it may come with the prefix, the size of point is larger
|
||||
than or equals to the size of an integer X. We also better check
|
||||
that the provided shared point is not larger than the size needed
|
||||
to represent the point. */
|
||||
if (point_nbytes < secret_x_size)
|
||||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
if (point_nbytes < nshared)
|
||||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
|
||||
/* Extract x component of the shared point: this is the actual
|
||||
shared secret. */
|
||||
secret_x = xtrymalloc_secure (point_nbytes);
|
||||
if (!secret_x)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
memcpy (secret_x, shared, nshared);
|
||||
|
||||
/* Wrangle the provided point unless only the x-component w/o any
|
||||
* prefix was provided. */
|
||||
if (nshared != secret_x_size)
|
||||
{
|
||||
/* Remove the prefix. */
|
||||
if ((point_nbytes & 1))
|
||||
memmove (secret_x, secret_x+1, secret_x_size);
|
||||
|
||||
/* Clear the rest of data. */
|
||||
if (point_nbytes - secret_x_size)
|
||||
memset (secret_x+secret_x_size, 0, point_nbytes-secret_x_size);
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (secret_x, secret_x_size, "ECDH shared secret X is:");
|
||||
|
||||
*r_secret_x = secret_x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Build KDF parameters */
|
||||
/* RFC 6637 defines the KDF parameters and its encoding in Section
|
||||
8. EC DH Algorighm (ECDH). Since it was written for v4 key, it
|
||||
@ -142,375 +86,57 @@ extract_secret_x (byte **r_secret_x,
|
||||
master key fingerprint". For v5 key, it is considered "adequate"
|
||||
(in terms of NIST SP 800 56A, see 5.8.2 FixedInfo) to use the first
|
||||
20 octets of its 32 octets fingerprint. */
|
||||
static gpg_error_t
|
||||
build_kdf_params (unsigned char kdf_params[256], size_t *r_size,
|
||||
gcry_mpi_t *pkey, const byte pk_fp[MAX_FINGERPRINT_LEN])
|
||||
{
|
||||
IOBUF obuf;
|
||||
gpg_error_t err;
|
||||
|
||||
*r_size = 0;
|
||||
|
||||
obuf = iobuf_temp();
|
||||
if (!obuf)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
/* variable-length field 1, curve name OID */
|
||||
err = gpg_mpi_write_opaque_nohdr (obuf, pkey[0]);
|
||||
/* fixed-length field 2 */
|
||||
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
|
||||
/* variable-length field 3, KDF params */
|
||||
err = (err ? err : gpg_mpi_write_opaque_nohdr (obuf, pkey[2]));
|
||||
/* fixed-length field 4 */
|
||||
iobuf_write (obuf, "Anonymous Sender ", 20);
|
||||
/* fixed-length field 5, recipient fp (or first 20 octets of fp) */
|
||||
iobuf_write (obuf, pk_fp, 20);
|
||||
|
||||
if (!err)
|
||||
*r_size = iobuf_temp_to_buffer (obuf, kdf_params, 256);
|
||||
|
||||
iobuf_close (obuf);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (kdf_params, *r_size, "ecdh KDF message params are:");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Derive KEK with KEK_SIZE into the memory at SECRET_X. */
|
||||
static gpg_error_t
|
||||
derive_kek (size_t kek_size,
|
||||
int kdf_hash_algo,
|
||||
byte *secret_x, int secret_x_size,
|
||||
const unsigned char *kdf_params, size_t kdf_params_size)
|
||||
{
|
||||
gpg_error_t err;
|
||||
#if 0 /* GCRYPT_VERSION_NUMBER >= 0x010b00 */
|
||||
/*
|
||||
* Experimental: We will remove this if/endif-conditional
|
||||
* compilation when we update NEED_LIBGCRYPT_VERSION to 1.11.0.
|
||||
*/
|
||||
gcry_kdf_hd_t hd;
|
||||
unsigned long param[1];
|
||||
|
||||
param[0] = kek_size;
|
||||
err = gcry_kdf_open (&hd, GCRY_KDF_ONESTEP_KDF, kdf_hash_algo,
|
||||
param, 1,
|
||||
secret_x, secret_x_size, NULL, 0, NULL, 0,
|
||||
kdf_params, kdf_params_size);
|
||||
if (!err)
|
||||
{
|
||||
gcry_kdf_compute (hd, NULL);
|
||||
gcry_kdf_final (hd, kek_size, secret_x);
|
||||
gcry_kdf_close (hd);
|
||||
/* Clean the tail before returning. */
|
||||
memset (secret_x+kek_size, 0, secret_x_size - kek_size);
|
||||
}
|
||||
#else
|
||||
gcry_md_hd_t h;
|
||||
|
||||
log_assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
|
||||
|
||||
err = gcry_md_open (&h, kdf_hash_algo, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error ("gcry_md_open failed for kdf_hash_algo %d: %s",
|
||||
kdf_hash_algo, gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
gcry_md_write(h, "\x00\x00\x00\x01", 4); /* counter = 1 */
|
||||
gcry_md_write(h, secret_x, secret_x_size); /* x of the point X */
|
||||
gcry_md_write(h, kdf_params, kdf_params_size); /* KDF parameters */
|
||||
gcry_md_final (h);
|
||||
memcpy (secret_x, gcry_md_read (h, kdf_hash_algo), kek_size);
|
||||
gcry_md_close (h);
|
||||
/* Clean the tail before returning. */
|
||||
memset (secret_x+kek_size, 0, secret_x_size - kek_size);
|
||||
#endif
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (secret_x, kek_size, "ecdh KEK is:");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compute KEK for ECC with HASHALGO, ECDH result, and public key in
|
||||
PK, using the method defined in RFC 6637. Note that ephemeral key
|
||||
is not used to compute KEK here. */
|
||||
gpg_error_t
|
||||
gnupg_ecc_6637_kdf (void *kek, size_t kek_len,
|
||||
int hashalgo, const void *ecdh, size_t ecdh_len,
|
||||
PKT_public_key *pk)
|
||||
ecc_build_kdf_params (unsigned char **r_kdf_params, size_t *r_len,
|
||||
const unsigned char **r_kdf_params_spec,
|
||||
gcry_mpi_t *pkey, const byte fp[MAX_FINGERPRINT_LEN])
|
||||
{
|
||||
gpg_error_t err;
|
||||
unsigned char kdf_params[256];
|
||||
size_t kdf_params_size;
|
||||
const unsigned char *oid;
|
||||
const unsigned char *kdf_params_spec;
|
||||
unsigned int nbits;
|
||||
byte *secret_x;
|
||||
int secret_x_size;
|
||||
gcry_kdf_hd_t hd;
|
||||
unsigned long param[1];
|
||||
byte fp[MAX_FINGERPRINT_LEN];
|
||||
size_t oid_len;
|
||||
size_t len;
|
||||
unsigned char *kdf_params = NULL;
|
||||
int kdf_params_len = 0;
|
||||
|
||||
fingerprint_from_pk (pk, fp, NULL);
|
||||
|
||||
/* Build kdf_params. */
|
||||
err = build_kdf_params (kdf_params, &kdf_params_size, pk->pkey, fp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pk->pkey);
|
||||
if (!nbits)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
secret_x_size = (nbits+7)/8;
|
||||
if (kek_len > secret_x_size)
|
||||
if (!gcry_mpi_get_flag (pkey[0], GCRYMPI_FLAG_OPAQUE))
|
||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
||||
err = extract_secret_x (&secret_x, ecdh, ecdh_len,
|
||||
/* pk->pkey[1] is the public point */
|
||||
(mpi_get_nbits (pk->pkey[1])+7)/8,
|
||||
secret_x_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
param[0] = kek_len;
|
||||
err = gcry_kdf_open (&hd, GCRY_KDF_ONESTEP_KDF, hashalgo, param, 1,
|
||||
secret_x, secret_x_size, NULL, 0, NULL, 0,
|
||||
kdf_params, kdf_params_size);
|
||||
if (!err)
|
||||
{
|
||||
gcry_kdf_compute (hd, NULL);
|
||||
gcry_kdf_final (hd, kek_len, secret_x);
|
||||
gcry_kdf_close (hd);
|
||||
memcpy (kek, secret_x, kek_len);
|
||||
/* Clean the tail before returning. */
|
||||
memset (secret_x+kek_len, 0, secret_x_size - kek_len);
|
||||
xfree (secret_x);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfree (secret_x);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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 (const char *shared, size_t nshared,
|
||||
const byte pk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t *pkey, gcry_cipher_hd_t *r_hd)
|
||||
{
|
||||
gpg_error_t err;
|
||||
byte *secret_x;
|
||||
int secret_x_size;
|
||||
unsigned int nbits;
|
||||
const unsigned char *kek_params;
|
||||
size_t kek_params_size;
|
||||
int kdf_hash_algo;
|
||||
int kdf_encr_algo;
|
||||
unsigned char kdf_params[256];
|
||||
size_t kdf_params_size;
|
||||
size_t kek_size;
|
||||
gcry_cipher_hd_t hd;
|
||||
|
||||
*r_hd = NULL;
|
||||
oid = gcry_mpi_get_opaque (pkey[0], &nbits);
|
||||
oid_len = (nbits+7)/8;
|
||||
|
||||
/* In the public key part, 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 (pkey[2], GCRYMPI_FLAG_OPAQUE))
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
||||
kek_params = gcry_mpi_get_opaque (pkey[2], &nbits);
|
||||
kek_params_size = (nbits+7)/8;
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (kek_params, kek_params_size, "ecdh KDF params:");
|
||||
kdf_params_spec = gcry_mpi_get_opaque (pkey[2], &nbits);
|
||||
len = (nbits+7)/8;
|
||||
|
||||
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
|
||||
if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1)
|
||||
if (len != 4 || kdf_params_spec[0] != 3 || kdf_params_spec[1] != 1)
|
||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
||||
kdf_hash_algo = kek_params[2];
|
||||
kdf_encr_algo = kek_params[3];
|
||||
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_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
|
||||
openpgp_md_algo_name (kdf_hash_algo),
|
||||
openpgp_cipher_algo_name (kdf_encr_algo));
|
||||
log_printhex (kdf_params, kdf_params_len,
|
||||
"ecdh KDF message params are:");
|
||||
|
||||
if (kdf_hash_algo != GCRY_MD_SHA256
|
||||
&& kdf_hash_algo != GCRY_MD_SHA384
|
||||
&& kdf_hash_algo != GCRY_MD_SHA512)
|
||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
||||
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);
|
||||
|
||||
kek_size = gcry_cipher_get_algo_keylen (kdf_encr_algo);
|
||||
if (kek_size > gcry_md_get_algo_dlen (kdf_hash_algo))
|
||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
||||
/* Build kdf_params. */
|
||||
err = build_kdf_params (kdf_params, &kdf_params_size, pkey, pk_fp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
|
||||
if (!nbits)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
secret_x_size = (nbits+7)/8;
|
||||
if (kek_size > secret_x_size)
|
||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
|
||||
err = extract_secret_x (&secret_x, shared, nshared,
|
||||
/* pkey[1] is the public point */
|
||||
(mpi_get_nbits (pkey[1])+7)/8,
|
||||
secret_x_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*** We have now the shared secret bytes in secret_x. ***/
|
||||
|
||||
/* At this point we are done with PK encryption and the rest of the
|
||||
* function uses symmetric key encryption techniques to protect the
|
||||
* input DATA. The following two sections will simply replace
|
||||
* current secret_x with a value derived from it. This will become
|
||||
* a KEK.
|
||||
*/
|
||||
|
||||
/* Derive a KEK (key wrapping key) using SECRET_X and KDF_PARAMS. */
|
||||
err = derive_kek (kek_size, kdf_hash_algo, secret_x,
|
||||
secret_x_size, kdf_params, kdf_params_size);
|
||||
if (err)
|
||||
{
|
||||
xfree (secret_x);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* And, finally, aeswrap with key secret_x. */
|
||||
err = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to initialize AESWRAP: %s\n",
|
||||
gpg_strerror (err));
|
||||
xfree (secret_x);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gcry_cipher_setkey (hd, secret_x, kek_size);
|
||||
xfree (secret_x);
|
||||
secret_x = NULL;
|
||||
if (err)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
log_error ("ecdh failed in gcry_cipher_setkey: %s\n",
|
||||
gpg_strerror (err));
|
||||
}
|
||||
else
|
||||
*r_hd = hd;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Perform ECDH decryption. */
|
||||
int
|
||||
pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data,
|
||||
const byte *shared, size_t nshared, gcry_mpi_t * skey)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_cipher_hd_t hd;
|
||||
size_t nbytes;
|
||||
byte *data_buf;
|
||||
int data_buf_size;
|
||||
const unsigned char *p;
|
||||
unsigned int nbits;
|
||||
|
||||
*r_result = NULL;
|
||||
|
||||
err = prepare_ecdh_with_shared_point (shared, nshared, sk_fp, skey, &hd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
p = gcry_mpi_get_opaque (data, &nbits);
|
||||
nbytes = (nbits+7)/8;
|
||||
|
||||
data_buf_size = nbytes;
|
||||
if ((data_buf_size & 7) != 1 || data_buf_size <= 1 + 8)
|
||||
{
|
||||
log_error ("can't use a shared secret of %d bytes for ecdh\n",
|
||||
data_buf_size);
|
||||
gcry_cipher_close (hd);
|
||||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
}
|
||||
|
||||
/* The first octet is for length. It's longer than the result
|
||||
because of one additional block of AESWRAP. */
|
||||
data_buf_size -= 1 + 8;
|
||||
data_buf = xtrymalloc_secure (data_buf_size);
|
||||
if (!data_buf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
gcry_cipher_close (hd);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!p)
|
||||
{
|
||||
xfree (data_buf);
|
||||
gcry_cipher_close (hd);
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
}
|
||||
if (p[0] != nbytes-1)
|
||||
{
|
||||
log_error ("ecdh inconsistent size\n");
|
||||
xfree (data_buf);
|
||||
gcry_cipher_close (hd);
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (p+1, nbytes-1, "ecdh decrypting :");
|
||||
|
||||
err = gcry_cipher_decrypt (hd, data_buf, data_buf_size, p+1, nbytes-1);
|
||||
gcry_cipher_close (hd);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",
|
||||
gpg_strerror (err));
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (data_buf, data_buf_size, "ecdh decrypted to :");
|
||||
|
||||
/* Padding is removed later. */
|
||||
/* if (in[data_buf_size-1] > 8 ) */
|
||||
/* { */
|
||||
/* log_error ("ecdh failed at decryption: invalid padding." */
|
||||
/* " 0x%02x > 8\n", in[data_buf_size-1] ); */
|
||||
/* return gpg_error (GPG_ERR_BAD_KEY); */
|
||||
/* } */
|
||||
|
||||
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, data_buf,
|
||||
data_buf_size, NULL);
|
||||
xfree (data_buf);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to create a plain text MPI: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
*r_kdf_params = kdf_params;
|
||||
*r_len = kdf_params_len;
|
||||
if (r_kdf_params_spec)
|
||||
*r_kdf_params_spec = kdf_params_spec;
|
||||
return 0;
|
||||
}
|
||||
|
70
g10/pkglue.c
70
g10/pkglue.c
@ -598,7 +598,7 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
|
||||
ecc_hash_algo,
|
||||
ecc_ecdh, ecc_ecdh_len,
|
||||
ecc_ct, ecc_ct_len,
|
||||
ecc_pubkey, ecc_pubkey_len, NULL);
|
||||
ecc_pubkey, ecc_pubkey_len, NULL, 0);
|
||||
if (err)
|
||||
{
|
||||
if (opt.verbose)
|
||||
@ -766,14 +766,19 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
unsigned char ecc_ct[ECC_POINT_LEN_MAX];
|
||||
unsigned char ecc_ecdh[ECC_POINT_LEN_MAX];
|
||||
size_t ecc_ct_len, ecc_ecdh_len;
|
||||
int is_weierstrass;
|
||||
|
||||
unsigned char *kek = NULL;
|
||||
size_t kek_len;
|
||||
|
||||
const unsigned char *kek_params;
|
||||
size_t kek_params_size;
|
||||
const unsigned char *kdf_params_spec;
|
||||
byte fp[MAX_FINGERPRINT_LEN];
|
||||
int keywrap_cipher_algo;
|
||||
int kdf_hash_algo;
|
||||
int kdf_encr_algo;
|
||||
unsigned char *kdf_params = NULL;
|
||||
size_t kdf_params_len = 0;
|
||||
|
||||
fingerprint_from_pk (pk, fp, NULL);
|
||||
|
||||
ecc_oid = openpgp_oid_to_str (pk->pkey[0]);
|
||||
if (!ecc_oid)
|
||||
@ -802,6 +807,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 32;
|
||||
is_weierstrass = 0;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_X448)
|
||||
{
|
||||
@ -816,6 +822,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 56;
|
||||
is_weierstrass = 0;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_BP256)
|
||||
{
|
||||
@ -830,6 +837,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 65;
|
||||
is_weierstrass = 1;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_BP384)
|
||||
{
|
||||
@ -844,6 +852,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 97;
|
||||
is_weierstrass = 1;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_BP512)
|
||||
{
|
||||
@ -858,6 +867,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 129;
|
||||
is_weierstrass = 1;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_P256R1)
|
||||
{
|
||||
@ -872,6 +882,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 65;
|
||||
is_weierstrass = 1;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_P384R1)
|
||||
{
|
||||
@ -886,6 +897,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 97;
|
||||
is_weierstrass = 1;
|
||||
}
|
||||
else if (ecc_algo == GCRY_KEM_RAW_P521R1)
|
||||
{
|
||||
@ -900,6 +912,7 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
ecc_ct_len = ecc_ecdh_len = 133;
|
||||
is_weierstrass = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -933,32 +946,18 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
log_printhex (ecc_ecdh, ecc_ecdh_len, "ECC ecdh:");
|
||||
}
|
||||
|
||||
if (!gcry_mpi_get_flag (pk->pkey[2], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BUG);
|
||||
goto leave;
|
||||
}
|
||||
err = ecc_build_kdf_params (&kdf_params, &kdf_params_len,
|
||||
&kdf_params_spec, pk->pkey, fp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
kek_params = gcry_mpi_get_opaque (pk->pkey[2], &nbits);
|
||||
kek_params_size = (nbits+7)/8;
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (kek_params, kek_params_size, "ecdh KDF params:");
|
||||
|
||||
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
|
||||
if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
kdf_hash_algo = kek_params[2];
|
||||
kdf_encr_algo = kek_params[3];
|
||||
keywrap_cipher_algo = kdf_params_spec[3];
|
||||
kdf_hash_algo = kdf_params_spec[2];
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
|
||||
openpgp_md_algo_name (kdf_hash_algo),
|
||||
openpgp_cipher_algo_name (kdf_encr_algo));
|
||||
openpgp_cipher_algo_name (keywrap_cipher_algo));
|
||||
|
||||
if (kdf_hash_algo != GCRY_MD_SHA256
|
||||
&& kdf_hash_algo != GCRY_MD_SHA384
|
||||
@ -968,15 +967,15 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (kdf_encr_algo != CIPHER_ALGO_AES
|
||||
&& kdf_encr_algo != CIPHER_ALGO_AES192
|
||||
&& kdf_encr_algo != CIPHER_ALGO_AES256)
|
||||
if (keywrap_cipher_algo != CIPHER_ALGO_AES
|
||||
&& keywrap_cipher_algo != CIPHER_ALGO_AES192
|
||||
&& keywrap_cipher_algo != CIPHER_ALGO_AES256)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
kek_len = gcry_cipher_get_algo_keylen (kdf_encr_algo);
|
||||
kek_len = gcry_cipher_get_algo_keylen (keywrap_cipher_algo);
|
||||
if (kek_len > gcry_md_get_algo_dlen (kdf_hash_algo))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
@ -990,8 +989,14 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = gnupg_ecc_6637_kdf (kek, kek_len, kdf_hash_algo,
|
||||
ecc_ecdh, ecc_ecdh_len, pk);
|
||||
err = gnupg_ecc_kem_kdf (kek, kek_len, kdf_hash_algo,
|
||||
is_weierstrass ?
|
||||
ecc_ecdh + 1 : ecc_ecdh,
|
||||
is_weierstrass ?
|
||||
(ecc_ecdh_len - 1) / 2 : ecc_ecdh_len,
|
||||
NULL, 0, NULL, 0,
|
||||
kdf_params, kdf_params_len);
|
||||
xfree (kdf_params);
|
||||
if (err)
|
||||
{
|
||||
if (opt.verbose)
|
||||
@ -1002,7 +1007,8 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (kek, kek_len, "KEK:");
|
||||
|
||||
err = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
err = gcry_cipher_open (&hd, keywrap_cipher_algo,
|
||||
GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (!err)
|
||||
err = gcry_cipher_setkey (hd, kek, kek_len);
|
||||
if (err)
|
||||
|
10
g10/pkglue.h
10
g10/pkglue.h
@ -38,12 +38,10 @@ int pk_check_secret_key (pubkey_algo_t algo, gcry_mpi_t *skey);
|
||||
|
||||
/*-- ecdh.c --*/
|
||||
gcry_mpi_t pk_ecdh_default_params (unsigned int qbits);
|
||||
int pk_ecdh_decrypt (gcry_mpi_t *result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data,
|
||||
const byte *frame, size_t nframe,
|
||||
gcry_mpi_t * skey);
|
||||
|
||||
gpg_error_t gnupg_ecc_6637_kdf (void *kek, size_t kek_len, int hashalgo,
|
||||
const void *ecdh, size_t ecdh_len, PKT_public_key *pk);
|
||||
gpg_error_t ecc_build_kdf_params (unsigned char **r_kdf_params, size_t *r_len,
|
||||
const unsigned char **r_kdf_params_spec,
|
||||
gcry_mpi_t *pkey,
|
||||
const byte fp[MAX_FINGERPRINT_LEN]);
|
||||
|
||||
#endif /*GNUPG_G10_PKGLUE_H*/
|
||||
|
@ -194,54 +194,19 @@ 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;
|
||||
size_t kdf_params_len = 0;
|
||||
|
||||
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:");
|
||||
err = ecc_build_kdf_params (&kdf_params, &kdf_params_len,
|
||||
&kdf_params_spec, sk->pkey, fp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
keywrap_cipher_algo = kdf_params_spec[3];
|
||||
kdf_hash_algo = kdf_params_spec[2];
|
||||
@ -256,7 +221,7 @@ ecdh_sexp_build (gcry_sexp_t *r_s_data, struct pubkey_enc_list *enc,
|
||||
"(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);
|
||||
(int)kdf_params_len, kdf_params);
|
||||
xfree (kdf_params);
|
||||
return err;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user