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 /cipher/rsa.c | |
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.
Diffstat (limited to 'cipher/rsa.c')
-rw-r--r-- | cipher/rsa.c | 231 |
1 files changed, 217 insertions, 14 deletions
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); } |