summaryrefslogtreecommitdiff
path: root/cipher/rsa.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2008-11-24 16:37:50 +0000
committerWerner Koch <wk@gnupg.org>2008-11-24 16:37:50 +0000
commit8cc2eb702eeed951907db225f25a1088db4e5c44 (patch)
treecb2d85993036d2a8c755a3729330a767f1e49c03 /cipher/rsa.c
parentf73ff6ce957e65b40dd7a52e9d96744239eb4996 (diff)
downloadlibgcrypt-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.c231
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);
}