diff options
author | Werner Koch <wk@gnupg.org> | 2008-11-24 16:37:50 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2008-11-24 16:37:50 +0000 |
commit | 8cc2eb702eeed951907db225f25a1088db4e5c44 (patch) | |
tree | cb2d85993036d2a8c755a3729330a767f1e49c03 | |
parent | f73ff6ce957e65b40dd7a52e9d96744239eb4996 (diff) | |
download | libgcrypt-8cc2eb702eeed951907db225f25a1088db4e5c44.tar.gz |
Cleaned up the public key module calling conventions.
Add a way to derive RSA keys according to X9.31.
-rw-r--r-- | cipher/ChangeLog | 35 | ||||
-rw-r--r-- | cipher/dsa.c | 44 | ||||
-rw-r--r-- | cipher/ecc.c | 83 | ||||
-rw-r--r-- | cipher/elgamal.c | 124 | ||||
-rw-r--r-- | cipher/primegen.c | 141 | ||||
-rw-r--r-- | cipher/pubkey.c | 238 | ||||
-rw-r--r-- | cipher/rsa.c | 231 | ||||
-rw-r--r-- | doc/gcrypt.texi | 42 | ||||
-rw-r--r-- | src/ChangeLog | 8 | ||||
-rw-r--r-- | src/cipher-proto.h | 14 | ||||
-rw-r--r-- | src/cipher.h | 11 | ||||
-rw-r--r-- | src/g10lib.h | 4 | ||||
-rw-r--r-- | tests/ChangeLog | 4 | ||||
-rwxr-xr-x | tests/cavs_driver.pl | 10 | ||||
-rw-r--r-- | tests/fipsdrv.c | 6 | ||||
-rw-r--r-- | tests/pubkey.c | 234 |
16 files changed, 937 insertions, 292 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 91422ed1..b93ac023 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,38 @@ +2008-11-24 Werner Koch <wk@g10code.com> + + * pubkey.c (gcry_pk_genkey): Remove parsing of almost all + parameters and pass the parameter S-expression to pubkey_generate. + (pubkey_generate): Simplify by requitring modules to parse the + parameters. Remove the special cases for Elgamal and ECC. + (sexp_elements_extract_ecc): Add arg EXTRASPEC and use it. Fix + small memory leak. + (sexp_to_key): Pass EXTRASPEC to sexp_elements_extract_ecc. + (pubkey_table) [USE_ELGAMAL]: Add real extraspec. + * rsa.c (rsa_generate_ext): Adjust for new calling convention. + * dsa.c (dsa_generate_ext): Ditto. + * elgamal.c (_gcry_elg_generate): Ditto. Rename to elg_generate_ext. + (elg_generate): New. + (_gcry_elg_generate_using_x): Remove after merging code with + elg_generate_ext. + (_gcry_pubkey_extraspec_elg): New. + (_gcry_elg_check_secret_key, _gcry_elg_encrypt, _gcry_elg_sign) + (_gcry_elg_verify, _gcry_elg_get_nbits): Make static and remove + _gcry_ prefix. + * ecc.c (_gcry_ecc_generate): Rename to ecc_generate_ext and + adjust for new calling convention. + (_gcry_ecc_get_param): Rename to ecc_get_param and make static. + (_gcry_pubkey_extraspec_ecdsa): Add ecc_generate_ext and + ecc_get_param. + +2008-11-20 Werner Koch <wk@g10code.com> + + * pubkey.c (pubkey_generate): Add arg DERIVEPARMS. + (gcry_pk_genkey): Parse derive-parms and pass it to above. + * rsa.c (generate_x931): New. + (rsa_generate_ext): Add arg DERIVEPARMS and call new function in + fips mode or if DERIVEPARMS is given. + * primegen.c (_gcry_derive_x931_prime, find_x931_prime): New. + 2008-11-19 Werner Koch <wk@g10code.com> * rsa.c (rsa_decrypt): Use gcry_create_nonce for blinding. diff --git a/cipher/dsa.c b/cipher/dsa.c index fe210fa0..fb5654e8 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -459,20 +459,40 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) *********************************************/ static gcry_err_code_t -dsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits, - unsigned long use_e, - const char *name, const gcry_sexp_t domain, - unsigned int keygen_flags, +dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue, + const gcry_sexp_t genparms, gcry_mpi_t *skey, gcry_mpi_t **retfactors) { gpg_err_code_t ec; DSA_secret_key sk; + gcry_sexp_t l1; + unsigned int qbits = 0; - (void)algo; - (void)use_e; - (void)name; - (void)domain; - (void)keygen_flags; + (void)algo; /* No need to check it. */ + (void)evalue; /* Not required for DSA. */ + + /* Parse the optional qbits element. */ + if (genparms) + { + l1 = gcry_sexp_find_token (genparms, "qbits", 0); + if (l1) + { + char buf[50]; + const char *s; + size_t n; + + s = gcry_sexp_nth_data (l1, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + gcry_sexp_release (l1); + return GPG_ERR_INV_OBJ; /* No value or value too large. */ + } + memcpy (buf, s, n); + buf[n] = 0; + qbits = (unsigned int)strtoul (buf, NULL, 0); + gcry_sexp_release (l1); + } + } ec = generate (&sk, nbits, qbits, retfactors); if (!ec) @@ -489,11 +509,11 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits, static gcry_err_code_t -dsa_generate (int algo, unsigned int nbits, unsigned long dummy, +dsa_generate (int algo, unsigned int nbits, unsigned long evalue, gcry_mpi_t *skey, gcry_mpi_t **retfactors) { - (void)dummy; - return dsa_generate_ext (algo, nbits, 0, 0, NULL, NULL, 0, skey, retfactors); + (void)evalue; + return dsa_generate_ext (algo, nbits, 0, NULL, skey, retfactors); } diff --git a/cipher/ecc.c b/cipher/ecc.c index c90391f9..5df22b01 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -949,35 +949,47 @@ os2ec (mpi_point_t *result, gcry_mpi_t value) return 0; } -/* Extended version of ecc_generate which is called directly by - pubkey.c. If CURVE is not NULL, that name will be used to select - the domain parameters. NBITS is not used in this case. */ -gcry_err_code_t -_gcry_ecc_generate (int algo, unsigned int nbits, const char *curve, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) + +/* Extended version of ecc_generate. */ +static gcry_err_code_t +ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue, + const gcry_sexp_t genparms, + gcry_mpi_t *skey, gcry_mpi_t **retfactors) { - gpg_err_code_t err; + gpg_err_code_t ec; ECC_secret_key sk; gcry_mpi_t g_x, g_y, q_x, q_y; + char *curve_name = NULL; + gcry_sexp_t l1; (void)algo; + (void)evalue; - /* Make an empty list of factors. */ - *retfactors = gcry_calloc ( 1, sizeof **retfactors ); - if (!*retfactors) - return gpg_err_code_from_syserror (); + if (genparms) + { + /* Parse the optional "curve" parameter. */ + l1 = gcry_sexp_find_token (genparms, "curve", 0); + if (l1) + { + curve_name = _gcry_sexp_nth_string (l1, 1); + gcry_sexp_release (l1); + if (!curve_name) + return GPG_ERR_INV_OBJ; /* No curve name or value too large. */ + } + } + + /* NBITS is required if no curve name has been given. */ + if (!nbits && !curve_name) + return GPG_ERR_NO_OBJ; /* No NBITS parameter. */ g_x = mpi_new (0); g_y = mpi_new (0); q_x = mpi_new (0); q_y = mpi_new (0); - err = generate_key (&sk, nbits, curve, g_x, g_y, q_x, q_y); - if (err) - { - gcry_free (*retfactors); - *retfactors = NULL; - return err; - } + ec = generate_key (&sk, nbits, curve_name, g_x, g_y, q_x, q_y); + gcry_free (curve_name); + if (ec) + return ec; skey[0] = sk.E.p; skey[1] = sk.E.a; @@ -992,12 +1004,27 @@ _gcry_ecc_generate (int algo, unsigned int nbits, const char *curve, point_free (&sk.E.G); point_free (&sk.Q); + /* Make an empty list of factors. */ + *retfactors = gcry_calloc ( 1, sizeof **retfactors ); + if (!*retfactors) + return gpg_err_code_from_syserror (); + return 0; } + +static gcry_err_code_t +ecc_generate (int algo, unsigned int nbits, unsigned long evalue, + gcry_mpi_t *skey, gcry_mpi_t **retfactors) +{ + (void)evalue; + return ecc_generate_ext (algo, nbits, 0, NULL, skey, retfactors); +} + + /* Return the parameters of the curve NAME. */ -gcry_err_code_t -_gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey) +static gcry_err_code_t +ecc_get_param (const char *name, gcry_mpi_t *pkey) { gpg_err_code_t err; unsigned int nbits; @@ -1027,14 +1054,6 @@ _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey) return 0; } -static gcry_err_code_t -ecc_generate (int algo, unsigned int nbits, unsigned long dummy, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - (void)dummy; - return _gcry_ecc_generate (algo, nbits, NULL, skey, retfactors); -} - static gcry_err_code_t ecc_check_secret_key (int algo, gcry_mpi_t *skey) @@ -1230,7 +1249,7 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ goto leave; } - ec = _gcry_ecc_get_param (curve, tmpvalues); + ec = ecc_get_param (curve, tmpvalues); gcry_free (curve); if (ec) goto leave; @@ -1358,10 +1377,12 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecdsa = ecc_verify, ecc_get_nbits }; + pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa = { run_selftests, - NULL, - compute_keygrip + ecc_generate_ext, + compute_keygrip, + ecc_get_param }; diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 04ad6fa1..a3eaf2ae 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -1,10 +1,11 @@ /* Elgamal.c - Elgamal Public Key encryption - * Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 1998, 2000, 2001, 2002, 2003, + * 2008 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as + * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * @@ -14,8 +15,7 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * License along with this program; if not, see <http://www.gnu.org/licenses/>. * * For a description of the algorithm, see: * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. @@ -612,50 +612,70 @@ verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) ************** interface ****************** *********************************************/ -gcry_err_code_t -_gcry_elg_generate (int algo, unsigned int nbits, unsigned long dummy, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) +static gpg_err_code_t +elg_generate_ext (int algo, unsigned int nbits, unsigned long evalue, + const gcry_sexp_t genparms, + gcry_mpi_t *skey, gcry_mpi_t **retfactors) { + gpg_err_code_t ec; ELG_secret_key sk; + gcry_mpi_t xvalue = NULL; + gcry_sexp_t l1; (void)algo; - (void)dummy; + (void)evalue; + + if (genparms) + { + /* Parse the optional xvalue element. */ + l1 = gcry_sexp_find_token (genparms, "xvalue", 0); + if (l1) + { + xvalue = gcry_sexp_nth_mpi (l1, 1, 0); + gcry_sexp_release (l1); + if (!xvalue) + return GPG_ERR_BAD_MPI; + } + } + + if (xvalue) + ec = generate_using_x (&sk, nbits, xvalue, retfactors); + else + { + generate (&sk, nbits, retfactors); + ec = 0; + } - generate (&sk, nbits, retfactors); skey[0] = sk.p; skey[1] = sk.g; skey[2] = sk.y; skey[3] = sk.x; - return GPG_ERR_NO_ERROR; + return ec; } -/* This is a specila generate function which is not called via the - module interface. */ -gcry_err_code_t -_gcry_elg_generate_using_x (int algo, unsigned int nbits, gcry_mpi_t x, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) +static gcry_err_code_t +elg_generate (int algo, unsigned int nbits, unsigned long evalue, + gcry_mpi_t *skey, gcry_mpi_t **retfactors) { - gcry_err_code_t ec; ELG_secret_key sk; (void)algo; + (void)evalue; - ec = generate_using_x (&sk, nbits, x, retfactors); - if (!ec) - { - skey[0] = sk.p; - skey[1] = sk.g; - skey[2] = sk.y; - skey[3] = sk.x; - } - return ec; + generate (&sk, nbits, retfactors); + skey[0] = sk.p; + skey[1] = sk.g; + skey[2] = sk.y; + skey[3] = sk.x; + + return GPG_ERR_NO_ERROR; } -gcry_err_code_t -_gcry_elg_check_secret_key (int algo, gcry_mpi_t *skey) +static gcry_err_code_t +elg_check_secret_key (int algo, gcry_mpi_t *skey) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_secret_key sk; @@ -679,9 +699,9 @@ _gcry_elg_check_secret_key (int algo, gcry_mpi_t *skey) } -gcry_err_code_t -_gcry_elg_encrypt (int algo, gcry_mpi_t *resarr, - gcry_mpi_t data, gcry_mpi_t *pkey, int flags) +static gcry_err_code_t +elg_encrypt (int algo, gcry_mpi_t *resarr, + gcry_mpi_t data, gcry_mpi_t *pkey, int flags) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_public_key pk; @@ -704,9 +724,9 @@ _gcry_elg_encrypt (int algo, gcry_mpi_t *resarr, } -gcry_err_code_t -_gcry_elg_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, int flags) +static gcry_err_code_t +elg_decrypt (int algo, gcry_mpi_t *result, + gcry_mpi_t *data, gcry_mpi_t *skey, int flags) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_secret_key sk; @@ -730,8 +750,8 @@ _gcry_elg_decrypt (int algo, gcry_mpi_t *result, } -gcry_err_code_t -_gcry_elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) +static gcry_err_code_t +elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_secret_key sk; @@ -755,9 +775,10 @@ _gcry_elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) return err; } -gcry_err_code_t -_gcry_elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) + +static gcry_err_code_t +elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, + int (*cmp) (void *, gcry_mpi_t), void *opaquev) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_public_key pk; @@ -782,14 +803,15 @@ _gcry_elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, } -unsigned int -_gcry_elg_get_nbits (int algo, gcry_mpi_t *pkey) +static unsigned int +elg_get_nbits (int algo, gcry_mpi_t *pkey) { (void)algo; return mpi_get_nbits (pkey[0]); } + static const char *elg_names[] = { "elg", @@ -804,11 +826,19 @@ gcry_pk_spec_t _gcry_pubkey_spec_elg = "ELG", elg_names, "pgy", "pgyx", "ab", "rs", "pgy", GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR, - _gcry_elg_generate, - _gcry_elg_check_secret_key, - _gcry_elg_encrypt, - _gcry_elg_decrypt, - _gcry_elg_sign, - _gcry_elg_verify, - _gcry_elg_get_nbits, + elg_generate, + elg_check_secret_key, + elg_encrypt, + elg_decrypt, + elg_sign, + elg_verify, + elg_get_nbits }; + +pk_extra_spec_t _gcry_pubkey_extraspec_elg = + { + NULL, + elg_generate_ext, + NULL + }; + diff --git a/cipher/primegen.c b/cipher/primegen.c index 94348687..d523a89c 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -1,6 +1,6 @@ /* primegen.c - prime number generator * Copyright (C) 1998, 2000, 2001, 2002, 2003 - * 2004 Free Software Foundation, Inc. + * 2004, 2008 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * @@ -1272,3 +1272,142 @@ gcry_prime_release_factors (gcry_mpi_t *factors) gcry_free (factors); } } + + +/* Helper for _gcry_generate_x931_prime. */ +static gcry_mpi_t +find_x931_prime (const gcry_mpi_t pfirst) +{ + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t prime; + + prime = gcry_mpi_copy (pfirst); + /* If P is even add 1. */ + mpi_set_bit (prime, 0); + + /* We use 64 Rabin-Miller rounds which is better and thus + sufficient. We do not have a Lucas test implementaion thus we + can't do it in the X9.31 preferred way of running a few + Rabin-Miller followed by one Lucas test. */ + while ( !check_prime (prime, val_2, 64, NULL, NULL) ) + mpi_add_ui (prime, prime, 2); + + mpi_free (val_2); + + return prime; +} + + +/* Generate a prime using the algorithm from X9.31 appendix B.4. + + This function requires that the provided public exponent E is odd. + XP, XP1 and XP2 are the seed values. All values are mandatory. + + On success the prime is returned. If R_P1 or R_P2 are given the + internal values P1 and P2 are saved at these addresses. On error + NULL is returned. */ +gcry_mpi_t +_gcry_derive_x931_prime (const gcry_mpi_t xp, + const gcry_mpi_t xp1, const gcry_mpi_t xp2, + const gcry_mpi_t e, + gcry_mpi_t *r_p1, gcry_mpi_t *r_p2) +{ + gcry_mpi_t p1, p2, p1p2, yp0; + + if (!xp || !xp1 || !xp2) + return NULL; + if (!e || !mpi_test_bit (e, 0)) + return NULL; /* We support only odd values for E. */ + + p1 = find_x931_prime (xp1); + p2 = find_x931_prime (xp2); + p1p2 = mpi_alloc_like (xp); + mpi_mul (p1p2, p1, p2); + + { + gcry_mpi_t r1, tmp; + + /* r1 = (p2^{-1} mod p1)p2 - (p1^{-1} mod p2) */ + tmp = mpi_alloc_like (p1); + mpi_invm (tmp, p2, p1); + mpi_mul (tmp, tmp, p2); + r1 = tmp; + + tmp = mpi_alloc_like (p2); + mpi_invm (tmp, p1, p2); + mpi_mul (tmp, tmp, p1); + mpi_sub (r1, r1, tmp); + + /* Fixup a negative value. */ + if (mpi_is_neg (r1)) + mpi_add (r1, r1, p1p2); + + /* yp0 = xp + (r1 - xp mod p1*p2) */ + yp0 = tmp; tmp = NULL; + mpi_subm (yp0, r1, xp, p1p2); + mpi_add (yp0, yp0, xp); + mpi_free (r1); + + /* Fixup a negative value. */ + if (mpi_cmp (yp0, xp) < 0 ) + mpi_add (yp0, yp0, p1p2); + } + + /* yp0 is now the first integer greater than xp with p1 being a + large prime factor of yp0-1 and p2 a large prime factor of yp0+1. */ + + /* Note that the first example from X9.31 (D.1.1) which uses + (Xq1 #1A5CF72EE770DE50CB09ACCEA9#) + (Xq2 #134E4CAA16D2350A21D775C404#) + (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325 + 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34 + 321DE34A#)))) + returns an yp0 of + #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC4E3 + BF20CB896EE37E098A906313271422162CB6C642 + 75C1201F# + and not + #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC2E6 + C88FE299D52D78BE405A97E01FD71DD7819ECB91 + FA85A076# + as stated in the standard. This seems to be a bug in X9.31. + */ + + { + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t gcdtmp = mpi_alloc_like (yp0); + int gcdres; + + mpi_sub_ui (p1p2, p1p2, 1); /* Adjust for loop body. */ + mpi_sub_ui (yp0, yp0, 1); /* Ditto. */ + for (;;) + { + gcdres = gcry_mpi_gcd (gcdtmp, e, yp0); + mpi_add_ui (yp0, yp0, 1); + if (!gcdres) + progress ('/'); /* gcd (e, yp0-1) != 1 */ + else if (check_prime (yp0, val_2, 64, NULL, NULL)) + break; /* Found. */ + /* We add p1p2-1 because yp0 is incremented after the gcd test. */ + mpi_add (yp0, yp0, p1p2); + } + mpi_free (gcdtmp); + mpi_free (val_2); + } + + mpi_free (p1p2); + + progress('\n'); + if (r_p1) + *r_p1 = p1; + else + mpi_free (p1); + if (r_p2) + *r_p2 = p2; + else + mpi_free (p2); + return yp0; +} diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 1d7e1d09..6bc248c3 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -64,9 +64,9 @@ static struct pubkey_table_entry #endif #if USE_ELGAMAL { &_gcry_pubkey_spec_elg, - &dummy_extra_spec, GCRY_PK_ELG }, + &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG }, { &_gcry_pubkey_spec_elg, - &dummy_extra_spec, GCRY_PK_ELG_E }, + &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E }, #endif #if USE_DSA { &_gcry_pubkey_spec_dsa, @@ -530,17 +530,18 @@ pubkey_get_nenc (int algorithm) /* Generate a new public key with algorithm ALGORITHM of size NBITS - and return it at SKEY. The use of the arguments QBITS, USE_E, - XVALUE, CURVE_NAME and DOMAIN depend on the ALGORITHM. RETFACTOR - is used by some algorithms to return certain additional information - which are in general not required. + and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS + is passed to the algorithm module if it features an extended + generation function. RETFACTOR is used by some algorithms to + return certain additional information which are in general not + required. The function returns the error code number or 0 on success. */ static gcry_err_code_t -pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits, - unsigned long use_e, gcry_mpi_t xvalue, - const char *curve_name, gcry_sexp_t domain, - unsigned int keygen_flags, +pubkey_generate (int algorithm, + unsigned int nbits, + unsigned long use_e, + gcry_sexp_t genparms, gcry_mpi_t *skey, gcry_mpi_t **retfactors) { gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO; @@ -554,43 +555,11 @@ pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits, { pk_extra_spec_t *extraspec = pubkey->extraspec; - if (keygen_flags && (!extraspec || !extraspec->ext_generate)) + if (extraspec && extraspec->ext_generate) { - /* A keygen flag has been given but the module does not - provide an ext_generate function. We don't want to - ignore such a condition as it might eventually be - security sensitive.. */ - ec = GPG_ERR_INV_FLAG; - } -#ifdef USE_ELGAMAL - else if (xvalue && pubkey->spec == &_gcry_pubkey_spec_elg) - { - /* Fixme: Merge this into an ext_generate fucntion. */ - ec = _gcry_elg_generate_using_x - (algorithm, nbits, xvalue, skey, retfactors); - } -#endif /*USE_ELGAMAL*/ -#ifdef USE_ECC - else if (curve_name && pubkey->spec == &_gcry_pubkey_spec_ecdsa) - { - /* Fixme: Merge this into an ext_generate fucntion. */ - ec = _gcry_ecc_generate - (algorithm, nbits, curve_name, skey, retfactors); - } -#endif /*USE_ECC*/ - else if (extraspec && extraspec->ext_generate) - { - /* Use the extended generate function if available. */ - ec = extraspec->ext_generate (algorithm, nbits, qbits, use_e, - NULL, domain, keygen_flags, - skey, retfactors); - } - else if (qbits || domain) - { - /* A qbits or domain parameter is specified but the - algorithm does not feature an extended generation - function. */ - ec = GPG_ERR_INV_PARAMETER; + /* Use the extended generate function. */ + ec = extraspec->ext_generate + (algorithm, nbits, use_e, genparms, skey, retfactors); } else { @@ -605,6 +574,7 @@ pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits, return ec; } + static gcry_err_code_t pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey) { @@ -868,11 +838,13 @@ sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names, return err; } + /* Internal function used for ecc. Note, that this function makes use of its intimate knowledge about the ECC parameters from ecc.c. */ static gcry_err_code_t sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements) + gcry_mpi_t *elements, pk_extra_spec_t *extraspec) + { gcry_err_code_t err = 0; int idx; @@ -907,35 +879,41 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, list = gcry_sexp_find_token (key_sexp, "curve", 5); if (list) { -#if USE_ECC - char *curve; - gcry_mpi_t params[6]; - - for (idx = 0; idx < DIM(params); idx++) - params[idx] = NULL; - - curve = _gcry_sexp_nth_string (list, 1); - if (!curve) + if (extraspec->get_param) { - err = GPG_ERR_INV_OBJ; /* No curve name given (or out of core). */ - goto leave; + char *curve; + gcry_mpi_t params[6]; + + for (idx = 0; idx < DIM(params); idx++) + params[idx] = NULL; + + curve = _gcry_sexp_nth_string (list, 1); + gcry_sexp_release (list); + if (!curve) + { + /* No curve name given (or out of core). */ + err = GPG_ERR_INV_OBJ; + goto leave; + } + err = extraspec->get_param (curve, params); + gcry_free (curve); + if (err) + goto leave; + + for (idx = 0; idx < DIM(params); idx++) + { + if (!elements[idx]) + elements[idx] = params[idx]; + else + mpi_free (params[idx]); + } } - err = _gcry_ecc_get_param (curve, params); - gcry_free (curve); - if (err) - goto leave; - - for (idx = 0; idx < DIM(params); idx++) + else { - if (!elements[idx]) - elements[idx] = params[idx]; - else - mpi_free (params[idx]); + gcry_sexp_release (list); + err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */ + goto leave; } -#else /* !USE_ECC */ - err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */ - goto leave; -#endif /* !USE_ECC */ } /* Check that all parameters are known. */ @@ -1001,6 +979,7 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, gcry_mpi_t *array; gcry_module_t module; gcry_pk_spec_t *pubkey; + pk_extra_spec_t *extraspec; int is_ecc; /* Check that the first element is valid. */ @@ -1038,7 +1017,10 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ } else - pubkey = (gcry_pk_spec_t *) module->spec; + { + pubkey = (gcry_pk_spec_t *) module->spec; + extraspec = module->extraspec; + } elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey; array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); @@ -1047,7 +1029,7 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, if (!err) { if (is_ecc) - err = sexp_elements_extract_ecc (list, elems, array); + err = sexp_elements_extract_ecc (list, elems, array, extraspec); else err = sexp_elements_extract (list, elems, array, pubkey->name); } @@ -2084,7 +2066,9 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) { gcry_pk_spec_t *pubkey = NULL; gcry_module_t module = NULL; - gcry_sexp_t list = NULL, l2 = NULL; + gcry_sexp_t list = NULL; + gcry_sexp_t l2 = NULL; + gcry_sexp_t l3 = NULL; char *name = NULL; size_t n; gcry_err_code_t rc = GPG_ERR_NO_ERROR; @@ -2095,10 +2079,6 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) gcry_mpi_t skey[12], *factors = NULL; unsigned int nbits = 0; unsigned long use_e = 0; - unsigned int qbits; - gcry_mpi_t xvalue = NULL; - char *curve = NULL; - unsigned int keygen_flags = 0; skey[0] = NULL; *r_key = NULL; @@ -2150,7 +2130,9 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) if (strlen (sec_elems) >= DIM(skey)) BUG (); - /* Handle the optional rsa-use-e element. */ + /* Handle the optional rsa-use-e element. Actually this belong into + the algorithm module but we have this parameter in the public + moudle API, so we need to parse it right here. */ l2 = gcry_sexp_find_token (list, "rsa-use-e", 0); if (l2) { @@ -2172,81 +2154,15 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) else use_e = 65537; /* Not given, use the value generated by old versions. */ - /* Handle the optional qbits element. */ - l2 = gcry_sexp_find_token (list, "qbits", 0); - if (l2) - { - char buf[50]; - const char *s; - s = gcry_sexp_nth_data (l2, 1, &n); - if (!s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* No value or value too large. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - qbits = (unsigned int)strtoul (buf, NULL, 0); - gcry_sexp_release (l2); - l2 = NULL; - } - else - qbits = 0; - - /* Parse the optional xvalue element. */ - l2 = gcry_sexp_find_token (list, "xvalue", 0); - if (l2) - { - xvalue = gcry_sexp_nth_mpi (l2, 1, 0); - if (!xvalue) - { - rc = GPG_ERR_BAD_MPI; - goto leave; - } - } - - /* Parse the optional "curve" parameter. */ - l2 = gcry_sexp_find_token (list, "curve", 0); - if (l2) - { - curve = _gcry_sexp_nth_string (l2, 1); - if (!curve) - { - rc = GPG_ERR_INV_OBJ; /* No curve name or value too large. */ - goto leave; - } - gcry_sexp_release (l2); - l2 = NULL; - } - - /* Parse the optional "transient-key" flag. */ - l2 = gcry_sexp_find_token (list, "transient-key", 0); - if (l2) - { - keygen_flags |= PUBKEY_FLAG_TRANSIENT_KEY; - gcry_sexp_release (l2); - l2 = NULL; - } - - - /* Unless a curve name has been given, the "nbits" parameter is - required. */ + /* Get the "nbits" parameter. */ l2 = gcry_sexp_find_token (list, "nbits", 0); - gcry_sexp_release (list); - list = l2; - l2 = NULL; - if (!list && !curve) - { - rc = GPG_ERR_NO_OBJ; /* No nbits parameter. */ - goto leave; - } - if (list) + if (l2) { char buf[50]; const char *s; - s = gcry_sexp_nth_data (list, 1, &n); + s = gcry_sexp_nth_data (l2, 1, &n); if (!s || n >= DIM (buf) - 1 ) { rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */ @@ -2255,18 +2171,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) memcpy (buf, s, n); buf[n] = 0; nbits = (unsigned int)strtoul (buf, NULL, 0); + gcry_sexp_release (l2); l2 = NULL; } else nbits = 0; - /* Extract the optional domain parameter and call the key generation. */ - l2 = gcry_sexp_find_token (list, "domain", 0); - rc = pubkey_generate (module->mod_id, nbits, qbits, use_e, xvalue, - curve, l2, keygen_flags, skey, &factors); - gcry_sexp_release (l2); + /* Pass control to the algorithm module. */ + rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey, &factors); + gcry_sexp_release (list); list = NULL; if (rc) goto leave; + /* Key generation succeeded: Build an S-expression. */ { char *string, *p; size_t nelem=0, nelem_cp = 0, needed=0; @@ -2312,7 +2228,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) } p = stpcpy (p, "))"); - /* Very ugly hack to make release_mpi_array() work FIXME */ + /* Hack to make release_mpi_array() work. */ skey[i] = NULL; if (factors[0]) @@ -2359,22 +2275,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) leave: gcry_free (name); - gcry_free (curve); release_mpi_array (skey); - /* Don't free SKEY itself, it is a static array. */ + /* Don't free SKEY itself, it is an stack allocated array. */ - gcry_mpi_release (xvalue); - if (factors) { release_mpi_array ( factors ); gcry_free (factors); } - if (l2) - gcry_sexp_release (l2); - if (list) - gcry_sexp_release (list); + gcry_sexp_release (l3); + gcry_sexp_release (l2); + gcry_sexp_release (list); if (module) { diff --git a/cipher/rsa.c b/cipher/rsa.c index f18feba1..8823af7e 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -207,8 +207,8 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, if ( (nbits&1) ) nbits++; - if (use_e == 1) /* Alias for a secure value. */ - use_e = 65537; /* as demanded by Spinx. */ + if (use_e == 1) /* Alias for a secure value */ + use_e = 65537; /* as demanded by Sphinx. */ /* Public exponent: In general we use 41 as this is quite fast and more secure than the @@ -328,6 +328,191 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, } +/* Variant of the standard key generation code using the algorithm + from X9.31. Using this algorithm has the advantage that the + generation can be made deterministic which is required for CAVS + testing. */ +static gpg_err_code_t +generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, + gcry_sexp_t deriveparms, int *swapped) +{ + gcry_mpi_t p, q; /* The two primes. */ + gcry_mpi_t e; /* The public exponent. */ + gcry_mpi_t n; /* The public key. */ + gcry_mpi_t d; /* The private key */ + gcry_mpi_t u; /* The inverse of p and q. */ + gcry_mpi_t pm1; /* p - 1 */ + gcry_mpi_t qm1; /* q - 1 */ + gcry_mpi_t phi; /* Euler totient. */ + gcry_mpi_t f, g; /* Helper. */ + + *swapped = 0; + + if (e_value == 1) /* Alias for a secure value. */ + e_value = 65537; + + /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */ + if (nbits < 1024 || (nbits % 256)) + return GPG_ERR_INV_VALUE; + + /* Point 2: 2 <= bitlength(e) < 2^{k-2} + Note that we do not need to check the upper bound because we use + an unsigned long for E and thus there is no way for E to reach + that limit. */ + if (e_value < 3) + return GPG_ERR_INV_VALUE; + + /* Our implementaion requires E to be odd. */ + if (!(e_value & 1)) + return GPG_ERR_INV_VALUE; + + /* Point 3: e > 0 or e 0 if it is to be randomly generated. + We support only a fixed E and thus there is no need for an extra test. */ + + + /* Compute or extract the derive parameters. */ + { + gcry_mpi_t xp1 = NULL; + gcry_mpi_t xp2 = NULL; + gcry_mpi_t xp = NULL; + gcry_mpi_t xq1 = NULL; + gcry_mpi_t xq2 = NULL; + gcry_mpi_t xq = NULL; + + if (!deriveparms) + { + /* Fixme: Create them. */ + return GPG_ERR_INV_VALUE; + } + else + { + struct { const char *name; gcry_mpi_t *value; } tbl[] = { + { "Xp1", &xp1 }, + { "Xp2", &xp2 }, + { "Xp", &xp }, + { "Xq1", &xq1 }, + { "Xq2", &xq2 }, + { "Xq", &xq }, + { NULL, NULL } + }; + int idx; + gcry_sexp_t oneparm; + + for (idx=0; tbl[idx].name; idx++) + { + oneparm = gcry_sexp_find_token (deriveparms, tbl[idx].name, 0); + if (oneparm) + { + *tbl[idx].value = gcry_sexp_nth_mpi (oneparm, 1, + GCRYMPI_FMT_USG); + gcry_sexp_release (oneparm); + } + } + for (idx=0; tbl[idx].name; idx++) + if (!*tbl[idx].value) + break; + if (tbl[idx].name) + { + /* At least one parameter is missing. */ + for (idx=0; tbl[idx].name; idx++) + gcry_mpi_release (*tbl[idx].value); + return GPG_ERR_MISSING_VALUE; + } + } + + e = mpi_alloc_set_ui (e_value); + + /* Find two prime numbers. */ + p = _gcry_derive_x931_prime (xp, xp1, xp2, e, NULL, NULL); + q = _gcry_derive_x931_prime (xq, xq1, xq2, e, NULL, NULL); + gcry_mpi_release (xp); xp = NULL; + gcry_mpi_release (xp1); xp1 = NULL; + gcry_mpi_release (xp2); xp2 = NULL; + gcry_mpi_release (xq); xq = NULL; + gcry_mpi_release (xq1); xq1 = NULL; + gcry_mpi_release (xq2); xq2 = NULL; + if (!p || !q) + { + gcry_mpi_release (p); + gcry_mpi_release (q); + gcry_mpi_release (e); + return GPG_ERR_NO_PRIME; + } + } + + + /* Compute the public modulus. We make sure that p is smaller than + q to allow the use of the CRT. */ + if (mpi_cmp (p, q) > 0 ) + { + mpi_swap (p, q); + *swapped = 1; + } + n = gcry_mpi_new (nbits); + mpi_mul (n, p, q); + + /* Compute the Euler totient: phi = (p-1)(q-1) */ + pm1 = gcry_mpi_snew (nbits/2); + qm1 = gcry_mpi_snew (nbits/2); + phi = gcry_mpi_snew (nbits); + mpi_sub_ui (pm1, p, 1); + mpi_sub_ui (qm1, q, 1); + mpi_mul (phi, pm1, qm1); + + g = gcry_mpi_snew (nbits); + gcry_assert (gcry_mpi_gcd (g, e, phi)); + + /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */ + gcry_mpi_gcd (g, pm1, qm1); + f = pm1; pm1 = NULL; + gcry_mpi_release (qm1); qm1 = NULL; + mpi_fdiv_q (f, phi, g); + gcry_mpi_release (phi); phi = NULL; + d = g; g = NULL; + /* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */ + mpi_invm (d, e, f); + + /* Compute the inverse of p and q. */ + u = f; f = NULL; + mpi_invm (u, p, q ); + + if( DBG_CIPHER ) + { + if (swapped) + log_debug ("p and q are swapped\n"); + log_mpidump(" p", p ); + log_mpidump(" q", q ); + log_mpidump(" n", n ); + log_mpidump(" e", e ); + log_mpidump(" d", d ); + log_mpidump(" u", u ); + } + + + sk->n = n; + sk->e = e; + sk->p = p; + sk->q = q; + sk->d = d; + sk->u = u; + + /* Now we can test our keys. */ + if (test_keys (sk, nbits - 64)) + { + gcry_mpi_release (sk->n); sk->n = NULL; + gcry_mpi_release (sk->e); sk->e = NULL; + gcry_mpi_release (sk->p); sk->p = NULL; + gcry_mpi_release (sk->q); sk->q = NULL; + gcry_mpi_release (sk->d); sk->d = NULL; + gcry_mpi_release (sk->u); sk->u = NULL; + fips_signal_error ("self-test after key generation failed"); + return GPG_ERR_SELFTEST_FAILED; + } + + return 0; +} + + /**************** * Test wether the secret key is valid. * Returns: true if this is a valid key. @@ -530,23 +715,42 @@ rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n) *********************************************/ static gcry_err_code_t -rsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits, - unsigned long use_e, - const char *name, const gcry_sexp_t domain, - unsigned int keygen_flags, +rsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue, + const gcry_sexp_t genparms, gcry_mpi_t *skey, gcry_mpi_t **retfactors) { RSA_secret_key sk; gpg_err_code_t ec; + gcry_sexp_t deriveparms; + int transient_key = 0; + gcry_sexp_t l1; + int swapped; int i; (void)algo; - (void)qbits; - (void)name; - (void)domain; - ec = generate_std (&sk, nbits, use_e, - !!(keygen_flags & PUBKEY_FLAG_TRANSIENT_KEY) ); + deriveparms = (genparms? + gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL); + + if (deriveparms || fips_mode ()) + { + ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); + gcry_sexp_release (deriveparms); + } + else + { + /* Parse the optional "transient-key" flag. */ + l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + transient_key = 1; + gcry_sexp_release (l1); + l1 = NULL; + } + /* Generate. */ + ec = generate_std (&sk, nbits, evalue, transient_key); + } + if (!ec) { skey[0] = sk.n; @@ -576,11 +780,10 @@ rsa_generate_ext (int algo, unsigned int nbits, unsigned int qbits, static gcry_err_code_t -rsa_generate (int algo, unsigned int nbits, unsigned long use_e, +rsa_generate (int algo, unsigned int nbits, unsigned long evalue, gcry_mpi_t *skey, gcry_mpi_t **retfactors) { - return rsa_generate_ext (algo, nbits, 0, use_e, NULL, NULL, 0, - skey, retfactors); + return rsa_generate_ext (algo, nbits, evalue, NULL, skey, retfactors); } diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 87fb9cec..e8d85b87 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -2725,6 +2725,33 @@ currently only implemented for DSA using this format: The @code{seed}, @code{counter} and @code{h} domain parameters are optional and currently not used. +@item derive-parms +This is currently only meaningful for RSA keys. If given, it is used +to derive the RSA keys using the given parameters. This is in general +only useful for key generation tests. If given for an RSA key the +X9.31 key generation algorithm is used even if libgcrypt is not in +FIPS mode. + +@example +(genkey + (rsa + (nbits 4:1024) + (rsa-use-e 1:3) + (derive-parms + (Xp1 #1A1916DDB29B4EB7EB6732E128#) + (Xp2 #192E8AAC41C576C822D93EA433#) + (Xp #D8CD81F035EC57EFE822955149D3BFF70C53520D + 769D6D76646C7A792E16EBD89FE6FC5B605A6493 + 39DFC925A86A4C6D150B71B9EEA02D68885F5009 + B98BD984#) + (Xq1 #1A5CF72EE770DE50CB09ACCEA9#) + (Xq2 #134E4CAA16D2350A21D775C404#) + (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325 + 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34 + 321DE34A#)))) +@end example + @end table @c end table of parameters @@ -2750,16 +2777,17 @@ As an example, here is what the Elgamal key generation returns: (y @var{y-mpi}) (x @var{x-mpi}))) (misc-key-info - (pm1-factors @var{n1 n2 ... nn}))) + (pm1-factors @var{n1 n2 ... nn})) @end example @noindent -As you can see, some of the information is duplicated, but this provides -an easy way to extract either the public or the private key. Note that -the order of the elements is not defined, e.g. the private key may be -stored before the public key. @var{n1 n2 ... nn} is a list of prime -numbers used to composite @var{p-mpi}; this is in general not a very -useful information. +As you can see, some of the information is duplicated, but this +provides an easy way to extract either the public or the private key. +Note that the order of the elements is not defined, e.g. the private +key may be stored before the public key. @var{n1 n2 ... nn} is a list +of prime numbers used to composite @var{p-mpi}; this is in general not +a very useful information and only available if the key generation +algorithm provides them. @end deftypefun @c end gcry_pk_genkey diff --git a/src/ChangeLog b/src/ChangeLog index c255fda2..d503dd35 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2008-11-24 Werner Koch <wk@g10code.com> + + * cipher-proto.h (pk_ext_generate_t): Simplify. + (pk_get_param): New. + (pk_extra_spec_t): Add field GET_PARAM. + * cipher.h (PUBKEY_FLAG_TRANSIENT_KEY): Remove. + (_gcry_pubkey_extraspec_elg): New. + 2008-11-05 Werner Koch <wk@g10code.com> * cipher.h (CIPHER_INFO_NO_WEAK_KEY): New. diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 975a2a11..31bf6ba3 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -43,18 +43,19 @@ typedef gpg_err_code_t (*selftest_func_t) typedef gcry_err_code_t (*pk_ext_generate_t) (int algo, unsigned int nbits, - unsigned int qbits, - unsigned long use_e, - const char *name, - gcry_sexp_t domain, - unsigned int keygen_flags, + unsigned long evalue, + gcry_sexp_t genparms, gcry_mpi_t *skey, gcry_mpi_t **retfactors); -/* The type is used to compute the keygrip. */ +/* The type used to compute the keygrip. */ typedef gpg_err_code_t (*pk_comp_keygrip_t) (gcry_md_hd_t md, gcry_sexp_t keyparm); +/* The type used to quert ECC curve parameters. */ +typedef gcry_err_code_t (*pk_get_param_t) + (const char *name, gcry_mpi_t *pkey); + /* The type used to convey additional information to a cipher. */ typedef gpg_err_code_t (*cipher_set_extra_info_t) (void *c, int what, const void *buffer, size_t buflen); @@ -79,6 +80,7 @@ typedef struct pk_extra_spec selftest_func_t selftest; pk_ext_generate_t ext_generate; pk_comp_keygrip_t comp_keygrip; + pk_get_param_t get_param; } pk_extra_spec_t; diff --git a/src/cipher.h b/src/cipher.h index f84d9ad7..62ca745a 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -27,7 +27,6 @@ #include "../random/random.h" #define PUBKEY_FLAG_NO_BLINDING (1 << 0) -#define PUBKEY_FLAG_TRANSIENT_KEY (1 << 1) #define CIPHER_INFO_NO_WEAK_KEY 1 @@ -62,18 +61,11 @@ void _gcry_register_pk_dsa_progress (gcry_handler_progress_t cbc, void *cb_data) /*-- elgamal.c --*/ void _gcry_register_pk_elg_progress (gcry_handler_progress_t cb, void *cb_data); -gcry_err_code_t _gcry_elg_generate_using_x (int algo, unsigned int nbits, - gcry_mpi_t x, - gcry_mpi_t *skey, - gcry_mpi_t **retfactors); + /*-- ecc.c --*/ void _gcry_register_pk_ecc_progress (gcry_handler_progress_t cbc, void *cb_data); -gcry_err_code_t _gcry_ecc_generate (int algo, unsigned int nbits, - const char *curve, - gcry_mpi_t *skey, gcry_mpi_t **retfactors); -gcry_err_code_t _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey); /*-- primegen.c --*/ @@ -138,6 +130,7 @@ extern gcry_pk_spec_t _gcry_pubkey_spec_ecdsa; extern pk_extra_spec_t _gcry_pubkey_extraspec_rsa; extern pk_extra_spec_t _gcry_pubkey_extraspec_dsa; +extern pk_extra_spec_t _gcry_pubkey_extraspec_elg; extern pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa; diff --git a/src/g10lib.h b/src/g10lib.h index 22f9acff..f7ea7816 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -175,6 +175,10 @@ gcry_mpi_t _gcry_generate_public_prime (unsigned int nbits, gcry_mpi_t _gcry_generate_elg_prime (int mode, unsigned int pbits, unsigned int qbits, gcry_mpi_t g, gcry_mpi_t **factors); +gcry_mpi_t _gcry_derive_x931_prime (const gcry_mpi_t xp, + const gcry_mpi_t xp1, const gcry_mpi_t xp2, + const gcry_mpi_t e, + gcry_mpi_t *r_p1, gcry_mpi_t *r_p2); /* replacements of missing functions (missing-string.c)*/ diff --git a/tests/ChangeLog b/tests/ChangeLog index 74a21a04..9867c278 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2008-11-24 Werner Koch <wk@g10code.com> + + * pubkey.c (check_x931_derived_key): New. + 2008-11-07 Werner Koch <wk@g10code.com> * fipsdrv.c (run_cipher_mct_loop, get_current_iv): New. diff --git a/tests/cavs_driver.pl b/tests/cavs_driver.pl index b6542fd7..8b4079ce 100755 --- a/tests/cavs_driver.pl +++ b/tests/cavs_driver.pl @@ -1035,6 +1035,7 @@ sub crypto_mct($$$$$$$$) { my $old_calc_data; my $old_old_calc_data; my $ov; + my $iv_arg; $out .= "COUNT = $i\n"; if (defined($key2)) { @@ -1059,10 +1060,15 @@ sub crypto_mct($$$$$$$$) { $out .= "CIPHERTEXT = ". bin2hex($source_data). "\n"; } + # Need to provide a dummy IV in case of ECB mode. + $iv_arg = (defined($iv) && $iv ne "") + ? bin2hex($iv) + : "00"x(length($source_data)); + print $CI "1\n" .$iloop."\n" .bin2hex($key1)."\n" - .bin2hex($iv)."\n" + .$iv_arg."\n" .bin2hex($source_data)."\n\n" or die; # fixme: We should skip over empty lines here. @@ -1130,7 +1136,7 @@ sub crypto_mct($$$$$$$$) { } if ($ciph =~ /des/) { - $iv = $ov; + $iv = $ov if (defined($iv) && $iv ne ""); if ($cipher =~ /des-ede3-ofb/) { $source_data = $source_data ^ $next_source; } else { diff --git a/tests/fipsdrv.c b/tests/fipsdrv.c index 9d3d5ba9..e27b84c1 100644 --- a/tests/fipsdrv.c +++ b/tests/fipsdrv.c @@ -240,6 +240,8 @@ read_textline (FILE *fp) any = 1; } while (*line == '#'); /* Always skip comment lines. */ + if (verbose > 1) + fprintf (stderr, PGM ": received line: %s\n", line); return gcry_xstrdup (line); } @@ -800,6 +802,8 @@ print_buffer (const void *buffer, size_t length) { const unsigned char *p = buffer; + if (verbose > 1) + showhex ("sent line", buffer, length); while (length-- && !ferror (stdout) ) printf ("%02X", *p++); if (ferror (stdout)) @@ -1099,6 +1103,8 @@ run_cipher_mct_loop (int encrypt_mode, int cipher_algo, int cipher_mode, putchar ('\n'); print_buffer (input, blocklen); /* Next input text. */ putchar ('\n'); + if (verbose > 1) + showhex ("sent line", "", 0); putchar ('\n'); fflush (stdout); diff --git a/tests/pubkey.c b/tests/pubkey.c index f3e65158..d5b0a7ce 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -114,6 +114,23 @@ die (const char *format, ...) } static void +show_sexp (const char *prefix, gcry_sexp_t a) +{ + char *buf; + size_t size; + + if (prefix) + fputs (prefix, stderr); + size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); + buf = gcry_xmalloc (size); + + gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); + fprintf (stderr, "%.*s", (int)size, buf); + gcry_free (buf); +} + + +static void check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey, gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code) { @@ -296,6 +313,7 @@ get_elg_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int fixed_x) *skey = sec_key; } + static void check_run (void) { @@ -342,6 +360,219 @@ check_run (void) } + +static gcry_mpi_t +key_param_from_sexp (gcry_sexp_t sexp, const char *topname, const char *name) +{ + gcry_sexp_t l1, l2; + gcry_mpi_t result; + + l1 = gcry_sexp_find_token (sexp, topname, 0); + if (!l1) + return NULL; + + l2 = gcry_sexp_find_token (l1, name, 0); + if (!l2) + { + gcry_sexp_release (l1); + return NULL; + } + result = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + gcry_sexp_release (l1); + return result; +} + + +static void +check_x931_derived_key (int what) +{ + static struct { + const char *param; + const char *expected_d; + } testtable[] = { + { /* First example from X9.31 (D.1.1). */ + "(genkey\n" + " (rsa\n" + " (nbits 4:1024)\n" + " (rsa-use-e 1:3)\n" + " (derive-parms\n" + " (Xp1 #1A1916DDB29B4EB7EB6732E128#)\n" + " (Xp2 #192E8AAC41C576C822D93EA433#)\n" + " (Xp #D8CD81F035EC57EFE822955149D3BFF70C53520D\n" + " 769D6D76646C7A792E16EBD89FE6FC5B605A6493\n" + " 39DFC925A86A4C6D150B71B9EEA02D68885F5009\n" + " B98BD984#)\n" + " (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)\n" + " (Xq2 #134E4CAA16D2350A21D775C404#)\n" + " (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D\n" + " 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325\n" + " 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34\n" + " 321DE34A#))))\n", + "1CCDA20BCFFB8D517EE9666866621B11822C7950D55F4BB5BEE37989A7D173" + "12E326718BE0D79546EAAE87A56623B919B1715FFBD7F16028FC4007741961" + "C88C5D7B4DAAAC8D36A98C9EFBB26C8A4A0E6BC15B358E528A1AC9D0F042BE" + "B93BCA16B541B33F80C933A3B769285C462ED5677BFE89DF07BED5C127FD13" + "241D3C4B" + }, + + { /* Second example from X9.31 (D.2.1). */ + "(genkey\n" + " (rsa\n" + " (nbits 4:1536)\n" + " (rsa-use-e 1:3)\n" + " (derive-parms\n" + " (Xp1 #18272558B61316348297EACA74#)\n" + " (Xp2 #1E970E8C6C97CEF91F05B0FA80#)\n" + " (Xp #F7E943C7EF2169E930DCF23FE389EF7507EE8265\n" + " 0D42F4A0D3A3CEFABE367999BB30EE680B2FE064\n" + " 60F707F46005F8AA7CBFCDDC4814BBE7F0F8BC09\n" + " 318C8E51A48D134296E40D0BBDD282DCCBDDEE1D\n" + " EC86F0B1C96EAFF5CDA70F9AEB6EE31E#)\n" + " (Xq1 #11FDDA6E8128DC1629F75192BA#)\n" + " (Xq2 #18AB178ECA907D72472F65E480#)\n" + " (Xq #C47560011412D6E13E3E7D007B5C05DBF5FF0D0F\n" + " CFF1FA2070D16C7ABA93EDFB35D8700567E5913D\n" + " B734E3FBD15862EBC59FA0425DFA131E549136E8\n" + " E52397A8ABE4705EC4877D4F82C4AAC651B33DA6\n" + " EA14B9D5F2A263DC65626E4D6CEAC767#))))\n", + "1FB56069985F18C4519694FB71055721A01F14422DC901C35B03A64D4A5BD1" + "259D573305F5B056AC931B82EDB084E39A0FD1D1A86CC5B147A264F7EF4EB2" + "0ED1E7FAAE5CAE4C30D5328B7F74C3CAA72C88B70DED8EDE207B8629DA2383" + "B78C3CE1CA3F9F218D78C938B35763AF2A8714664CC57F5CECE2413841F5E9" + "EDEC43B728E25A41BF3E1EF8D9EEE163286C9F8BF0F219D3B322C3E4B0389C" + "2E8BB28DC04C47DA2BF38823731266D2CF6CC3FC181738157624EF051874D0" + "BBCCB9F65C83" + /* Note that this example in X9.31 gives this value for D: + + "7ED581A6617C6311465A53EDC4155C86807C5108B724070D6C0E9935296F44" + "96755CCC17D6C15AB24C6E0BB6C2138E683F4746A1B316C51E8993DFBD3AC8" + "3B479FEAB972B930C354CA2DFDD30F2A9CB222DC37B63B7881EE18A7688E0E" + "DE30F38728FE7C8635E324E2CD5D8EBCAA1C51993315FD73B38904E107D7A7" + "B7B10EDCA3896906FCF87BE367BB858CA1B27E2FC3C8674ECC8B0F92C0E270" + "BA2ECA3701311F68AFCE208DCC499B4B3DB30FF0605CE055D893BC1461D342" + "EF32E7D9720B" + + This is a bug in X9.31, obviously introduced by using + + d = e^{-1} mod (p-1)(q-1) + + instead of using the universal exponent as required by 4.1.3: + + d = e^{-1} mod lcm(p-1,q-1) + + The examples in X9.31 seem to be pretty buggy, see + cipher/primegen.c for another bug. Not only that I had to + spend 100 USD for the 66 pages of the document, it also took + me several hours to figure out that the bugs are in the + document and not in my code. + */ + }, + + { /* First example from NIST RSAVS (B.1.1). */ + "(genkey\n" + " (rsa\n" + " (nbits 4:1024)\n" + " (rsa-use-e 1:3)\n" + " (derive-parms\n" + " (Xp1 #1ed3d6368e101dab9124c92ac8#)\n" + " (Xp2 #16e5457b8844967ce83cab8c11#)\n" + " (Xp #b79f2c2493b4b76f329903d7555b7f5f06aaa5ea\n" + " ab262da1dcda8194720672a4e02229a0c71f60ae\n" + " c4f0d2ed8d49ef583ca7d5eeea907c10801c302a\n" + " cab44595#)\n" + " (Xq1 #1a5d9e3fa34fb479bedea412f6#)\n" + " (Xq2 #1f9cca85f185341516d92e82fd#)\n" + " (Xq #c8387fd38fa33ddcea6a9de1b2d55410663502db\n" + " c225655a9310cceac9f4cf1bce653ec916d45788\n" + " f8113c46bc0fa42bf5e8d0c41120c1612e2ea8bb\n" + " 2f389eda#))))\n", + "17ef7ad4fd96011b62d76dfb2261b4b3270ca8e07bc501be954f8719ef586b" + "f237e8f693dd16c23e7adecc40279dc6877c62ab541df5849883a5254fccfd" + "4072a657b7f4663953930346febd6bbd82f9a499038402cbf97fd5f068083a" + "c81ad0335c4aab0da19cfebe060a1bac7482738efafea078e21df785e56ea0" + "dc7e8feb" + }, + + { /* Second example from NIST RSAVS (B.1.1). */ + "(genkey\n" + " (rsa\n" + " (nbits 4:1536)\n" + " (rsa-use-e 1:3)\n" + " (derive-parms\n" + " (Xp1 #1e64c1af460dff8842c22b64d0#)\n" + " (Xp2 #1e948edcedba84039c81f2ac0c#)\n" + " (Xp #c8c67df894c882045ede26a9008ab09ea0672077\n" + " d7bc71d412511cd93981ddde8f91b967da404056\n" + " c39f105f7f239abdaff92923859920f6299e82b9\n" + " 5bd5b8c959948f4a034d81613d6235a3953b49ce\n" + " 26974eb7bb1f14843841281b363b9cdb#)\n" + " (Xq1 #1f3df0f017ddd05611a97b6adb#)\n" + " (Xq2 #143edd7b22d828913abf24ca4d#)\n" + " (Xq #f15147d0e7c04a1e3f37adde802cdc610999bf7a\n" + " b0088434aaeda0c0ab3910b14d2ce56cb66bffd9\n" + " 7552195fae8b061077e03920814d8b9cfb5a3958\n" + " b3a82c2a7fc97e55db543948d3396289245336ec\n" + " 9e3cb308cc655aebd766340da8921383#))))\n", + "1f8b19f3f5f2ac9fc599f110cad403dcd9bdf5f7f00fb2790e78e820398184" + "1f3fb3dd230fb223d898f45719d9b2d3525587ff2b8bcc7425e40550a5b536" + "1c8e9c1d26e83fbd9c33c64029c0e878b829d55def12912b73d94fd758c461" + "0f473e230c41b5e4c86e27c5a5029d82c811c88525d0269b95bd2ff272994a" + "dbd80f2c2ecf69065feb8abd8b445b9c6d306b1585d7d3d7576d49842bc7e2" + "8b4a2f88f4a47e71c3edd35fdf83f547ea5c2b532975c551ed5268f748b2c4" + "2ccf8a84835b" + } + }; + gpg_error_t err; + gcry_sexp_t key_spec, key, pub_key, sec_key; + gcry_mpi_t d_expected, d_have; + + if (what < 0 && what >= sizeof testtable) + die ("invalid WHAT value\n"); + + err = gcry_sexp_new (&key_spec, testtable[what].param, 0, 1); + if (err) + die ("error creating S-expression [%d]: %s\n", what, gpg_strerror (err)); + + err = gcry_pk_genkey (&key, key_spec); + gcry_sexp_release (key_spec); + if (err) + die ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err)); + + pub_key = gcry_sexp_find_token (key, "public-key", 0); + if (!pub_key) + die ("public part missing in key [%d]\n", what); + + sec_key = gcry_sexp_find_token (key, "private-key", 0); + if (!sec_key) + die ("private part missing in key [%d]\n", what); + + err = gcry_mpi_scan + (&d_expected, GCRYMPI_FMT_HEX, testtable[what].expected_d, 0, NULL); + if (err) + die ("error converting string [%d]\n", what); + + if (verbose) + show_sexp ("generated private key:\n", sec_key); + d_have = key_param_from_sexp (sec_key, "rsa", "d"); + if (!d_have) + die ("parameter d not found in RSA secret key [%d]\n", what); + if (gcry_mpi_cmp (d_expected, d_have)) + { + show_sexp (NULL, sec_key); + die ("parameter d does match expected value [%d]\n", what); + } + gcry_mpi_release (d_expected); + gcry_mpi_release (d_have); + + gcry_sexp_release (key); + gcry_sexp_release (pub_key); + gcry_sexp_release (sec_key); +} + + + + int main (int argc, char **argv) { @@ -364,6 +595,9 @@ main (int argc, char **argv) for (i=0; i < 2; i++) check_run (); + + for (i=0; i < 4; i++) + check_x931_derived_key (i); return 0; } |