summaryrefslogtreecommitdiff
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
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.
-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
-rw-r--r--doc/gcrypt.texi42
-rw-r--r--src/ChangeLog8
-rw-r--r--src/cipher-proto.h14
-rw-r--r--src/cipher.h11
-rw-r--r--src/g10lib.h4
-rw-r--r--tests/ChangeLog4
-rwxr-xr-xtests/cavs_driver.pl10
-rw-r--r--tests/fipsdrv.c6
-rw-r--r--tests/pubkey.c234
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;
}