summaryrefslogtreecommitdiff
path: root/cipher
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
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')
-rw-r--r--cipher/ChangeLog35
-rw-r--r--cipher/dsa.c44
-rw-r--r--cipher/ecc.c83
-rw-r--r--cipher/elgamal.c124
-rw-r--r--cipher/primegen.c141
-rw-r--r--cipher/pubkey.c238
-rw-r--r--cipher/rsa.c231
7 files changed, 628 insertions, 268 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);
}