From 5761a9ba74e41f52660e20a1de700fe784c97832 Mon Sep 17 00:00:00 2001 From: Andrey Jivsov Date: Mon, 10 Jan 2011 20:24:14 -0800 Subject: [PATCH] 'g10/gpg2 --encrypt --debug 15 -r ecdsa -a -o _e.asc _' and 'g10/gpg2 --debug 15 _e.asc', as well as decoding of an old message posted on https://sites.google.com/site/brainhub/pgpecckeys work. This is the milestone 2 that brings in ECDH support from http://code.google.com/p/gnupg-ecc/source/detail?r=15 . This corresponds to the commit 899386826c85f1e757e75bcc5d5b2159d05676a0 in libgcrypt --- g10/call-agent.c | 3 -- g10/call-agent.h | 1 - g10/ecdh.c | 82 ++++++++++++++++++++---------------------------- g10/pkglue.c | 74 ------------------------------------------- g10/pkglue.h | 4 +-- g10/pubkey-enc.c | 40 +++++++++++++++++++++-- 6 files changed, 73 insertions(+), 131 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 25f9a537e..dc2ace0e5 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1744,7 +1744,6 @@ inq_ciphertext_cb (void *opaque, const char *line) gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, gcry_sexp_t s_ciphertext, - const byte sk_fp[MAX_FINGERPRINT_LEN], unsigned char **r_buf, size_t *r_buflen) { gpg_error_t err; @@ -1753,8 +1752,6 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, size_t n, len; char *p, *buf, *endp; - /*TODO: use sk_fp */ - if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen) return gpg_error (GPG_ERR_INV_VALUE); *r_buf = NULL; diff --git a/g10/call-agent.h b/g10/call-agent.h index 45e593bb8..e09c30990 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -168,7 +168,6 @@ gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce, /* Decrypt a ciphertext. */ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, gcry_sexp_t s_ciphertext, - const byte sk_fp[MAX_FINGERPRINT_LEN], unsigned char **r_buf, size_t *r_buflen); /* Retrieve a key encryption key. */ diff --git a/g10/ecdh.c b/g10/ecdh.c index 6615b75a4..091a28cde 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -76,8 +76,6 @@ pk_ecdh_default_params_to_mpi( int qbits ) { */ byte * pk_ecdh_default_params( int qbits, size_t *sizeout ) { - gpg_error_t err; - gcry_mpi_t result; /* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */ byte kek_params[4] = { 3 /*size of following field*/, @@ -370,6 +368,29 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi, return rc; } + +static gcry_mpi_t +gen_k (unsigned nbits) +{ + gcry_mpi_t k; + + k = gcry_mpi_snew (nbits); + if (DBG_CIPHER) + log_debug ("choosing a random k of %u bits\n", nbits); + + gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM); + + if( DBG_CIPHER ) { + unsigned char *buffer; + if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k)) + BUG (); + log_debug("ephemeral scalar MPI #0: %s\n", buffer); + gcry_free( buffer ); + } + + return k; +} + /* Perform ECDH encryption, which involves ECDH key generation. */ int @@ -377,25 +398,17 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr { gcry_sexp_t s_ciph, s_data, s_pkey; - PKT_public_key *pk_eph; int nbits; int rc; + gcry_mpi_t k; nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey ); - - /*** Generate an ephemeral key ***/ - rc = pk_ecc_keypair_gen( &pk_eph, PUBKEY_ALGO_ECDH, KEYGEN_FLAG_TRANSIENT_KEY | KEYGEN_FLAG_NO_PROTECTION /*this is ephemeral*/, "", nbits ); - if( rc ) - return rc; - if( DBG_CIPHER ) { - unsigned char *buffer; - if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, pk_eph->pkey[1])) - BUG (); - log_debug("ephemeral key MPI #0: %s\n", buffer); - gcry_free( buffer ); - } - free_public_key (pk_eph); + /*** Generate an ephemeral key, actually, a scalar ***/ + + k = gen_k (nbits); + if( k == NULL ) + BUG (); /*** Done with ephemeral key generation. * Now use ephemeral secret to get the shared secret. ***/ @@ -406,7 +419,7 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr BUG (); /* put the data into a simple list */ - if (gcry_sexp_build (&s_data, NULL, "%m", pk_eph->pkey[3])) /* ephemeral scalar goes as data */ + if (gcry_sexp_build (&s_data, NULL, "%m", k)) /* ephemeral scalar goes as data */ BUG (); /* pass it to libgcrypt */ @@ -421,7 +434,7 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr { gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* ... and get the shared point */ gcry_sexp_release (s_ciph); - resarr[0] = pk_eph->pkey[1]; /* ephemeral public key */ + resarr[0] = mpi_from_sexp (s_ciph, "b"); /* ephemeral public key */ if( DBG_CIPHER ) { unsigned char *buffer; @@ -441,37 +454,10 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr /* Perform ECDH decryption. */ int -pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *data, gcry_mpi_t * skey) { - gcry_sexp_t s_skey, s_data, s_ciph; - int rc; - - if (!data[0] || !data[1]) +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) { + if (!data) return gpg_error (GPG_ERR_BAD_MPI); - - rc = gcry_sexp_build (&s_skey, NULL, - "(public-key(ecdh(c%m)(q%m)(p%m)))", - skey[0]/*curve*/, data[0]/*ephemeral key*/, skey[2]/*KDF params*/); - if (rc) - BUG (); - - /* put the data into a simple list */ - if (gcry_sexp_build (&s_data, NULL, "%m", skey[3])) /* static private key (scalar) goes as data */ - BUG (); - - rc = gcry_pk_encrypt (&s_ciph, s_data, s_skey); /* encrypting ephemeral key with our private scalar yields the shared point */ - gcry_sexp_release (s_skey); - gcry_sexp_release (s_data); - if (rc) - return rc; - - { - gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* get the shared point */ - gcry_sexp_release (s_ciph); - rc = pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data[1]/*encr data as an MPI*/, skey, result ); - mpi_release( shared ); - } - - return rc; + return pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data/*encr data as an MPI*/, skey, result ); } diff --git a/g10/pkglue.c b/g10/pkglue.c index f78591940..9050cc241 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -257,80 +257,6 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX return rc; } - - -/**************** - * Emulate our old PK interface here - sometime in the future we might - * change the internal design to directly fit to libgcrypt. - */ -int -pk_decrypt (int algo, gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * data, - gcry_mpi_t * skey) -{ - gcry_sexp_t s_skey, s_data, s_plain; - int rc; - - *result = NULL; - /* make a sexp from skey */ - if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E) - { - rc = gcry_sexp_build (&s_skey, NULL, - "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", - skey[0], skey[1], skey[2], skey[3]); - } - else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E) - { - rc = gcry_sexp_build (&s_skey, NULL, - "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", - skey[0], skey[1], skey[2], skey[3], skey[4], - skey[5]); - } - else if( algo == PUBKEY_ALGO_ECDH ) { - return pk_ecdh_decrypt( result, sk_fp, data, skey ); - } - else - return GPG_ERR_PUBKEY_ALGO; - - if (rc) - BUG (); - - /* put data into a S-Exp s_data */ - if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E) - { - if (!data[0] || !data[1]) - rc = gpg_error (GPG_ERR_BAD_MPI); - else - rc = gcry_sexp_build (&s_data, NULL, - "(enc-val(elg(a%m)(b%m)))", data[0], data[1]); - } - else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E) - { - if (!data[0]) - rc = gpg_error (GPG_ERR_BAD_MPI); - else - rc = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data[0]); - } - else - BUG (); - - if (rc) - BUG (); - - rc = gcry_pk_decrypt (&s_plain, s_data, s_skey); - gcry_sexp_release (s_skey); - gcry_sexp_release (s_data); - if (rc) - return rc; - - *result = gcry_sexp_nth_mpi (s_plain, 0, 0); - gcry_sexp_release (s_plain); - if (!*result) - return -1; /* oops */ - - return 0; -} - - /* Check whether SKEY is a suitable secret key. */ int pk_check_secret_key (int algo, gcry_mpi_t *skey) diff --git a/g10/pkglue.h b/g10/pkglue.h index 0d5194818..a1c821dcd 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -33,8 +33,8 @@ int pk_decrypt (int algo, gcry_mpi_t *result, const byte fp[MAX_FINGERPRINT_LEN] gcry_mpi_t *skey); int pk_check_secret_key (int algo, gcry_mpi_t *skey); -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 * skey); +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 pk_ecdh_default_params_to_mpi( int qbits ); byte *pk_ecdh_default_params( int qbits, size_t *sizeout ); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index a5224e20a..24411e8a1 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -147,14 +147,16 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) char *keygrip; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; + const int gcry_pkalgo = map_pk_openpgp_to_gcry( sk->pubkey_algo ); /* Get the keygrip. */ err = hexkeygrip_from_pk (sk, &keygrip); if (err) goto leave; + /* Convert the data to an S-expression. */ - if (sk->pubkey_algo == GCRY_PK_ELG || sk->pubkey_algo == GCRY_PK_ELG_E) + if (gcry_pkalgo == GCRY_PK_ELG ||gcry_pkalgo == GCRY_PK_ELG_E) { if (!enc->data[0] || !enc->data[1]) err = gpg_error (GPG_ERR_BAD_MPI); @@ -162,7 +164,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))", enc->data[0], enc->data[1]); } - else if (sk->pubkey_algo == GCRY_PK_RSA || sk->pubkey_algo == GCRY_PK_RSA_E) + else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_E) { if (!enc->data[0]) err = gpg_error (GPG_ERR_BAD_MPI); @@ -170,6 +172,14 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", enc->data[0]); } + else if (gcry_pkalgo == GCRY_PK_ECDH ) + { + if (!enc->data[0] || !enc->data[1]) + err = gpg_error (GPG_ERR_BAD_MPI); + else + err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(a%m)(b%m)))", + enc->data[0], enc->data[1]); + } else err = gpg_error (GPG_ERR_BUG); @@ -181,7 +191,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) /* Decrypt. */ desc = gpg_format_keydesc (sk, 0, 1); - err = agent_pkdecrypt (NULL, keygrip, desc, s_data, fp, &frame, &nframe); + err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe); xfree (desc); gcry_sexp_release (s_data); if (err) @@ -233,6 +243,30 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) } } else { + gcry_mpi_t shared_mpi; + gcry_mpi_t decoded; + + /* at the beginning the frame is the bytes of shared point MPI */ + + err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL); + if (err) { + log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err)); + goto leave; + } + + err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/, shared_mpi, sk->pkey); + mpi_release( shared_mpi ); + if( err ) + goto leave; + + /* reuse nframe, which size is sufficient to include the session key */ + err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded); + mpi_release( decoded ); + if( err ) + goto leave; + + /* Now the frame is the bytes decrypted but padded session key */ + /* Allow double padding for the benefit of DEK size concealment. * Higher than this is wasteful. */