diff options
author | Werner Koch <wk@gnupg.org> | 2013-10-11 21:13:12 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2013-10-11 21:13:12 +0200 |
commit | 07950c865a901afc48acb46f0695040cadfd5068 (patch) | |
tree | d608acf3116831d6a8874caa4686efcd44f87b9e /cipher | |
parent | 6bd5d18c45a4a3ce8f0f66f56c83b80594877f53 (diff) | |
download | libgcrypt-07950c865a901afc48acb46f0695040cadfd5068.tar.gz |
pubkey: Move sexp parsing for gcry_pk_decrypt to the modules.
* cipher/rsa.c (rsa_decrypt): Revamp.
* cipher/elgamal.c (elg_decrypt): Revamp.
* cipher/ecc.c (ecc_decrypt_raw): Revamp.
* cipher/pubkey.c (gcry_pk_decrypt): Simplify.
(sexp_to_enc): Remove.
* cipher/pubkey-util.c (_gcry_pk_util_preparse_encval): New.
--
Note that we do not have a regression test for ecc_decrypt_raw. Even
GnuPG does not use it. we also better check whether the interface is
really usable; for example GnuPG implements way to much low-level ECC
code. Maybe we should move the OpenPGP ECC encryption code into
Libgcrypt.
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/ecc.c | 159 | ||||
-rw-r--r-- | cipher/elgamal.c | 145 | ||||
-rw-r--r-- | cipher/pubkey-internal.h | 4 | ||||
-rw-r--r-- | cipher/pubkey-util.c | 291 | ||||
-rw-r--r-- | cipher/pubkey.c | 265 | ||||
-rw-r--r-- | cipher/rsa.c | 166 |
6 files changed, 549 insertions, 481 deletions
diff --git a/cipher/ecc.c b/cipher/ecc.c index 051308f0..17724e82 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1949,70 +1949,115 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) * see ecc_encrypt_raw for details. */ static gcry_err_code_t -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) +ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) { gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data_e = NULL; ECC_secret_key sk; - mpi_point_struct R; /* Result that we return. */ + gcry_mpi_t mpi_g = NULL; + char *curvename = NULL; + mpi_ec_t ec = NULL; mpi_point_struct kG; - mpi_ec_t ctx; - gcry_mpi_t r; - - (void)algo; - (void)flags; - (void)encoding; - (void)hash_algo; - (void)label; - (void)labellen; - - if (!data || !data[0] - || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] - || !skey[5] || !skey[6] ) - return GPG_ERR_BAD_MPI; + mpi_point_struct R; + gcry_mpi_t r = NULL; + memset (&sk, 0, sizeof sk); point_init (&kG); - rc = _gcry_ecc_os2ec (&kG, data[0]); + point_init (&R); + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + ecc_get_nbits (keyparms)); + + /* + * Extract the data. + */ + rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx); if (rc) + goto leave; + rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("ecc_decrypt d_e", data_e); + if (mpi_is_opaque (data_e)) { - point_free (&kG); - return rc; + rc = GPG_ERR_INV_DATA; + goto leave; } - sk.E.model = MPI_EC_WEIERSTRASS; - sk.E.p = skey[0]; - sk.E.a = skey[1]; - sk.E.b = skey[2]; - point_init (&sk.E.G); - rc = _gcry_ecc_os2ec (&sk.E.G, skey[3]); + /* + * Extract the key. + */ + rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &sk.d, NULL); if (rc) + goto leave; + if (mpi_g) { - point_free (&kG); - point_free (&sk.E.G); - return rc; + point_init (&sk.E.G); + rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g); + if (rc) + goto leave; } - sk.E.n = skey[4]; - point_init (&sk.Q); - rc = _gcry_ecc_os2ec (&sk.Q, skey[5]); + /* Add missing parameters using the optional curve parameter. */ + gcry_sexp_release (l1); + l1 = gcry_sexp_find_token (keyparms, "curve", 5); + if (l1) + { + curvename = gcry_sexp_nth_string (l1, 1); + if (curvename) + { + rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL); + if (rc) + return rc; + } + } + /* Guess required fields if a curve parameter has not been given. */ + if (!curvename) + { + sk.E.model = MPI_EC_WEIERSTRASS; + sk.E.dialect = ECC_DIALECT_STANDARD; + } + if (DBG_CIPHER) + { + log_debug ("ecc_decrypt info: %s/%s\n", + _gcry_ecc_model2str (sk.E.model), + _gcry_ecc_dialect2str (sk.E.dialect)); + if (sk.E.name) + log_debug ("ecc_decrypt name: %s\n", sk.E.name); + log_printmpi ("ecc_decrypt p", sk.E.p); + log_printmpi ("ecc_decrypt a", sk.E.a); + log_printmpi ("ecc_decrypt b", sk.E.b); + log_printpnt ("ecc_decrypt g", &sk.E.G, NULL); + log_printmpi ("ecc_decrypt n", sk.E.n); + if (!fips_mode ()) + log_printmpi ("ecc_decrypt d", sk.d); + } + if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + + /* + * Compute the plaintext. + */ + rc = _gcry_ecc_os2ec (&kG, data_e); if (rc) { point_free (&kG); - point_free (&sk.E.G); - point_free (&sk.Q); return rc; } - sk.d = skey[6]; - ctx = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, - sk.E.p, sk.E.a, sk.E.b); + ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, + sk.E.p, sk.E.a, sk.E.b); /* R = dkG */ - point_init (&R); - _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ctx); - - point_free (&kG); + _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ec); /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so: */ { @@ -2021,7 +2066,7 @@ ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data, x = mpi_new (0); y = mpi_new (0); - if (_gcry_mpi_ec_get_affine (x, y, &R, ctx)) + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) log_fatal ("ecdh: Failed to get affine coordinates\n"); r = _gcry_ecc_ec2os (x, y, sk.E.p); @@ -2032,16 +2077,30 @@ ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data, mpi_free (x); mpi_free (y); } + if (DBG_CIPHER) + log_printmpi ("ecc_decrypt res", r); + + if (!rc) + rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r); + leave: point_free (&R); - _gcry_mpi_ec_free (ctx); point_free (&kG); + gcry_mpi_release (r); + gcry_mpi_release (sk.E.p); + gcry_mpi_release (sk.E.a); + gcry_mpi_release (sk.E.b); + gcry_mpi_release (mpi_g); point_free (&sk.E.G); - point_free (&sk.Q); - - if (!rc) - rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r); - mpi_free (r); + gcry_mpi_release (sk.E.n); + gcry_mpi_release (sk.d); + gcry_mpi_release (data_e); + gcry_free (curvename); + gcry_sexp_release (l1); + _gcry_mpi_ec_free (ec); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_decrypt => %s\n", gpg_strerror (rc)); return rc; } diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 37182874..7fedc7bf 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -811,71 +811,104 @@ elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) static gcry_err_code_t -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) +elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gcry_err_code_t rc; - ELG_secret_key sk; - gcry_mpi_t plain; + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data_a = NULL; + gcry_mpi_t data_b = NULL; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + gcry_mpi_t plain = NULL; + unsigned char *unpad = NULL; + size_t unpadlen = 0; - (void)algo; + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + elg_get_nbits (keyparms)); - if ((! data[0]) || (! data[1]) - || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) - rc = GPG_ERR_BAD_MPI; - else + /* Extract the data. */ + rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx); + if (rc) + goto leave; + rc = _gcry_pk_util_extract_mpis (l1, "ab", &data_a, &data_b, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) { - unsigned char *unpad = NULL; - size_t unpadlen = 0; - unsigned int nbits; + log_printmpi ("elg_decrypt d_a", data_a); + log_printmpi ("elg_decrypt d_b", data_b); + } + if (mpi_is_opaque (data_a) || mpi_is_opaque (data_b)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; + /* Extract the key. */ + rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + return rc; + if (DBG_CIPHER) + { + log_printmpi ("elg_decrypt p", sk.p); + log_printmpi ("elg_decrypt g", sk.g); + log_printmpi ("elg_decrypt y", sk.y); + if (!fips_mode ()) + log_printmpi ("elg_decrypt x", sk.x); + } - nbits = gcry_mpi_get_nbits (sk.p); + plain = gcry_mpi_snew (ctx.nbits); + decrypt (plain, data_a, data_b, &sk); + if (DBG_CIPHER) + log_printmpi ("elg_decrypt res", plain); - plain = mpi_snew (nbits); - decrypt (plain, data[0], data[1], &sk); + /* Reverse the encoding and build the s-expression. */ + switch (ctx.encoding) + { + case PUBKEY_ENC_PKCS1: + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); + mpi_free (plain); plain = NULL; + if (!rc) + rc = gcry_sexp_build (r_plain, NULL, "(value %b)", + (int)unpadlen, unpad); + break; + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + ctx.nbits, ctx.hash_algo, plain, + ctx.label, ctx.labellen); + mpi_free (plain); plain = NULL; + if (!rc) + rc = 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_sexp_build (r_plain, NULL, + (ctx.flags & PUBKEY_FLAG_LEGACYRESULT) + ? "%m" : "(value %m)", + plain); + break; + } - /* 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_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_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_sexp_build (r_plain, NULL, - (flags & PUBKEY_FLAG_LEGACYRESULT) - ? "%m" : "(value %m)", - plain); - break; - } - gcry_free (unpad); - mpi_free (plain); - } + leave: + gcry_free (unpad); + gcry_mpi_release (plain); + gcry_mpi_release (sk.p); + gcry_mpi_release (sk.g); + gcry_mpi_release (sk.y); + gcry_mpi_release (sk.x); + gcry_mpi_release (data_a); + gcry_mpi_release (data_b); + gcry_sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_decrypt => %s\n", gpg_strerror (rc)); return rc; } diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h index 3bed609a..7e3667e9 100644 --- a/cipher/pubkey-internal.h +++ b/cipher/pubkey-internal.h @@ -32,6 +32,10 @@ gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, gcry_sexp_t *r_parms, int *r_eccflags); +gpg_err_code_t _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, + const char **algo_names, + gcry_sexp_t *r_parms, + struct pk_encoding_ctx *ctx); void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op, unsigned int nbits); diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index debe6ca6..9a94fe27 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -46,6 +46,57 @@ pss_verify_cmp (void *opaque, gcry_mpi_t tmp) } +static int +get_hash_algo (const char *s, size_t n) +{ + static const struct { const char *name; int algo; } hashnames[] = { + { "sha1", GCRY_MD_SHA1 }, + { "md5", GCRY_MD_MD5 }, + { "sha256", GCRY_MD_SHA256 }, + { "ripemd160", GCRY_MD_RMD160 }, + { "rmd160", GCRY_MD_RMD160 }, + { "sha384", GCRY_MD_SHA384 }, + { "sha512", GCRY_MD_SHA512 }, + { "sha224", GCRY_MD_SHA224 }, + { "md2", GCRY_MD_MD2 }, + { "md4", GCRY_MD_MD4 }, + { "tiger", GCRY_MD_TIGER }, + { "haval", GCRY_MD_HAVAL }, + { NULL, 0 } + }; + int algo; + int i; + + for (i=0; hashnames[i].name; i++) + { + if ( strlen (hashnames[i].name) == n + && !memcmp (hashnames[i].name, s, n)) + break; + } + if (hashnames[i].name) + algo = hashnames[i].algo; + else + { + /* In case of not listed or dynamically allocated hash + algorithm we fall back to this somewhat slower + method. Further, it also allows to use OIDs as + algorithm names. */ + char *tmpname; + + tmpname = gcry_malloc (n+1); + if (!tmpname) + algo = 0; /* Out of core - silently give up. */ + else + { + memcpy (tmpname, s, n); + tmpname[n] = 0; + algo = gcry_md_map_name (tmpname); + gcry_free (tmpname); + } + } + return algo; +} + /* Get the "nbits" parameter from an s-expression of the format: * @@ -249,7 +300,7 @@ _gcry_pk_util_extract_mpis (gcry_sexp_t sexp, const char *list, ...) } -/* Parse a "sig_val s-expression and store the inner parameter list at +/* Parse a "sig-val" s-expression and store the inner parameter list at R_PARMS. ALGO_NAMES is used to verify that the algorithm in "sig-val" is valid. Returns 0 on success and stores a new list at R_PARMS which must be freed by the caller. On error R_PARMS is set @@ -336,6 +387,192 @@ _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, return rc; } + +/* Parse a "enc-val" s-expression and store the inner parameter list + at R_PARMS. ALGO_NAMES is used to verify that the algorithm in + "enc-val" is valid. Returns 0 on success and stores a new list at + R_PARMS which must be freed by the caller. On error R_PARMS is set + to NULL and an error code returned. If R_ECCFLAGS is not NULL flag + values are set into it; as of now they are only used with ecc + algorithms. + + (enc-val + [(flags [raw, pkcs1, oaep, no-blinding])] + [(hash-algo <algo>)] + [(label <label>)] + (<algo> + (<param_name1> <mpi>) + ... + (<param_namen> <mpi>))) + + HASH-ALGO and LABEL are specific to OAEP. CTX will be updated with + encoding information. */ +gpg_err_code_t +_gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names, + gcry_sexp_t *r_parms, + struct pk_encoding_ctx *ctx) +{ + gcry_err_code_t rc = 0; + gcry_sexp_t l1 = NULL; + gcry_sexp_t l2 = NULL; + char *name = NULL; + size_t n; + int parsed_flags = 0; + int i; + + *r_parms = NULL; + + /* Check that the first element is valid. */ + l1 = gcry_sexp_find_token (sexp, "enc-val" , 0); + if (!l1) + { + rc = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ + goto leave; + } + + l2 = gcry_sexp_nth (l1, 1); + if (!l2) + { + rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */ + goto leave; + } + + /* Extract identifier of sublist. */ + name = _gcry_sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + + if (!strcmp (name, "flags")) + { + /* There is a flags element - process it. */ + const char *s; + + for (i = gcry_sexp_length (l2) - 1; i > 0; i--) + { + s = gcry_sexp_nth_data (l2, i, &n); + if (! s) + ; /* Not a data element - ignore. */ + else if (n == 3 && !memcmp (s, "raw", 3) + && ctx->encoding == PUBKEY_ENC_UNKNOWN) + ctx->encoding = PUBKEY_ENC_RAW; + else if (n == 5 && !memcmp (s, "pkcs1", 5) + && ctx->encoding == PUBKEY_ENC_UNKNOWN) + ctx->encoding = PUBKEY_ENC_PKCS1; + else if (n == 4 && !memcmp (s, "oaep", 4) + && ctx->encoding == PUBKEY_ENC_UNKNOWN) + ctx->encoding = PUBKEY_ENC_OAEP; + else if (n == 3 && !memcmp (s, "pss", 3) + && ctx->encoding == PUBKEY_ENC_UNKNOWN) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + else if (n == 11 && !memcmp (s, "no-blinding", 11)) + parsed_flags |= PUBKEY_FLAG_NO_BLINDING; + else + { + rc = GPG_ERR_INV_FLAG; + goto leave; + } + } + + /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */ + if (ctx->encoding == PUBKEY_ENC_OAEP) + { + /* Get HASH-ALGO. */ + gcry_sexp_release (l2); + l2 = gcry_sexp_find_token (l1, "hash-algo", 0); + if (l2) + { + s = gcry_sexp_nth_data (l2, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else + { + ctx->hash_algo = get_hash_algo (s, n); + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + } + if (rc) + goto leave; + } + + /* Get LABEL. */ + gcry_sexp_release (l2); + l2 = gcry_sexp_find_token (l1, "label", 0); + if (l2) + { + s = gcry_sexp_nth_data (l2, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else if (n > 0) + { + ctx->label = gcry_malloc (n); + if (!ctx->label) + rc = gpg_err_code_from_syserror (); + else + { + memcpy (ctx->label, s, n); + ctx->labellen = n; + } + } + if (rc) + goto leave; + } + } + + /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */ + for (i = 2; (gcry_sexp_release (l2), l2 = gcry_sexp_nth (l1, i)); i++) + { + s = gcry_sexp_nth_data (l2, 0, &n); + if (!(n == 9 && !memcmp (s, "hash-algo", 9)) + && !(n == 5 && !memcmp (s, "label", 5)) + && !(n == 15 && !memcmp (s, "random-override", 15))) + break; + } + if (!l2) + { + rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */ + goto leave; + } + + /* Extract sublist identifier. */ + gcry_free (name); + name = _gcry_sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + } + else /* No flags - flag as legacy structure. */ + parsed_flags |= PUBKEY_FLAG_LEGACYRESULT; + + for (i=0; algo_names[i]; i++) + if (!stricmp (name, algo_names[i])) + break; + if (!algo_names[i]) + { + rc = GPG_ERR_CONFLICT; /* "enc-val" uses an unexpected algo. */ + goto leave; + } + + *r_parms = l2; + l2 = NULL; + ctx->flags |= parsed_flags; + rc = 0; + + leave: + gcry_free (name); + gcry_sexp_release (l2); + gcry_sexp_release (l1); + return rc; +} + + /* Initialize an encoding context. */ void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx, @@ -362,58 +599,6 @@ _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx) } -static inline int -get_hash_algo (const char *s, size_t n) -{ - static const struct { const char *name; int algo; } hashnames[] = { - { "sha1", GCRY_MD_SHA1 }, - { "md5", GCRY_MD_MD5 }, - { "sha256", GCRY_MD_SHA256 }, - { "ripemd160", GCRY_MD_RMD160 }, - { "rmd160", GCRY_MD_RMD160 }, - { "sha384", GCRY_MD_SHA384 }, - { "sha512", GCRY_MD_SHA512 }, - { "sha224", GCRY_MD_SHA224 }, - { "md2", GCRY_MD_MD2 }, - { "md4", GCRY_MD_MD4 }, - { "tiger", GCRY_MD_TIGER }, - { "haval", GCRY_MD_HAVAL }, - { NULL, 0 } - }; - int algo; - int i; - - for (i=0; hashnames[i].name; i++) - { - if ( strlen (hashnames[i].name) == n - && !memcmp (hashnames[i].name, s, n)) - break; - } - if (hashnames[i].name) - algo = hashnames[i].algo; - else - { - /* In case of not listed or dynamically allocated hash - algorithm we fall back to this somewhat slower - method. Further, it also allows to use OIDs as - algorithm names. */ - char *tmpname; - - tmpname = gcry_malloc (n+1); - if (!tmpname) - algo = 0; /* Out of core - silently give up. */ - else - { - memcpy (tmpname, s, n); - tmpname[n] = 0; - algo = gcry_md_map_name (tmpname); - gcry_free (tmpname); - } - } - return algo; -} - - /* Take the hash value and convert into an MPI, suitable for passing to the low level functions. We currently support the old style way of passing just a MPI and the modern interface which diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 8a46e4e5..d7a474d8 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -693,213 +693,6 @@ get_hash_algo (const char *s, size_t n) } -/**************** - * Take sexp and return an array of MPI as used for our internal decrypt - * function. - * s_data = (enc-val - * [(flags [raw, pkcs1, oaep, no-blinding])] - * [(hash-algo <algo>)] - * [(label <label>)] - * (<algo> - * (<param_name1> <mpi>) - * ... - * (<param_namen> <mpi>) - * )) - * HASH-ALGO and LABEL are specific to OAEP. - * RET_MODERN is set to true when at least an empty flags list has been found. - * CTX is used to return encoding information; it may be NULL in which - * case raw encoding is used. - */ -static gcry_err_code_t -sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, - int *flags, struct pk_encoding_ctx *ctx) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list = NULL; - gcry_sexp_t l2 = NULL; - gcry_pk_spec_t *spec = NULL; - char *name = NULL; - size_t n; - int parsed_flags = 0; - const char *elems; - gcry_mpi_t *array = NULL; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, "enc-val" , 0); - if (!list) - { - err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ - goto leave; - } - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract identifier of sublist. */ - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - if (!strcmp (name, "flags")) - { - /* There is a flags element - process it. */ - const char *s; - int i; - - for (i = gcry_sexp_length (l2) - 1; i > 0; i--) - { - s = gcry_sexp_nth_data (l2, i, &n); - if (! s) - ; /* Not a data element - ignore. */ - else if (n == 3 && !memcmp (s, "raw", 3) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_RAW; - else if (n == 5 && !memcmp (s, "pkcs1", 5) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_PKCS1; - else if (n == 4 && !memcmp (s, "oaep", 4) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_OAEP; - else if (n == 3 && !memcmp (s, "pss", 3) - && ctx->encoding == PUBKEY_ENC_UNKNOWN) - { - err = GPG_ERR_CONFLICT; - goto leave; - } - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - { - err = GPG_ERR_INV_FLAG; - goto leave; - } - } - gcry_sexp_release (l2); - - /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */ - if (ctx->encoding == PUBKEY_ENC_OAEP) - { - /* Get HASH-ALGO. */ - l2 = gcry_sexp_find_token (list, "hash-algo", 0); - if (l2) - { - s = gcry_sexp_nth_data (l2, 1, &n); - if (!s) - err = GPG_ERR_NO_OBJ; - else - { - ctx->hash_algo = get_hash_algo (s, n); - if (!ctx->hash_algo) - err = GPG_ERR_DIGEST_ALGO; - } - gcry_sexp_release (l2); - if (err) - goto leave; - } - - /* Get LABEL. */ - l2 = gcry_sexp_find_token (list, "label", 0); - if (l2) - { - s = gcry_sexp_nth_data (l2, 1, &n); - if (!s) - err = GPG_ERR_NO_OBJ; - else if (n > 0) - { - ctx->label = gcry_malloc (n); - if (!ctx->label) - err = gpg_err_code_from_syserror (); - else - { - memcpy (ctx->label, s, n); - ctx->labellen = n; - } - } - gcry_sexp_release (l2); - if (err) - goto leave; - } - } - - /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */ - for (i = 2; (l2 = gcry_sexp_nth (list, i)) != NULL; i++) - { - s = gcry_sexp_nth_data (l2, 0, &n); - if (!(n == 9 && !memcmp (s, "hash-algo", 9)) - && !(n == 5 && !memcmp (s, "label", 5)) - && !(n == 15 && !memcmp (s, "random-override", 15))) - break; - gcry_sexp_release (l2); - } - - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract sublist identifier. */ - gcry_free (name); - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - gcry_sexp_release (list); - list = l2; - l2 = NULL; - } - else - parsed_flags |= PUBKEY_FLAG_LEGACYRESULT; - - spec = spec_from_name (name); - if (!spec) - { - err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - goto leave; - } - - elems = spec->elements_enc; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - { - err = gpg_err_code_from_syserror (); - goto leave; - } - - err = sexp_elements_extract (list, elems, array, NULL, 0); - - leave: - gcry_sexp_release (list); - gcry_sexp_release (l2); - gcry_free (name); - - if (err) - { - gcry_free (array); - gcry_free (ctx->label); - ctx->label = NULL; - } - else - { - *retarray = array; - *r_spec = spec; - *flags = parsed_flags; - } - - return err; -} - - /* Do a PK encrypt operation @@ -978,70 +771,22 @@ gcry_error_t 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; - int i; - int flags; - struct pk_encoding_ctx ctx; - gcry_pk_spec_t *spec = NULL; - gcry_pk_spec_t *spec_enc = NULL; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms; *r_plain = NULL; - ctx.label = NULL; - - rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_ENCR, NULL, - &skey, &spec, NULL); - if (rc) - goto leave; - _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey)); - rc = sexp_to_enc (s_data, &data, &spec_enc, &flags, &ctx); + rc = spec_from_sexp (s_skey, 1, &spec, &keyparms); if (rc) goto leave; - if (spec->algo != spec_enc->algo) - { - rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */ - goto leave; - } - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("gcry_pk_decrypt: algo=%d\n", spec->algo); - for(i = 0; i < pubkey_get_nskey (spec->algo); i++) - log_mpidump (" skey", skey[i]); - for(i = 0; i < pubkey_get_nenc (spec->algo); i++) - log_mpidump (" data", data[i]); - } - if (spec->decrypt) - rc = spec->decrypt (spec->algo, r_plain, data, skey, flags, - ctx.encoding, ctx.hash_algo, - ctx.label, ctx.labellen); + rc = spec->decrypt (r_plain, s_data, keyparms); else rc = GPG_ERR_NOT_IMPLEMENTED; - if (rc) - goto leave; - - /* if (DBG_CIPHER && !fips_mode ()) */ - /* log_mpidump (" plain", plain); */ - leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (data) - { - release_mpi_array (data); - gcry_free (data); - } - - gcry_free (ctx.label); - + gcry_sexp_release (keyparms); return gcry_error (rc); } diff --git a/cipher/rsa.c b/cipher/rsa.c index 51480df3..428185bf 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -890,13 +890,15 @@ rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) return rc; if (DBG_CIPHER) { - log_mpidump ("rsa_encrypt n", pk.n); - log_mpidump ("rsa_encrypt e", pk.e); + log_mpidump ("rsa_encrypt n", pk.n); + log_mpidump ("rsa_encrypt e", pk.e); } /* Do RSA computation and build result. */ ciph = gcry_mpi_new (0); public (ciph, data, &pk); + if (DBG_CIPHER) + log_mpidump ("rsa_encrypt res", ciph); if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN)) { /* We need to make sure to return the correct length to avoid @@ -922,92 +924,117 @@ rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) gcry_mpi_release (data); _gcry_pk_util_free_encoding_ctx (&ctx); if (DBG_CIPHER) - log_debug ("rsa_encrypt => %s\n", gpg_strerror (rc)); + log_debug ("rsa_encrypt => %s\n", gpg_strerror (rc)); return rc; } static gcry_err_code_t -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) +rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) { gpg_err_code_t rc; - RSA_secret_key sk; - gcry_mpi_t plain; /* Decrypted data. */ + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data = NULL; + RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; + gcry_mpi_t plain = NULL; + gcry_mpi_t r = NULL; /* Random number needed for blinding. */ + gcry_mpi_t ri = NULL; /* Modular multiplicative inverse of r. */ + gcry_mpi_t bldata = NULL;/* Blinded data to decrypt. */ unsigned char *unpad = NULL; size_t unpadlen = 0; - unsigned int nbits; - (void)algo; + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + rsa_get_nbits (keyparms)); - /* Extract private key. */ - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; /* Optional. */ - sk.q = skey[4]; /* Optional. */ - sk.u = skey[5]; /* Optional. */ + /* Extract the data. */ + rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx); + if (rc) + goto leave; + rc = _gcry_pk_util_extract_mpis (l1, "a", &data, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("rsa_decrypt data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - nbits = gcry_mpi_get_nbits (sk.n); + /* Extract the key. */ + rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); + if (rc) + return rc; + if (DBG_CIPHER) + { + log_printmpi ("rsa_decrypt n", sk.n); + log_printmpi ("rsa_decrypt e", sk.e); + if (!fips_mode ()) + { + log_printmpi ("rsa_decrypt d", sk.d); + log_printmpi ("rsa_decrypt p", sk.p); + log_printmpi ("rsa_decrypt q", sk.q); + log_printmpi ("rsa_decrypt u", sk.u); + } + } - plain = gcry_mpi_snew (nbits); + plain = gcry_mpi_snew (ctx.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)) + if (!(ctx.flags & PUBKEY_FLAG_NO_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 (nbits); - ri = gcry_mpi_snew (nbits); - ciph = gcry_mpi_snew (nbits); + r = gcry_mpi_snew (ctx.nbits); + ri = gcry_mpi_snew (ctx.nbits); + bldata = gcry_mpi_snew (ctx.nbits); - gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM); + gcry_mpi_randomize (r, ctx.nbits, GCRY_WEAK_RANDOM); gcry_mpi_mod (r, r, sk.n); - - /* Calculate inverse of r. It practically impossible that the - following test fails, thus we do not add code to release - allocated resources. */ if (!gcry_mpi_invm (ri, r, sk.n)) - return GPG_ERR_INTERNAL; + { + rc = GPG_ERR_INTERNAL; + goto leave; + } /* 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); + gcry_mpi_powm (bldata, r, sk.e, sk.n); + gcry_mpi_mulm (bldata, bldata, data, sk.n); /* Perform decryption. */ - secret (plain, ciph, &sk); + secret (plain, bldata, &sk); + gcry_mpi_release (bldata); bldata = NULL; /* 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 (ciph); - gcry_mpi_release (r); - gcry_mpi_release (ri); + gcry_mpi_release (r); r = NULL; + gcry_mpi_release (ri); ri = NULL; } else - secret (plain, data[0], &sk); + secret (plain, data, &sk); + + if (DBG_CIPHER) + log_printmpi ("rsa_decrypt res", plain); /* Reverse the encoding and build the s-expression. */ - switch (encoding) + switch (ctx.encoding) { case PUBKEY_ENC_PKCS1: - rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain); + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); mpi_free (plain); plain = NULL; if (!rc) @@ -1017,7 +1044,8 @@ rsa_decrypt (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data, case PUBKEY_ENC_OAEP: rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, - nbits, hash_algo, plain, label, labellen); + ctx.nbits, ctx.hash_algo, + plain, ctx.label, ctx.labellen); mpi_free (plain); plain = NULL; if (!rc) @@ -1029,14 +1057,28 @@ rsa_decrypt (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data, /* Raw format. For backward compatibility we need to assume a signed mpi by using the sexp format string "%m". */ rc = gcry_sexp_build (r_plain, NULL, - (flags & PUBKEY_FLAG_LEGACYRESULT) + (ctx.flags & PUBKEY_FLAG_LEGACYRESULT) ? "%m":"(value %m)", plain); break; } + leave: gcry_free (unpad); - mpi_free (plain); - + gcry_mpi_release (plain); + gcry_mpi_release (sk.n); + gcry_mpi_release (sk.e); + gcry_mpi_release (sk.d); + gcry_mpi_release (sk.p); + gcry_mpi_release (sk.q); + gcry_mpi_release (sk.u); + gcry_mpi_release (data); + gcry_mpi_release (r); + gcry_mpi_release (ri); + gcry_mpi_release (bldata); + gcry_sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("rsa_decrypt => %s\n", gpg_strerror (rc)); return rc; } @@ -1058,7 +1100,7 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) if (rc) goto leave; if (DBG_CIPHER) - log_mpidump ("rsa_sign data", data); + log_printmpi ("rsa_sign data", data); if (mpi_is_opaque (data)) { rc = GPG_ERR_INV_DATA; @@ -1073,14 +1115,14 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) return rc; if (DBG_CIPHER) { - log_mpidump ("rsa_sign n", sk.n); - log_mpidump ("rsa_sign e", sk.e); + log_printmpi ("rsa_sign n", sk.n); + log_printmpi ("rsa_sign e", sk.e); if (!fips_mode ()) { - log_mpidump ("rsa_sign d", sk.d); - log_mpidump ("rsa_sign p", sk.p); - log_mpidump ("rsa_sign q", sk.q); - log_mpidump ("rsa_sign u", sk.u); + log_printmpi ("rsa_sign d", sk.d); + log_printmpi ("rsa_sign p", sk.p); + log_printmpi ("rsa_sign q", sk.q); + log_printmpi ("rsa_sign u", sk.u); } } @@ -1088,7 +1130,7 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) sig = gcry_mpi_new (0); secret (sig, data, &sk); if (DBG_CIPHER) - log_mpidump ("rsa_sign sig", sig); + log_printmpi ("rsa_sign res", sig); if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN)) { /* We need to make sure to return the correct length to avoid @@ -1143,7 +1185,7 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) if (rc) goto leave; if (DBG_CIPHER) - log_mpidump ("rsa_verify data", data); + log_printmpi ("rsa_verify data", data); if (mpi_is_opaque (data)) { rc = GPG_ERR_INV_DATA; @@ -1158,7 +1200,7 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) if (rc) goto leave; if (DBG_CIPHER) - log_mpidump ("rsa_verify sig", sig); + log_printmpi ("rsa_verify sig", sig); /* Extract the key. */ rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL); @@ -1166,15 +1208,15 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) return rc; if (DBG_CIPHER) { - log_mpidump ("rsa_verify n", pk.n); - log_mpidump ("rsa_verify e", pk.e); + log_printmpi ("rsa_verify n", pk.n); + log_printmpi ("rsa_verify e", pk.e); } /* Do RSA computation and compare. */ result = gcry_mpi_new (0); public (result, sig, &pk); if (DBG_CIPHER) - log_mpidump ("rsa_verify cmp", result); + log_printmpi ("rsa_verify cmp", result); if (ctx.verify_cmp) rc = ctx.verify_cmp (&ctx, result); else @@ -1401,8 +1443,8 @@ selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) } /* Check that the ciphertext does no match the plaintext. */ - /* _gcry_log_mpidump ("plaintext", plaintext); */ - /* _gcry_log_mpidump ("ciphertxt", ciphertext); */ + /* _gcry_log_printmpi ("plaintext", plaintext); */ + /* _gcry_log_printmpi ("ciphertxt", ciphertext); */ if (!gcry_mpi_cmp (plaintext, ciphertext)) { errtxt = "ciphertext matches plaintext"; |