diff options
-rw-r--r-- | cipher/ecc.c | 48 | ||||
-rw-r--r-- | cipher/elgamal.c | 63 | ||||
-rw-r--r-- | cipher/pubkey.c | 58 | ||||
-rw-r--r-- | cipher/rsa.c | 145 | ||||
-rw-r--r-- | src/cipher-proto.h | 8 | ||||
-rw-r--r-- | src/cipher.h | 1 | ||||
-rw-r--r-- | tests/basic.c | 13 |
7 files changed, 179 insertions, 157 deletions
diff --git a/cipher/ecc.c b/cipher/ecc.c index 9a9c21b9..cf054f83 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1661,20 +1661,24 @@ ecc_encrypt_raw (int algo, gcry_sexp_t *r_result, gcry_mpi_t k, * see ecc_encrypt_raw for details. */ static gcry_err_code_t -ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) +ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data, + gcry_mpi_t *skey, int flags, + enum pk_encoding encoding, int hash_algo, + unsigned char *label, size_t labellen) { + gpg_err_code_t rc; ECC_secret_key sk; mpi_point_struct R; /* Result that we return. */ mpi_point_struct kG; mpi_ec_t ctx; gcry_mpi_t r; - int err; (void)algo; (void)flags; - - *result = NULL; + (void)encoding; + (void)hash_algo; + (void)label; + (void)labellen; if (!data || !data[0] || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] @@ -1682,11 +1686,11 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data, return GPG_ERR_BAD_MPI; point_init (&kG); - err = _gcry_ecc_os2ec (&kG, data[0]); - if (err) + rc = _gcry_ecc_os2ec (&kG, data[0]); + if (rc) { point_free (&kG); - return err; + return rc; } sk.E.model = MPI_EC_WEIERSTRASS; @@ -1694,22 +1698,22 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data, sk.E.a = skey[1]; sk.E.b = skey[2]; point_init (&sk.E.G); - err = _gcry_ecc_os2ec (&sk.E.G, skey[3]); - if (err) + rc = _gcry_ecc_os2ec (&sk.E.G, skey[3]); + if (rc) { point_free (&kG); point_free (&sk.E.G); - return err; + return rc; } sk.E.n = skey[4]; point_init (&sk.Q); - err = _gcry_ecc_os2ec (&sk.Q, skey[5]); - if (err) + rc = _gcry_ecc_os2ec (&sk.Q, skey[5]); + if (rc) { point_free (&kG); point_free (&sk.E.G); point_free (&sk.Q); - return err; + return rc; } sk.d = skey[6]; @@ -1733,6 +1737,10 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data, log_fatal ("ecdh: Failed to get affine coordinates\n"); r = _gcry_ecc_ec2os (x, y, sk.E.p); + if (!r) + rc = gpg_err_code_from_syserror (); + else + rc = 0; mpi_free (x); mpi_free (y); } @@ -1743,14 +1751,10 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data, point_free (&sk.E.G); point_free (&sk.Q); - if (!r) - return GPG_ERR_ENOMEM; - - /* Success. */ - - *result = r; - - return 0; + if (!rc) + rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %m)", r)); + mpi_free (r); + return rc; } diff --git a/cipher/elgamal.c b/cipher/elgamal.c index c2a953bd..ecbac756 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -30,6 +30,8 @@ #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "pubkey-internal.h" + typedef struct { @@ -777,28 +779,73 @@ elg_encrypt (int algo, gcry_sexp_t *r_result, static gcry_err_code_t -elg_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, int flags) +elg_decrypt (int algo, gcry_sexp_t *r_plain, + gcry_mpi_t *data, gcry_mpi_t *skey, int flags, + enum pk_encoding encoding, int hash_algo, + unsigned char *label, size_t labellen) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; ELG_secret_key sk; + gcry_mpi_t plain; (void)algo; - (void)flags; if ((! data[0]) || (! data[1]) || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) - err = GPG_ERR_BAD_MPI; + rc = GPG_ERR_BAD_MPI; else { + unsigned char *unpad = NULL; + size_t unpadlen = 0; + unsigned int nbits; + sk.p = skey[0]; sk.g = skey[1]; sk.y = skey[2]; sk.x = skey[3]; - *result = mpi_alloc_secure (mpi_get_nlimbs (sk.p)); - decrypt (*result, data[0], data[1], &sk); + + nbits = gcry_mpi_get_nbits (sk.p); + + plain = mpi_snew (nbits); + decrypt (plain, data[0], data[1], &sk); + + /* Reverse the encoding and build the s-expression. */ + switch (encoding) + { + case PUBKEY_ENC_PKCS1: + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain); + mpi_free (plain); + plain = NULL; + if (!rc) + rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)", + (int)unpadlen, unpad)); + break; + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + nbits, hash_algo, plain, label, labellen); + mpi_free (plain); + plain = NULL; + if (!rc) + rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)", + (int)unpadlen, unpad)); + break; + + default: + /* Raw format. For backward compatibility we need to assume a + signed mpi by using the sexp format string "%m". */ + rc = gcry_err_code + (gcry_sexp_build (r_plain, NULL, + (flags & PUBKEY_FLAG_LEGACYRESULT) + ? "%m" : "(value %m)", + plain)); + break; + } + + gcry_free (unpad); + mpi_free (plain); } - return err; + return rc; } diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 7085b25f..99b9ba8a 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -714,7 +714,7 @@ get_hash_algo (const char *s, size_t n) */ static gcry_err_code_t sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, - int *ret_modern, int *flags, struct pk_encoding_ctx *ctx) + int *flags, struct pk_encoding_ctx *ctx) { gcry_err_code_t err = 0; gcry_sexp_t list = NULL; @@ -726,8 +726,6 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, const char *elems; gcry_mpi_t *array = NULL; - *ret_modern = 0; - /* Check that the first element is valid. */ list = gcry_sexp_find_token (sexp, "enc-val" , 0); if (!list) @@ -757,7 +755,6 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, const char *s; int i; - *ret_modern = 1; for (i = gcry_sexp_length (l2) - 1; i > 0; i--) { s = gcry_sexp_nth_data (l2, i, &n); @@ -863,6 +860,8 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, list = l2; l2 = NULL; } + else + parsed_flags |= PUBKEY_FLAG_LEGACYRESULT; spec = spec_from_name (name); if (!spec) @@ -1533,11 +1532,8 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) gcry_err_code_t rc; gcry_mpi_t *skey = NULL; gcry_mpi_t *data = NULL; - gcry_mpi_t plain = NULL; - unsigned char *unpad = NULL; - size_t unpadlen = 0; int i; - int modern, flags; + int flags; struct pk_encoding_ctx ctx; gcry_pk_spec_t *spec = NULL; gcry_pk_spec_t *spec_enc = NULL; @@ -1551,7 +1547,7 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) goto leave; init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey)); - rc = sexp_to_enc (s_data, &data, &spec_enc, &modern, &flags, &ctx); + rc = sexp_to_enc (s_data, &data, &spec_enc, &flags, &ctx); if (rc) goto leave; @@ -1571,59 +1567,25 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) } if (spec->decrypt) - rc = spec->decrypt (spec->algo, &plain, data, skey, flags); + rc = spec->decrypt (spec->algo, r_plain, data, skey, flags, + ctx.encoding, ctx.hash_algo, + ctx.label, ctx.labellen); else rc = GPG_ERR_NOT_IMPLEMENTED; if (rc) goto leave; - if (DBG_CIPHER && !fips_mode ()) - log_mpidump (" plain", plain); - - /* Do un-padding if necessary. */ - switch (ctx.encoding) - { - case PUBKEY_ENC_PKCS1: - rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, - gcry_pk_get_nbits (s_skey), - plain); - mpi_free (plain); - plain = NULL; - if (!rc) - rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)", - (int)unpadlen, unpad)); - break; - - case PUBKEY_ENC_OAEP: - rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, - gcry_pk_get_nbits (s_skey), ctx.hash_algo, - plain, ctx.label, ctx.labellen); - mpi_free (plain); - plain = NULL; - if (!rc) - rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)", - (int)unpadlen, unpad)); - break; + /* if (DBG_CIPHER && !fips_mode ()) */ + /* log_mpidump (" plain", plain); */ - default: - /* Raw format. For backward compatibility we need to assume a - signed mpi by using the sexp format string "%m". */ - rc = gcry_err_code (gcry_sexp_build - (r_plain, NULL, modern? "(value %m)" : "%m", plain)); - break; - } leave: - gcry_free (unpad); - if (skey) { release_mpi_array (skey); gcry_free (skey); } - mpi_free (plain); - if (data) { release_mpi_array (data); diff --git a/cipher/rsa.c b/cipher/rsa.c index 5754e438..71052711 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -32,6 +32,7 @@ #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "pubkey-internal.h" typedef struct @@ -737,47 +738,6 @@ secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) -/* Perform RSA blinding. */ -static gcry_mpi_t -rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n) -{ - /* A helper. */ - gcry_mpi_t a; - - /* Result. */ - gcry_mpi_t y; - - a = gcry_mpi_snew (gcry_mpi_get_nbits (n)); - y = gcry_mpi_snew (gcry_mpi_get_nbits (n)); - - /* Now we calculate: y = (x * r^e) mod n, where r is the random - number, e is the public exponent, x is the non-blinded data and n - is the RSA modulus. */ - gcry_mpi_powm (a, r, e, n); - gcry_mpi_mulm (y, a, x, n); - - gcry_mpi_release (a); - - return y; -} - -/* Undo RSA blinding. */ -static gcry_mpi_t -rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n) -{ - gcry_mpi_t y; - - y = gcry_mpi_snew (gcry_mpi_get_nbits (n)); - - /* Here we calculate: y = (x * r^-1) mod n, where x is the blinded - decrypted data, ri is the modular multiplicative inverse of r and - n is the RSA modulus. */ - - gcry_mpi_mulm (y, ri, x, n); - - return y; -} - /********************************************* ************** interface ****************** *********************************************/ @@ -926,15 +886,18 @@ rsa_encrypt (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, static gcry_err_code_t -rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) +rsa_decrypt (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data, + gcry_mpi_t *skey, int flags, + enum pk_encoding encoding, int hash_algo, + unsigned char *label, size_t labellen) + { + gpg_err_code_t rc; RSA_secret_key sk; - gcry_mpi_t r = MPI_NULL; /* Random number needed for blinding. */ - gcry_mpi_t ri = MPI_NULL; /* Modular multiplicative inverse of - r. */ - gcry_mpi_t x = MPI_NULL; /* Data to decrypt. */ - gcry_mpi_t y; /* Result. */ + gcry_mpi_t plain; /* Decrypted data. */ + unsigned char *unpad = NULL; + size_t unpadlen = 0; + unsigned int nbits; (void)algo; @@ -946,24 +909,29 @@ rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, sk.q = skey[4]; /* Optional. */ sk.u = skey[5]; /* Optional. */ - y = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); + nbits = gcry_mpi_get_nbits (sk.n); + + plain = gcry_mpi_snew (nbits); /* We use blinding by default to mitigate timing attacks which can be practically mounted over the network as shown by Brumley and Boney in 2003. */ if (! (flags & PUBKEY_FLAG_NO_BLINDING)) { - /* Initialize blinding. */ + gcry_mpi_t r; /* Random number needed for blinding. */ + gcry_mpi_t ri; /* Modular multiplicative inverse of r. */ + gcry_mpi_t ciph; /* Blinded data to decrypt. */ /* First, we need a random number r between 0 and n - 1, which is relatively prime to n (i.e. it is neither p nor q). The random number needs to be only unpredictable, thus we employ the gcry_create_nonce function by using GCRY_WEAK_RANDOM with gcry_mpi_randomize. */ - r = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); - ri = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); + r = gcry_mpi_snew (nbits); + ri = gcry_mpi_snew (nbits); + ciph = gcry_mpi_snew (nbits); - gcry_mpi_randomize (r, gcry_mpi_get_nbits (sk.n), GCRY_WEAK_RANDOM); + gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM); gcry_mpi_mod (r, r, sk.n); /* Calculate inverse of r. It practically impossible that the @@ -971,39 +939,64 @@ rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, allocated resources. */ if (!gcry_mpi_invm (ri, r, sk.n)) return GPG_ERR_INTERNAL; - } - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) - x = rsa_blind (data[0], r, sk.e, sk.n); - else - x = data[0]; - - /* Do the encryption. */ - secret (y, x, &sk); + /* Do blinding. We calculate: y = (x * r^e) mod n, where r is + the random number, e is the public exponent, x is the + non-blinded data and n is the RSA modulus. */ + gcry_mpi_powm (ciph, r, sk.e, sk.n); + gcry_mpi_mulm (ciph, ciph, data[0], sk.n); - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) - { - /* Undo blinding. */ - gcry_mpi_t a = gcry_mpi_copy (y); + /* Perform decryption. */ + secret (plain, ciph, &sk); - gcry_mpi_release (y); - y = rsa_unblind (a, ri, sk.n); + /* Undo blinding. Here we calculate: y = (x * r^-1) mod n, + where x is the blinded decrypted data, ri is the modular + multiplicative inverse of r and n is the RSA modulus. */ + gcry_mpi_mulm (plain, plain, ri, sk.n); - gcry_mpi_release (a); + gcry_mpi_release (ciph); + gcry_mpi_release (r); + gcry_mpi_release (ri); } + else + secret (plain, data[0], &sk); - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) + /* Reverse the encoding and build the s-expression. */ + switch (encoding) { - /* Deallocate resources needed for blinding. */ - gcry_mpi_release (x); - gcry_mpi_release (r); - gcry_mpi_release (ri); + case PUBKEY_ENC_PKCS1: + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain); + mpi_free (plain); + plain = NULL; + if (!rc) + rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)", + (int)unpadlen, unpad)); + break; + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + nbits, hash_algo, plain, label, labellen); + mpi_free (plain); + plain = NULL; + if (!rc) + rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)", + (int)unpadlen, unpad)); + break; + + default: + /* Raw format. For backward compatibility we need to assume a + signed mpi by using the sexp format string "%m". */ + rc = gcry_err_code + (gcry_sexp_build (r_plain, NULL, + (flags & PUBKEY_FLAG_LEGACYRESULT)? "%m":"(value %m)", + plain)); + break; } - /* Copy out result. */ - *result = y; + gcry_free (unpad); + mpi_free (plain); - return GPG_ERR_NO_ERROR; + return rc; } diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 1285fe85..212857b8 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -67,10 +67,14 @@ typedef gcry_err_code_t (*gcry_pk_encrypt_t) (int algo, /* Type for the pk_decrypt function. */ typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo, - gcry_mpi_t *result, + gcry_sexp_t *r_result, gcry_mpi_t *data, gcry_mpi_t *skey, - int flags); + int flags, + enum pk_encoding encoding, + int hash_algo, + unsigned char *label, + size_t labellen); /* Type for the pk_sign function. */ typedef gcry_err_code_t (*gcry_pk_sign_t) (int algo, diff --git a/src/cipher.h b/src/cipher.h index 9fe30a66..e3a2fe0c 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -30,6 +30,7 @@ #define PUBKEY_FLAG_RFC6979 (1 << 1) #define PUBKEY_FLAG_EDDSA (1 << 2) #define PUBKEY_FLAG_FIXEDLEN (1 << 3) +#define PUBKEY_FLAG_LEGACYRESULT (1 << 4) enum pk_operation { diff --git a/tests/basic.c b/tests/basic.c index 14ceea4e..e9709d5c 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -3654,7 +3654,18 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo) } rc = gcry_pk_decrypt (&plain, ciph, skey); if (gcry_err_code (rc) != datas[dataidx].decrypt_expected_rc) - fail ("gcry_pk_decrypt failed: %s\n", gpg_strerror (rc)); + { + if (verbose) + { + show_sexp (" data:\n", data); + show_sexp (" ciph:\n", ciph); + show_sexp (" key:\n", skey); + } + fail ("gcry_pk_decrypt failed: expected %d (%s), got %d (%s)\n", + datas[dataidx].decrypt_expected_rc, + gpg_strerror (datas[dataidx].decrypt_expected_rc), + rc, gpg_strerror (rc)); + } if (!rc && datas[dataidx].unpadded) { |