diff --git a/cipher/dsa.c b/cipher/dsa.c index 37c1b180..909a8ca2 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -1,1377 +1,1383 @@ /* dsa.c - DSA signature algorithm * Copyright (C) 1998, 2000, 2001, 2002, 2003, * 2006, 2008 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH. * * 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 * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, see . */ #include #include #include #include #include "g10lib.h" #include "mpi.h" #include "cipher.h" #include "pubkey-internal.h" typedef struct { gcry_mpi_t p; /* prime */ gcry_mpi_t q; /* group order */ gcry_mpi_t g; /* group generator */ gcry_mpi_t y; /* g^x mod p */ } DSA_public_key; typedef struct { gcry_mpi_t p; /* prime */ gcry_mpi_t q; /* group order */ gcry_mpi_t g; /* group generator */ gcry_mpi_t y; /* g^x mod p */ gcry_mpi_t x; /* secret exponent */ } DSA_secret_key; /* A structure used to hold domain parameters. */ typedef struct { gcry_mpi_t p; /* prime */ gcry_mpi_t q; /* group order */ gcry_mpi_t g; /* group generator */ } dsa_domain_t; static const char *dsa_names[] = { "dsa", "openpgp-dsa", NULL, }; -/* A sample 1024 bit DSA key used for the selftests. */ +/* A sample 1024 bit DSA key used for the selftests. Not anymore + * used, kept only for reference. */ +#if 0 static const char sample_secret_key_1024[] = "(private-key" " (dsa" " (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" " 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" " CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" " 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" " (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" " (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" " AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" " B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" " 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" " (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" " A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" " 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" " 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)" " (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))"; /* A sample 1024 bit DSA key used for the selftests (public only). */ static const char sample_public_key_1024[] = "(public-key" " (dsa" " (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" " 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" " CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" " 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" " (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" " (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" " AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" " B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" " 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" " (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" " A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" " 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" " 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)))"; +#endif /*0*/ /* 2048 DSA key from RFC 6979 A.2.2 */ static const char sample_public_key_2048[] = "(public-key" " (dsa" " (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)" " (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)" " (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)" " (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)))"; static const char sample_secret_key_2048[] = "(private-key" " (dsa" " (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)" " (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)" " (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)" " (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)" " (x #69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC#)))"; static int test_keys (DSA_secret_key *sk, unsigned int qbits); static int check_secret_key (DSA_secret_key *sk); static gpg_err_code_t generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors); static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, int flags, int hashalgo); static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey); static unsigned int dsa_get_nbits (gcry_sexp_t parms); static void (*progress_cb) (void *,const char *, int, int, int ); static void *progress_cb_data; void _gcry_register_pk_dsa_progress (void (*cb) (void *, const char *, int, int, int), void *cb_data) { progress_cb = cb; progress_cb_data = cb_data; } static void progress (int c) { if (progress_cb) progress_cb (progress_cb_data, "pk_dsa", c, 0, 0); } /* Check that a freshly generated key actually works. Returns 0 on success. */ static int test_keys (DSA_secret_key *sk, unsigned int qbits) { int result = -1; /* Default to failure. */ DSA_public_key pk; gcry_mpi_t data = mpi_new (qbits); gcry_mpi_t sig_a = mpi_new (qbits); gcry_mpi_t sig_b = mpi_new (qbits); /* Put the relevant parameters into a public key structure. */ pk.p = sk->p; pk.q = sk->q; pk.g = sk->g; pk.y = sk->y; /* Create a random plaintext. */ _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); /* Sign DATA using the secret key. */ sign (sig_a, sig_b, data, sk, 0, 0); /* Verify the signature using the public key. */ if ( verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature does not match. */ /* Modify the data and check that the signing fails. */ mpi_add_ui (data, data, 1); if ( !verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature matches but should not. */ result = 0; /* The test succeeded. */ leave: _gcry_mpi_release (sig_b); _gcry_mpi_release (sig_a); _gcry_mpi_release (data); return result; } /* Generate a DSA key pair with a key of size NBITS. If transient_key is true the key is generated using the standard RNG and not the very secure one. Returns: 2 structures filled with all needed values and an array with the n-1 factors of (p-1) */ static gpg_err_code_t generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors ) { gpg_err_code_t rc; gcry_mpi_t p; /* the prime */ gcry_mpi_t q; /* the 160 bit prime factor */ gcry_mpi_t g; /* the generator */ gcry_mpi_t y; /* g^x mod p */ gcry_mpi_t x; /* the secret exponent */ gcry_mpi_t h, e; /* helper */ unsigned char *rndbuf; gcry_random_level_t random_level; if (qbits) ; /* Caller supplied qbits. Use this value. */ else if ( nbits >= 512 && nbits <= 1024 ) qbits = 160; else if ( nbits == 2048 ) qbits = 224; else if ( nbits == 3072 ) qbits = 256; else if ( nbits == 7680 ) qbits = 384; else if ( nbits == 15360 ) qbits = 512; else return GPG_ERR_INV_VALUE; if (qbits < 160 || qbits > 512 || (qbits%8) ) return GPG_ERR_INV_VALUE; if (nbits < 2*qbits || nbits > 15360) return GPG_ERR_INV_VALUE; if (fips_mode ()) { if (nbits < 1024) return GPG_ERR_INV_VALUE; if (transient_key) return GPG_ERR_INV_VALUE; } if (domain->p && domain->q && domain->g) { /* Domain parameters are given; use them. */ p = mpi_copy (domain->p); q = mpi_copy (domain->q); g = mpi_copy (domain->g); gcry_assert (mpi_get_nbits (p) == nbits); gcry_assert (mpi_get_nbits (q) == qbits); h = mpi_alloc (0); e = NULL; } else { /* Generate new domain parameters. */ rc = _gcry_generate_elg_prime (1, nbits, qbits, NULL, &p, ret_factors); if (rc) return rc; /* Get q out of factors. */ q = mpi_copy ((*ret_factors)[0]); gcry_assert (mpi_get_nbits (q) == qbits); /* Find a generator g (h and e are helpers). e = (p-1)/q */ e = mpi_alloc (mpi_get_nlimbs (p)); mpi_sub_ui (e, p, 1); mpi_fdiv_q (e, e, q); g = mpi_alloc (mpi_get_nlimbs (p)); h = mpi_alloc_set_ui (1); /* (We start with 2.) */ do { mpi_add_ui (h, h, 1); /* g = h^e mod p */ mpi_powm (g, h, e, p); } while (!mpi_cmp_ui (g, 1)); /* Continue until g != 1. */ } /* Select a random number X with the property: * 0 < x < q-1 * * FIXME: Why do we use the requirement x < q-1 ? It should be * sufficient to test for x < q. FIPS-186-3 check x < q-1 but it * does not check for 0 < x because it makes sure that Q is unsigned * and finally adds one to the result so that 0 will never be * returned. We should replace the code below with _gcry_dsa_gen_k. * * This must be a very good random number because this is the secret * part. The random quality depends on the transient_key flag. */ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; if (DBG_CIPHER) log_debug("choosing a random x%s\n", transient_key? " (transient-key)":""); gcry_assert( qbits >= 160 ); x = mpi_alloc_secure( mpi_get_nlimbs(q) ); mpi_sub_ui( h, q, 1 ); /* put q-1 into h */ rndbuf = NULL; do { if( DBG_CIPHER ) progress('.'); if( !rndbuf ) rndbuf = _gcry_random_bytes_secure ((qbits+7)/8, random_level); else { /* Change only some of the higher bits (= 2 bytes)*/ char *r = _gcry_random_bytes_secure (2, random_level); memcpy(rndbuf, r, 2 ); xfree(r); } _gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 ); mpi_clear_highbit( x, qbits+1 ); } while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) ); xfree(rndbuf); mpi_free( e ); mpi_free( h ); /* y = g^x mod p */ y = mpi_alloc( mpi_get_nlimbs(p) ); mpi_powm (y, g, x, p); if( DBG_CIPHER ) { progress('\n'); log_mpidump("dsa p", p ); log_mpidump("dsa q", q ); log_mpidump("dsa g", g ); log_mpidump("dsa y", y ); log_mpidump("dsa x", x ); } /* Copy the stuff to the key structures. */ sk->p = p; sk->q = q; sk->g = g; sk->y = y; sk->x = x; /* Now we can test our keys (this should never fail!). */ if ( test_keys (sk, qbits) ) { _gcry_mpi_release (sk->p); sk->p = NULL; _gcry_mpi_release (sk->q); sk->q = NULL; _gcry_mpi_release (sk->g); sk->g = NULL; _gcry_mpi_release (sk->y); sk->y = NULL; _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); return GPG_ERR_SELFTEST_FAILED; } return 0; } /* Generate a DSA key pair with a key of size NBITS using the algorithm given in FIPS-186-3. If USE_FIPS186_2 is true, FIPS-186-2 is used and thus the length is restricted to 1024/160. If DERIVEPARMS is not NULL it may contain a seed value. If domain parameters are specified in DOMAIN, DERIVEPARMS may not be given and NBITS and QBITS must match the specified domain parameters. */ static gpg_err_code_t generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, gcry_sexp_t deriveparms, int use_fips186_2, dsa_domain_t *domain, int *r_counter, void **r_seed, size_t *r_seedlen, gcry_mpi_t *r_h) { gpg_err_code_t ec; struct { gcry_sexp_t sexp; const void *seed; size_t seedlen; } initial_seed = { NULL, NULL, 0 }; gcry_mpi_t prime_q = NULL; gcry_mpi_t prime_p = NULL; gcry_mpi_t value_g = NULL; /* The generator. */ gcry_mpi_t value_y = NULL; /* g^x mod p */ gcry_mpi_t value_x = NULL; /* The secret exponent. */ gcry_mpi_t value_h = NULL; /* Helper. */ gcry_mpi_t value_e = NULL; /* Helper. */ gcry_mpi_t value_c = NULL; /* helper for x */ gcry_mpi_t value_qm2 = NULL; /* q - 2 */ /* Preset return values. */ *r_counter = 0; *r_seed = NULL; *r_seedlen = 0; *r_h = NULL; /* Derive QBITS from NBITS if requested */ if (!qbits) { if (nbits == 1024) qbits = 160; else if (nbits == 2048) qbits = 224; else if (nbits == 3072) qbits = 256; } /* Check that QBITS and NBITS match the standard. Note that FIPS 186-3 uses N for QBITS and L for NBITS. */ - if (nbits == 2048 && qbits == 224) + if (nbits == 1024 && qbits == 160 && use_fips186_2) + ; /* Allowed in FIPS 186-2 mode. */ + else if (nbits == 2048 && qbits == 224) ; else if (nbits == 2048 && qbits == 256) ; else if (nbits == 3072 && qbits == 256) ; else return GPG_ERR_INV_VALUE; if (domain->p && domain->q && domain->g) { /* Domain parameters are given; use them. */ prime_p = mpi_copy (domain->p); prime_q = mpi_copy (domain->q); value_g = mpi_copy (domain->g); gcry_assert (mpi_get_nbits (prime_p) == nbits); gcry_assert (mpi_get_nbits (prime_q) == qbits); gcry_assert (!deriveparms); ec = 0; } else { /* Generate new domain parameters. */ /* Get an initial seed value. */ if (deriveparms) { initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0); if (initial_seed.sexp) initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1, - &initial_seed.seedlen); + &initial_seed.seedlen); } if (use_fips186_2) ec = _gcry_generate_fips186_2_prime (nbits, qbits, - initial_seed.seed, - initial_seed.seedlen, - &prime_q, &prime_p, - r_counter, - r_seed, r_seedlen); + initial_seed.seed, + initial_seed.seedlen, + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen); else ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, - &prime_q, &prime_p, - r_counter, - r_seed, r_seedlen, NULL); + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen, NULL); sexp_release (initial_seed.sexp); if (ec) goto leave; /* Find a generator g (h and e are helpers). - e = (p-1)/q */ + * e = (p-1)/q + */ value_e = mpi_alloc_like (prime_p); mpi_sub_ui (value_e, prime_p, 1); mpi_fdiv_q (value_e, value_e, prime_q ); value_g = mpi_alloc_like (prime_p); value_h = mpi_alloc_set_ui (1); do { mpi_add_ui (value_h, value_h, 1); /* g = h^e mod p */ mpi_powm (value_g, value_h, value_e, prime_p); } while (!mpi_cmp_ui (value_g, 1)); /* Continue until g != 1. */ } value_c = mpi_snew (qbits); value_x = mpi_snew (qbits); value_qm2 = mpi_snew (qbits); mpi_sub_ui (value_qm2, prime_q, 2); /* FIPS 186-4 B.1.2 steps 4-6 */ do { if( DBG_CIPHER ) progress('.'); _gcry_mpi_randomize (value_c, qbits, GCRY_VERY_STRONG_RANDOM); mpi_clear_highbit (value_c, qbits+1); } while (!(mpi_cmp_ui (value_c, 0) > 0 && mpi_cmp (value_c, value_qm2) < 0)); /* while (mpi_cmp (value_c, value_qm2) > 0); */ /* x = c + 1 */ mpi_add_ui(value_x, value_c, 1); /* y = g^x mod p */ value_y = mpi_alloc_like (prime_p); mpi_powm (value_y, value_g, value_x, prime_p); if (DBG_CIPHER) { progress('\n'); log_mpidump("dsa p", prime_p ); log_mpidump("dsa q", prime_q ); log_mpidump("dsa g", value_g ); log_mpidump("dsa y", value_y ); log_mpidump("dsa x", value_x ); log_mpidump("dsa h", value_h ); } /* Copy the stuff to the key structures. */ sk->p = prime_p; prime_p = NULL; sk->q = prime_q; prime_q = NULL; sk->g = value_g; value_g = NULL; sk->y = value_y; value_y = NULL; sk->x = value_x; value_x = NULL; *r_h = value_h; value_h = NULL; leave: _gcry_mpi_release (prime_p); _gcry_mpi_release (prime_q); _gcry_mpi_release (value_g); _gcry_mpi_release (value_y); _gcry_mpi_release (value_x); _gcry_mpi_release (value_h); _gcry_mpi_release (value_e); _gcry_mpi_release (value_c); _gcry_mpi_release (value_qm2); /* As a last step test this keys (this should never fail of course). */ if (!ec && test_keys (sk, qbits) ) { _gcry_mpi_release (sk->p); sk->p = NULL; _gcry_mpi_release (sk->q); sk->q = NULL; _gcry_mpi_release (sk->g); sk->g = NULL; _gcry_mpi_release (sk->y); sk->y = NULL; _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); ec = GPG_ERR_SELFTEST_FAILED; } if (ec) { *r_counter = 0; xfree (*r_seed); *r_seed = NULL; *r_seedlen = 0; _gcry_mpi_release (*r_h); *r_h = NULL; } return ec; } /* Test whether the secret key is valid. Returns: if this is a valid key. */ static int check_secret_key( DSA_secret_key *sk ) { int rc; gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); mpi_powm( y, sk->g, sk->x, sk->p ); rc = !mpi_cmp( y, sk->y ); mpi_free( y ); return rc; } /* Make a DSA signature from INPUT and put it into r and s. INPUT may either be a plain MPI or an opaque MPI which is then internally converted to a plain MPI. FLAGS and HASHALGO may both be 0 for standard operation mode. The return value is 0 on success or an error code. Note that for backward compatibility the function will not return any error if FLAGS and HASHALGO are both 0 and INPUT is a plain MPI. */ static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, int flags, int hashalgo) { gpg_err_code_t rc; gcry_mpi_t hash; gcry_mpi_t k; gcry_mpi_t kinv; gcry_mpi_t tmp; const void *abuf; unsigned int abits, qbits; int extraloops = 0; qbits = mpi_get_nbits (skey->q); /* Convert the INPUT into an MPI. */ rc = _gcry_dsa_normalize_hash (input, &hash, qbits); if (rc) return rc; again: /* Create the K value. */ if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) { /* Use Pornin's method for deterministic DSA. If this flag is set, it is expected that HASH is an opaque MPI with the to be signed hash. That hash is also used as h1 from 3.2.a. */ if (!mpi_is_opaque (input)) { rc = GPG_ERR_CONFLICT; goto leave; } abuf = mpi_get_opaque (input, &abits); rc = _gcry_dsa_gen_rfc6979_k (&k, skey->q, skey->x, abuf, (abits+7)/8, hashalgo, extraloops); if (rc) goto leave; } else { /* Select a random k with 0 < k < q */ k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM); } /* r = (a^k mod p) mod q */ mpi_powm( r, skey->g, k, skey->p ); mpi_fdiv_r( r, r, skey->q ); /* kinv = k^(-1) mod q */ kinv = mpi_alloc( mpi_get_nlimbs(k) ); mpi_invm(kinv, k, skey->q ); /* s = (kinv * ( hash + x * r)) mod q */ tmp = mpi_alloc( mpi_get_nlimbs(skey->p) ); mpi_mul( tmp, skey->x, r ); mpi_add( tmp, tmp, hash ); mpi_mulm( s , kinv, tmp, skey->q ); mpi_free(k); mpi_free(kinv); mpi_free(tmp); if (!mpi_cmp_ui (r, 0)) { /* This is a highly unlikely code path. */ extraloops++; goto again; } rc = 0; leave: if (hash != input) mpi_free (hash); return rc; } /* Returns true if the signature composed from R and S is valid. */ static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey ) { gpg_err_code_t rc = 0; gcry_mpi_t w, u1, u2, v; gcry_mpi_t base[3]; gcry_mpi_t ex[3]; gcry_mpi_t hash; unsigned int nbits; if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ nbits = mpi_get_nbits (pkey->q); rc = _gcry_dsa_normalize_hash (input, &hash, nbits); if (rc) return rc; w = mpi_alloc( mpi_get_nlimbs(pkey->q) ); u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); v = mpi_alloc( mpi_get_nlimbs(pkey->p) ); /* w = s^(-1) mod q */ mpi_invm( w, s, pkey->q ); /* u1 = (hash * w) mod q */ mpi_mulm( u1, hash, w, pkey->q ); /* u2 = r * w mod q */ mpi_mulm( u2, r, w, pkey->q ); /* v = g^u1 * y^u2 mod p mod q */ base[0] = pkey->g; ex[0] = u1; base[1] = pkey->y; ex[1] = u2; base[2] = NULL; ex[2] = NULL; mpi_mulpowm( v, base, ex, pkey->p ); mpi_fdiv_r( v, v, pkey->q ); if (mpi_cmp( v, r )) { if (DBG_CIPHER) { log_mpidump (" i", input); log_mpidump (" h", hash); log_mpidump (" v", v); log_mpidump (" r", r); log_mpidump (" s", s); } rc = GPG_ERR_BAD_SIGNATURE; } mpi_free(w); mpi_free(u1); mpi_free(u2); mpi_free(v); if (hash != input) mpi_free (hash); return rc; } /********************************************* ************** interface ****************** *********************************************/ static gcry_err_code_t dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { gpg_err_code_t rc; unsigned int nbits; gcry_sexp_t domainsexp; DSA_secret_key sk; gcry_sexp_t l1; unsigned int qbits = 0; gcry_sexp_t deriveparms = NULL; gcry_sexp_t seedinfo = NULL; gcry_sexp_t misc_info = NULL; int flags = 0; dsa_domain_t domain; gcry_mpi_t *factors = NULL; memset (&sk, 0, sizeof sk); memset (&domain, 0, sizeof domain); rc = _gcry_pk_util_get_nbits (genparms, &nbits); if (rc) return rc; /* Parse the optional flags list. */ l1 = sexp_find_token (genparms, "flags", 0); if (l1) { rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); sexp_release (l1); if (rc) return rc;\ } /* Parse the optional qbits element. */ l1 = sexp_find_token (genparms, "qbits", 0); if (l1) { char buf[50]; const char *s; size_t n; s = sexp_nth_data (l1, 1, &n); if (!s || n >= DIM (buf) - 1 ) { 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); sexp_release (l1); } /* Parse the optional transient-key flag. */ if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) { l1 = sexp_find_token (genparms, "transient-key", 0); if (l1) { flags |= PUBKEY_FLAG_TRANSIENT_KEY; sexp_release (l1); } } /* Get the optional derive parameters. */ deriveparms = sexp_find_token (genparms, "derive-parms", 0); /* Parse the optional "use-fips186" flags. */ if (!(flags & PUBKEY_FLAG_USE_FIPS186)) { l1 = sexp_find_token (genparms, "use-fips186", 0); if (l1) { flags |= PUBKEY_FLAG_USE_FIPS186; sexp_release (l1); } } if (!(flags & PUBKEY_FLAG_USE_FIPS186_2)) { l1 = sexp_find_token (genparms, "use-fips186-2", 0); if (l1) { flags |= PUBKEY_FLAG_USE_FIPS186_2; sexp_release (l1); } } /* Check whether domain parameters are given. */ domainsexp = sexp_find_token (genparms, "domain", 0); if (domainsexp) { /* DERIVEPARMS can't be used together with domain parameters. NBITS abnd QBITS may not be specified because there values are derived from the domain parameters. */ if (deriveparms || qbits || nbits) { sexp_release (domainsexp); sexp_release (deriveparms); return GPG_ERR_INV_VALUE; } /* Put all domain parameters into the domain object. */ l1 = sexp_find_token (domainsexp, "p", 0); domain.p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); l1 = sexp_find_token (domainsexp, "q", 0); domain.q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); l1 = sexp_find_token (domainsexp, "g", 0); domain.g = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); sexp_release (domainsexp); /* Check that all domain parameters are available. */ if (!domain.p || !domain.q || !domain.g) { _gcry_mpi_release (domain.p); _gcry_mpi_release (domain.q); _gcry_mpi_release (domain.g); sexp_release (deriveparms); return GPG_ERR_MISSING_VALUE; } /* Get NBITS and QBITS from the domain parameters. */ nbits = mpi_get_nbits (domain.p); qbits = mpi_get_nbits (domain.q); } if (deriveparms || (flags & PUBKEY_FLAG_USE_FIPS186) || (flags & PUBKEY_FLAG_USE_FIPS186_2) || fips_mode ()) { int counter; void *seed; size_t seedlen; gcry_mpi_t h_value; rc = generate_fips186 (&sk, nbits, qbits, deriveparms, !!(flags & PUBKEY_FLAG_USE_FIPS186_2), &domain, &counter, &seed, &seedlen, &h_value); if (!rc && h_value) { /* Format the seed-values unless domain parameters are used for which a H_VALUE of NULL is an indication. */ rc = sexp_build (&seedinfo, NULL, "(seed-values(counter %d)(seed %b)(h %m))", counter, (int)seedlen, seed, h_value); xfree (seed); _gcry_mpi_release (h_value); } } else { rc = generate (&sk, nbits, qbits, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY), &domain, &factors); } if (!rc) { /* Put the factors into MISC_INFO. Note that the factors are not confidential thus we can store them in standard memory. */ int nfactors, i, j; char *p; char *format = NULL; void **arg_list = NULL; for (nfactors=0; factors && factors[nfactors]; nfactors++) ; /* Allocate space for the format string: "(misc-key-info%S(pm1-factors%m))" with one "%m" for each factor and construct it. */ format = xtrymalloc (50 + 2*nfactors); if (!format) rc = gpg_err_code_from_syserror (); else { p = stpcpy (format, "(misc-key-info"); if (seedinfo) p = stpcpy (p, "%S"); if (nfactors) { p = stpcpy (p, "(pm1-factors"); for (i=0; i < nfactors; i++) p = stpcpy (p, "%m"); p = stpcpy (p, ")"); } p = stpcpy (p, ")"); /* Allocate space for the list of factors plus one for the seedinfo s-exp plus an extra NULL entry for safety and fill it with the factors. */ arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list); if (!arg_list) rc = gpg_err_code_from_syserror (); else { i = 0; if (seedinfo) arg_list[i++] = &seedinfo; for (j=0; j < nfactors; j++) arg_list[i++] = factors + j; arg_list[i] = NULL; rc = sexp_build_array (&misc_info, NULL, format, arg_list); } } xfree (arg_list); xfree (format); } if (!rc) rc = sexp_build (r_skey, NULL, "(key-data" " (public-key" " (dsa(p%m)(q%m)(g%m)(y%m)))" " (private-key" " (dsa(p%m)(q%m)(g%m)(y%m)(x%m)))" " %S)", sk.p, sk.q, sk.g, sk.y, sk.p, sk.q, sk.g, sk.y, sk.x, misc_info); _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); _gcry_mpi_release (sk.g); _gcry_mpi_release (sk.y); _gcry_mpi_release (sk.x); _gcry_mpi_release (domain.p); _gcry_mpi_release (domain.q); _gcry_mpi_release (domain.g); sexp_release (seedinfo); sexp_release (misc_info); sexp_release (deriveparms); if (factors) { gcry_mpi_t *mp; for (mp = factors; *mp; mp++) mpi_free (*mp); xfree (factors); } return rc; } static gcry_err_code_t dsa_check_secret_key (gcry_sexp_t keyparms) { gcry_err_code_t rc; DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (!check_secret_key (&sk)) rc = GPG_ERR_BAD_SECKEY; leave: _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); _gcry_mpi_release (sk.g); _gcry_mpi_release (sk.y); _gcry_mpi_release (sk.x); if (DBG_CIPHER) log_debug ("dsa_testkey => %s\n", gpg_strerror (rc)); return rc; } static gcry_err_code_t dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { gcry_err_code_t rc; struct pk_encoding_ctx ctx; gcry_mpi_t data = NULL; DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; gcry_mpi_t sig_r = NULL; gcry_mpi_t sig_s = NULL; _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, dsa_get_nbits (keyparms)); /* Extract the data. */ rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); if (rc) goto leave; if (DBG_CIPHER) log_mpidump ("dsa_sign data", data); /* Extract the key. */ rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_sign p", sk.p); log_mpidump ("dsa_sign q", sk.q); log_mpidump ("dsa_sign g", sk.g); log_mpidump ("dsa_sign y", sk.y); if (!fips_mode ()) log_mpidump ("dsa_sign x", sk.x); } sig_r = mpi_new (0); sig_s = mpi_new (0); rc = sign (sig_r, sig_s, data, &sk, ctx.flags, ctx.hash_algo); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_sign sig_r", sig_r); log_mpidump ("dsa_sign sig_s", sig_s); } rc = sexp_build (r_sig, NULL, "(sig-val(dsa(r%M)(s%M)))", sig_r, sig_s); leave: _gcry_mpi_release (sig_r); _gcry_mpi_release (sig_s); _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); _gcry_mpi_release (sk.g); _gcry_mpi_release (sk.y); _gcry_mpi_release (sk.x); _gcry_mpi_release (data); _gcry_pk_util_free_encoding_ctx (&ctx); if (DBG_CIPHER) log_debug ("dsa_sign => %s\n", gpg_strerror (rc)); return rc; } static gcry_err_code_t dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { gcry_err_code_t rc; struct pk_encoding_ctx ctx; gcry_sexp_t l1 = NULL; gcry_mpi_t sig_r = NULL; gcry_mpi_t sig_s = NULL; gcry_mpi_t data = NULL; DSA_public_key pk = { NULL, NULL, NULL, NULL }; _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, dsa_get_nbits (s_keyparms)); /* Extract the data. */ rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); if (rc) goto leave; if (DBG_CIPHER) log_mpidump ("dsa_verify data", data); /* Extract the signature value. */ rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); if (rc) goto leave; rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_verify s_r", sig_r); log_mpidump ("dsa_verify s_s", sig_s); } /* Extract the key. */ rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", &pk.p, &pk.q, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_verify p", pk.p); log_mpidump ("dsa_verify q", pk.q); log_mpidump ("dsa_verify g", pk.g); log_mpidump ("dsa_verify y", pk.y); } /* Verify the signature. */ rc = verify (sig_r, sig_s, data, &pk); leave: _gcry_mpi_release (pk.p); _gcry_mpi_release (pk.q); _gcry_mpi_release (pk.g); _gcry_mpi_release (pk.y); _gcry_mpi_release (data); _gcry_mpi_release (sig_r); _gcry_mpi_release (sig_s); sexp_release (l1); _gcry_pk_util_free_encoding_ctx (&ctx); if (DBG_CIPHER) log_debug ("dsa_verify => %s\n", rc?gpg_strerror (rc):"Good"); return rc; } /* Return the number of bits for the key described by PARMS. On error * 0 is returned. The format of PARMS starts with the algorithm name; * for example: * * (dsa * (p ) * (q ) * (g ) * (y )) * * More parameters may be given but we only need P here. */ static unsigned int dsa_get_nbits (gcry_sexp_t parms) { gcry_sexp_t l1; gcry_mpi_t p; unsigned int nbits; l1 = sexp_find_token (parms, "p", 1); if (!l1) return 0; /* Parameter P not found. */ p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); nbits = p? mpi_get_nbits (p) : 0; _gcry_mpi_release (p); return nbits; } /* Self-test section. */ static const char * selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) { /* Sample data from RFC 6979 section A.2.2, hash is of message "sample" */ static const char sample_data[] = "(data (flags rfc6979)" " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))"; static const char sample_data_bad[] = "(data (flags rfc6979)" " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))"; static const char signature_r[] = "eace8bdbbe353c432a795d9ec556c6d021f7a03f42c36e9bc87e4ac7932cc809"; static const char signature_s[] = "7081e175455f9247b812b74583e9e94f9ea79bd640dc962533b0680793a38d53"; const char *errtxt = NULL; gcry_error_t err; gcry_sexp_t data = NULL; gcry_sexp_t data_bad = NULL; gcry_sexp_t sig = NULL; gcry_sexp_t l1 = NULL; gcry_sexp_t l2 = NULL; gcry_mpi_t r = NULL; gcry_mpi_t s = NULL; gcry_mpi_t calculated_r = NULL; gcry_mpi_t calculated_s = NULL; int cmp; err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); if (!err) err = sexp_sscan (&data_bad, NULL, sample_data_bad, strlen (sample_data_bad)); if (!err) err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL); if (!err) err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL); if (err) { errtxt = "converting data failed"; goto leave; } err = _gcry_pk_sign (&sig, data, skey); if (err) { errtxt = "signing failed"; goto leave; } /* check against known signature */ errtxt = "signature validity failed"; l1 = _gcry_sexp_find_token (sig, "sig-val", 0); if (!l1) goto leave; l2 = _gcry_sexp_find_token (l1, "dsa", 0); if (!l2) goto leave; sexp_release (l1); l1 = l2; l2 = _gcry_sexp_find_token (l1, "r", 0); if (!l2) goto leave; calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); if (!calculated_r) goto leave; l2 = _gcry_sexp_find_token (l1, "s", 0); if (!l2) goto leave; calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); if (!calculated_s) goto leave; errtxt = "known sig check failed"; cmp = _gcry_mpi_cmp (r, calculated_r); if (cmp) goto leave; cmp = _gcry_mpi_cmp (s, calculated_s); if (cmp) goto leave; errtxt = NULL; err = _gcry_pk_verify (sig, data, pkey); if (err) { errtxt = "verify failed"; goto leave; } err = _gcry_pk_verify (sig, data_bad, pkey); if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) { errtxt = "bad signature not detected"; goto leave; } leave: sexp_release (sig); sexp_release (data_bad); sexp_release (data); return errtxt; } static gpg_err_code_t selftests_dsa_2048 (selftest_report_func_t report) { const char *what; const char *errtxt; gcry_error_t err; gcry_sexp_t skey = NULL; gcry_sexp_t pkey = NULL; /* Convert the S-expressions into the internal representation. */ what = "convert"; err = sexp_sscan (&skey, NULL, sample_secret_key_2048, strlen (sample_secret_key_2048)); if (!err) err = sexp_sscan (&pkey, NULL, sample_public_key_2048, strlen (sample_public_key_2048)); if (err) { errtxt = _gcry_strerror (err); goto failed; } what = "key consistency"; err = _gcry_pk_testkey (skey); if (err) { errtxt = _gcry_strerror (err); goto failed; } what = "sign"; errtxt = selftest_sign (pkey, skey); if (errtxt) goto failed; sexp_release (pkey); sexp_release (skey); return 0; /* Succeeded. */ failed: sexp_release (pkey); sexp_release (skey); if (report) report ("pubkey", GCRY_PK_DSA, what, errtxt); return GPG_ERR_SELFTEST_FAILED; } /* Run a full self-test for ALGO and return 0 on success. */ static gpg_err_code_t run_selftests (int algo, int extended, selftest_report_func_t report) { gpg_err_code_t ec; (void)extended; switch (algo) { case GCRY_PK_DSA: ec = selftests_dsa_2048 (report); break; default: ec = GPG_ERR_PUBKEY_ALGO; break; } return ec; } gcry_pk_spec_t _gcry_pubkey_spec_dsa = { GCRY_PK_DSA, { 0, 1 }, GCRY_PK_USAGE_SIGN, "DSA", dsa_names, "pqgy", "pqgyx", "", "rs", "pqgy", dsa_generate, dsa_check_secret_key, NULL, NULL, dsa_sign, dsa_verify, dsa_get_nbits, run_selftests }; diff --git a/cipher/primegen.c b/cipher/primegen.c index 9fd58d22..3ed432bf 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -1,1854 +1,1851 @@ /* primegen.c - prime number generator * Copyright (C) 1998, 2000, 2001, 2002, 2003 * 2004, 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 * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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 */ #include #include #include #include #include #include "g10lib.h" #include "mpi.h" #include "cipher.h" static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg); static int check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, gcry_prime_check_func_t cb_func, void *cb_arg ); static int is_prime (gcry_mpi_t n, int steps, unsigned int *count); static void m_out_of_n( char *array, int m, int n ); static void (*progress_cb) (void *,const char*,int,int, int ); static void *progress_cb_data; /* Note: 2 is not included because it can be tested more easily by looking at bit 0. The last entry in this list is marked by a zero */ static ushort small_prime_numbers[] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 0 }; static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; /* An object and a list to build up a global pool of primes. See save_pool_prime and get_pool_prime. */ struct primepool_s { struct primepool_s *next; gcry_mpi_t prime; /* If this is NULL the entry is not used. */ unsigned int nbits; gcry_random_level_t randomlevel; }; struct primepool_s *primepool; /* Mutex used to protect access to the primepool. */ GPGRT_LOCK_DEFINE (primepool_lock); gcry_err_code_t _gcry_primegen_init (void) { /* This function was formerly used to initialize the primepool Mutex. This has been replace by a static initialization. */ return 0; } /* Save PRIME which has been generated at RANDOMLEVEL for later use. Needs to be called while primepool_lock is being hold. Note that PRIME should be considered released after calling this function. */ static void save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) { struct primepool_s *item, *item2; size_t n; for (n=0, item = primepool; item; item = item->next, n++) if (!item->prime) break; if (!item && n > 100) { /* Remove some of the entries. Our strategy is removing the last third from the list. */ int i; for (i=0, item2 = primepool; item2; item2 = item2->next) { if (i >= n/3*2) { _gcry_mpi_release (item2->prime); item2->prime = NULL; if (!item) item = item2; } } } if (!item) { item = xtrycalloc (1, sizeof *item); if (!item) { /* Out of memory. Silently giving up. */ _gcry_mpi_release (prime); return; } item->next = primepool; primepool = item; } item->prime = prime; item->nbits = mpi_get_nbits (prime); item->randomlevel = randomlevel; } /* Return a prime for the prime pool or NULL if none has been found. The prime needs to match NBITS and randomlevel. This function needs to be called with the primepool_look is being hold. */ static gcry_mpi_t get_pool_prime (unsigned int nbits, gcry_random_level_t randomlevel) { struct primepool_s *item; for (item = primepool; item; item = item->next) if (item->prime && item->nbits == nbits && item->randomlevel == randomlevel) { gcry_mpi_t prime = item->prime; item->prime = NULL; gcry_assert (nbits == mpi_get_nbits (prime)); return prime; } return NULL; } void _gcry_register_primegen_progress ( void (*cb)(void *,const char*,int,int,int), void *cb_data ) { progress_cb = cb; progress_cb_data = cb_data; } static void progress( int c ) { if ( progress_cb ) progress_cb ( progress_cb_data, "primegen", c, 0, 0 ); } /**************** * Generate a prime number (stored in secure memory) */ gcry_mpi_t _gcry_generate_secret_prime (unsigned int nbits, gcry_random_level_t random_level, int (*extra_check)(void*, gcry_mpi_t), void *extra_check_arg) { gcry_mpi_t prime; prime = gen_prime (nbits, 1, random_level, extra_check, extra_check_arg); progress('\n'); return prime; } /* Generate a prime number which may be public, i.e. not allocated in secure memory. */ gcry_mpi_t _gcry_generate_public_prime (unsigned int nbits, gcry_random_level_t random_level, int (*extra_check)(void*, gcry_mpi_t), void *extra_check_arg) { gcry_mpi_t prime; prime = gen_prime (nbits, 0, random_level, extra_check, extra_check_arg); progress('\n'); return prime; } /* Core prime generation function. The algorithm used to generate practically save primes is due to Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847) page 260. NEED_Q_FACTOR: If true make sure that at least one factor is of size qbits. This is for example required for DSA. PRIME_GENERATED: Adresss of a variable where the resulting prime number will be stored. PBITS: Requested size of the prime number. At least 48. QBITS: One factor of the prime needs to be of this size. Maybe 0 if this is not required. See also MODE. G: If not NULL an MPI which will receive a generator for the prime for use with Elgamal. RET_FACTORS: if not NULL, an array with all factors are stored at that address. ALL_FACTORS: If set to true all factors of prime-1 are returned. RANDOMLEVEL: How strong should the random numers be. FLAGS: Prime generation bit flags. Currently supported: GCRY_PRIME_FLAG_SECRET - The prime needs to be kept secret. CB_FUNC, CB_ARG: Callback to be used for extra checks. */ static gcry_err_code_t prime_generate_internal (int need_q_factor, gcry_mpi_t *prime_generated, unsigned int pbits, unsigned int qbits, gcry_mpi_t g, gcry_mpi_t **ret_factors, gcry_random_level_t randomlevel, unsigned int flags, int all_factors, gcry_prime_check_func_t cb_func, void *cb_arg) { gcry_err_code_t err = 0; gcry_mpi_t *factors_new = NULL; /* Factors to return to the caller. */ gcry_mpi_t *factors = NULL; /* Current factors. */ gcry_random_level_t poolrandomlevel; /* Random level used for pool primes. */ gcry_mpi_t *pool = NULL; /* Pool of primes. */ int *pool_in_use = NULL; /* Array with currently used POOL elements. */ unsigned char *perms = NULL; /* Permutations of POOL. */ gcry_mpi_t q_factor = NULL; /* Used if QBITS is non-zero. */ unsigned int fbits = 0; /* Length of prime factors. */ unsigned int n = 0; /* Number of factors. */ unsigned int m = 0; /* Number of primes in pool. */ gcry_mpi_t q = NULL; /* First prime factor. */ gcry_mpi_t prime = NULL; /* Prime candidate. */ unsigned int nprime = 0; /* Bits of PRIME. */ unsigned int req_qbits; /* The original QBITS value. */ gcry_mpi_t val_2; /* For check_prime(). */ int is_locked = 0; /* Flag to help unlocking the primepool. */ unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET); unsigned int count1 = 0, count2 = 0; unsigned int i = 0, j = 0; if (pbits < 48) return GPG_ERR_INV_ARG; /* We won't use a too strong random elvel for the pooled subprimes. */ poolrandomlevel = (randomlevel > GCRY_STRONG_RANDOM? GCRY_STRONG_RANDOM : randomlevel); /* If QBITS is not given, assume a reasonable value. */ if (!qbits) qbits = pbits / 3; req_qbits = qbits; /* Find number of needed prime factors N. */ for (n = 1; (pbits - qbits - 1) / n >= qbits; n++) ; n--; val_2 = mpi_alloc_set_ui (2); if ((! n) || ((need_q_factor) && (n < 2))) { err = GPG_ERR_INV_ARG; goto leave; } if (need_q_factor) { n--; /* Need one factor less because we want a specific Q-FACTOR. */ fbits = (pbits - 2 * req_qbits -1) / n; qbits = pbits - req_qbits - n * fbits; } else { fbits = (pbits - req_qbits -1) / n; qbits = pbits - n * fbits; } if (DBG_CIPHER) log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", pbits, req_qbits, qbits, fbits, n); /* Allocate an integer to old the new prime. */ prime = mpi_new (pbits); /* Generate first prime factor. */ q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); /* Generate a specific Q-Factor if requested. */ if (need_q_factor) q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); /* Allocate an array to hold all factors + 2 for later usage. */ factors = xtrycalloc (n + 2, sizeof (*factors)); if (!factors) { err = gpg_err_code_from_errno (errno); goto leave; } /* Allocate an array to track pool usage. */ pool_in_use = xtrymalloc (n * sizeof *pool_in_use); if (!pool_in_use) { err = gpg_err_code_from_errno (errno); goto leave; } for (i=0; i < n; i++) pool_in_use[i] = -1; /* Make a pool of 3n+5 primes (this is an arbitrary value). We require at least 30 primes for are useful selection process. Fixme: We need to research the best formula for sizing the pool. */ m = n * 3 + 5; if (need_q_factor) /* Need some more in this case. */ m += 5; if (m < 30) m = 30; pool = xtrycalloc (m , sizeof (*pool)); if (! pool) { err = gpg_err_code_from_errno (errno); goto leave; } /* Permutate over the pool of primes until we find a prime of the requested length. */ do { next_try: for (i=0; i < n; i++) pool_in_use[i] = -1; if (!perms) { /* Allocate new primes. This is done right at the beginning of the loop and if we have later run out of primes. */ for (i = 0; i < m; i++) { mpi_free (pool[i]); pool[i] = NULL; } /* Init m_out_of_n(). */ perms = xtrycalloc (1, m); if (!perms) { err = gpg_err_code_from_errno (errno); goto leave; } err = gpgrt_lock_lock (&primepool_lock); if (err) goto leave; is_locked = 1; for (i = 0; i < n; i++) { perms[i] = 1; /* At a maximum we use strong random for the factors. This saves us a lot of entropy. Given that Q and possible Q-factor are also used in the final prime this should be acceptable. We also don't allocate in secure memory to save on that scare resource too. If Q has been allocated in secure memory, the final prime will be saved there anyway. This is because our MPI routines take care of that. GnuPG has worked this way ever since. */ pool[i] = NULL; if (is_locked) { pool[i] = get_pool_prime (fbits, poolrandomlevel); if (!pool[i]) { err = gpgrt_lock_unlock (&primepool_lock); if (err) goto leave; is_locked = 0; } } if (!pool[i]) pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); pool_in_use[i] = i; factors[i] = pool[i]; } if (is_locked && (err = gpgrt_lock_unlock (&primepool_lock))) goto leave; is_locked = 0; } else { /* Get next permutation. */ m_out_of_n ( (char*)perms, n, m); if ((err = gpgrt_lock_lock (&primepool_lock))) goto leave; is_locked = 1; for (i = j = 0; (i < m) && (j < n); i++) if (perms[i]) { /* If the subprime has not yet beed generated do it now. */ if (!pool[i] && is_locked) { pool[i] = get_pool_prime (fbits, poolrandomlevel); if (!pool[i]) { if ((err = gpgrt_lock_unlock (&primepool_lock))) goto leave; is_locked = 0; } } if (!pool[i]) pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); pool_in_use[j] = i; factors[j++] = pool[i]; } if (is_locked && (err = gpgrt_lock_unlock (&primepool_lock))) goto leave; is_locked = 0; if (i == n) { /* Ran out of permutations: Allocate new primes. */ xfree (perms); perms = NULL; progress ('!'); goto next_try; } } /* Generate next prime candidate: p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. */ mpi_set (prime, q); mpi_mul_ui (prime, prime, 2); if (need_q_factor) mpi_mul (prime, prime, q_factor); for(i = 0; i < n; i++) mpi_mul (prime, prime, factors[i]); mpi_add_ui (prime, prime, 1); nprime = mpi_get_nbits (prime); if (nprime < pbits) { if (++count1 > 20) { count1 = 0; qbits++; progress('>'); mpi_free (q); q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); goto next_try; } } else count1 = 0; if (nprime > pbits) { if (++count2 > 20) { count2 = 0; qbits--; progress('<'); mpi_free (q); q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); goto next_try; } } else count2 = 0; } while (! ((nprime == pbits) && check_prime (prime, val_2, 5, cb_func, cb_arg))); if (DBG_CIPHER) { progress ('\n'); log_mpidump ("prime ", prime); log_mpidump ("factor q", q); if (need_q_factor) log_mpidump ("factor q0", q_factor); for (i = 0; i < n; i++) log_mpidump ("factor pi", factors[i]); log_debug ("bit sizes: prime=%u, q=%u", mpi_get_nbits (prime), mpi_get_nbits (q)); if (need_q_factor) log_printf (", q0=%u", mpi_get_nbits (q_factor)); for (i = 0; i < n; i++) log_printf (", p%d=%u", i, mpi_get_nbits (factors[i])); log_printf ("\n"); } if (ret_factors) { /* Caller wants the factors. */ factors_new = xtrycalloc (n + 4, sizeof (*factors_new)); if (! factors_new) { err = gpg_err_code_from_errno (errno); goto leave; } if (all_factors) { i = 0; factors_new[i++] = mpi_set_ui (NULL, 2); factors_new[i++] = mpi_copy (q); if (need_q_factor) factors_new[i++] = mpi_copy (q_factor); for(j=0; j < n; j++) factors_new[i++] = mpi_copy (factors[j]); } else { i = 0; if (need_q_factor) { factors_new[i++] = mpi_copy (q_factor); for (; i <= n; i++) factors_new[i] = mpi_copy (factors[i]); } else for (; i < n; i++ ) factors_new[i] = mpi_copy (factors[i]); } } if (g && need_q_factor) err = GPG_ERR_NOT_IMPLEMENTED; else if (g) { /* Create a generator (start with 3). */ gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); factors[n] = q; factors[n + 1] = mpi_alloc_set_ui (2); mpi_sub_ui (pmin1, prime, 1); mpi_set_ui (g, 2); do { mpi_add_ui (g, g, 1); if (DBG_CIPHER) log_printmpi ("checking g", g); else progress('^'); for (i = 0; i < n + 2; i++) { mpi_fdiv_q (tmp, pmin1, factors[i]); /* No mpi_pow(), but it is okay to use this with mod prime. */ mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } if (DBG_CIPHER) progress('\n'); } while (i < n + 2); mpi_free (factors[n+1]); mpi_free (tmp); mpi_free (b); mpi_free (pmin1); } if (! DBG_CIPHER) progress ('\n'); leave: if (pool) { is_locked = !gpgrt_lock_lock (&primepool_lock); for(i = 0; i < m; i++) { if (pool[i]) { for (j=0; j < n; j++) if (pool_in_use[j] == i) break; if (j == n && is_locked) { /* This pooled subprime has not been used. */ save_pool_prime (pool[i], poolrandomlevel); } else mpi_free (pool[i]); } } if (is_locked) err = gpgrt_lock_unlock (&primepool_lock); is_locked = 0; xfree (pool); } xfree (pool_in_use); if (factors) xfree (factors); /* Factors are shallow copies. */ if (perms) xfree (perms); mpi_free (val_2); mpi_free (q); mpi_free (q_factor); if (! err) { *prime_generated = prime; if (ret_factors) *ret_factors = factors_new; } else { if (factors_new) { for (i = 0; factors_new[i]; i++) mpi_free (factors_new[i]); xfree (factors_new); } mpi_free (prime); } return err; } /* Generate a prime used for discrete logarithm algorithms; i.e. this prime will be public and no strong random is required. On success R_PRIME receives a new MPI with the prime. On error R_PRIME is set to NULL and an error code is returned. If RET_FACTORS is not NULL it is set to an allocated array of factors on success or to NULL on error. */ gcry_err_code_t _gcry_generate_elg_prime (int mode, unsigned pbits, unsigned qbits, gcry_mpi_t g, gcry_mpi_t *r_prime, gcry_mpi_t **ret_factors) { *r_prime = NULL; if (ret_factors) *ret_factors = NULL; return prime_generate_internal ((mode == 1), r_prime, pbits, qbits, g, ret_factors, GCRY_WEAK_RANDOM, 0, 0, NULL, NULL); } static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg) { gcry_mpi_t prime, ptest, pminus1, val_2, val_3, result; int i; unsigned int x, step; unsigned int count1, count2; int *mods; /* if ( DBG_CIPHER ) */ /* log_debug ("generate a prime of %u bits ", nbits ); */ if (nbits < 16) log_fatal ("can't generate a prime with less than %d bits\n", 16); mods = xmalloc (no_of_small_prime_numbers * sizeof *mods); /* Make nbits fit into gcry_mpi_t implementation. */ val_2 = mpi_alloc_set_ui( 2 ); val_3 = mpi_alloc_set_ui( 3); prime = secret? mpi_snew (nbits): mpi_new (nbits); result = mpi_alloc_like( prime ); pminus1= mpi_alloc_like( prime ); ptest = mpi_alloc_like( prime ); count1 = count2 = 0; for (;;) { /* try forvever */ int dotcount=0; /* generate a random number */ _gcry_mpi_randomize( prime, nbits, randomlevel ); /* Set high order bit to 1, set low order bit to 1. If we are generating a secret prime we are most probably doing that for RSA, to make sure that the modulus does have the requested key size we set the 2 high order bits. */ mpi_set_highbit (prime, nbits-1); if (secret) mpi_set_bit (prime, nbits-2); mpi_set_bit(prime, 0); /* Calculate all remainders. */ for (i=0; (x = small_prime_numbers[i]); i++ ) mods[i] = mpi_fdiv_r_ui(NULL, prime, x); /* Now try some primes starting with prime. */ for(step=0; step < 20000; step += 2 ) { /* Check against all the small primes we have in mods. */ count1++; for (i=0; (x = small_prime_numbers[i]); i++ ) { while ( mods[i] + step >= x ) mods[i] -= x; if ( !(mods[i] + step) ) break; } if ( x ) continue; /* Found a multiple of an already known prime. */ mpi_add_ui( ptest, prime, step ); /* Do a fast Fermat test now. */ count2++; mpi_sub_ui( pminus1, ptest, 1); mpi_powm( result, val_2, pminus1, ptest ); if ( !mpi_cmp_ui( result, 1 ) ) { /* Not composite, perform stronger tests */ if (is_prime(ptest, 5, &count2 )) { if (!mpi_test_bit( ptest, nbits-1-secret )) { progress('\n'); log_debug ("overflow in prime generation\n"); break; /* Stop loop, continue with a new prime. */ } if (extra_check && extra_check (extra_check_arg, ptest)) { /* The extra check told us that this prime is not of the caller's taste. */ progress ('/'); } else { /* Got it. */ mpi_free(val_2); mpi_free(val_3); mpi_free(result); mpi_free(pminus1); mpi_free(prime); xfree(mods); return ptest; } } } if (++dotcount == 10 ) { progress('.'); dotcount = 0; } } progress(':'); /* restart with a new random value */ } } /**************** * Returns: true if this may be a prime * RM_ROUNDS gives the number of Rabin-Miller tests to run. */ static int check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, gcry_prime_check_func_t cb_func, void *cb_arg) { int i; unsigned int x; unsigned int count=0; /* Check against small primes. */ for (i=0; (x = small_prime_numbers[i]); i++ ) { if ( mpi_divisible_ui( prime, x ) ) return !mpi_cmp_ui (prime, x); } /* A quick Fermat test. */ { gcry_mpi_t result = mpi_alloc_like( prime ); gcry_mpi_t pminus1 = mpi_alloc_like( prime ); mpi_sub_ui( pminus1, prime, 1); mpi_powm( result, val_2, pminus1, prime ); mpi_free( pminus1 ); if ( mpi_cmp_ui( result, 1 ) ) { /* Is composite. */ mpi_free( result ); progress('.'); return 0; } mpi_free( result ); } if (!cb_func || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_MAYBE_PRIME, prime)) { /* Perform stronger tests. */ if ( is_prime( prime, rm_rounds, &count ) ) { if (!cb_func || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_GOT_PRIME, prime)) return 1; /* Probably a prime. */ } } progress('.'); return 0; } /* * Return true if n is probably a prime */ static int is_prime (gcry_mpi_t n, int steps, unsigned int *count) { gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t z = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t nminus1 = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t a2 = mpi_alloc_set_ui( 2 ); gcry_mpi_t q; unsigned i, j, k; int rc = 0; unsigned nbits = mpi_get_nbits( n ); if (steps < 5) /* Make sure that we do at least 5 rounds. */ steps = 5; mpi_sub_ui( nminus1, n, 1 ); /* Find q and k, so that n = 1 + 2^k * q . */ q = mpi_copy ( nminus1 ); k = mpi_trailing_zeros ( q ); mpi_tdiv_q_2exp (q, q, k); for (i=0 ; i < steps; i++ ) { ++*count; if( !i ) { mpi_set_ui( x, 2 ); } else { _gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM ); /* Make sure that the number is smaller than the prime and keep the randomness of the high bit. */ if ( mpi_test_bit ( x, nbits-2) ) { mpi_set_highbit ( x, nbits-2); /* Clear all higher bits. */ } else { mpi_set_highbit( x, nbits-2 ); mpi_clear_bit( x, nbits-2 ); } gcry_assert (mpi_cmp (x, nminus1) < 0 && mpi_cmp_ui (x, 1) > 0); } mpi_powm ( y, x, q, n); if ( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) { for ( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) { mpi_powm(y, y, a2, n); if( !mpi_cmp_ui( y, 1 ) ) goto leave; /* Not a prime. */ } if (mpi_cmp( y, nminus1 ) ) goto leave; /* Not a prime. */ } progress('+'); } rc = 1; /* May be a prime. */ leave: mpi_free( x ); mpi_free( y ); mpi_free( z ); mpi_free( nminus1 ); mpi_free( q ); mpi_free( a2 ); return rc; } /* Given ARRAY of size N with M elements set to true produce a modified array with the next permutation of M elements. Note, that ARRAY is used in a one-bit-per-byte approach. To detected the last permutation it is useful to initialize the array with the first M element set to true and use this test: m_out_of_n (array, m, n); for (i = j = 0; i < n && j < m; i++) if (array[i]) j++; if (j == m) goto ready; This code is based on the algorithm 452 from the "Collected Algorithms From ACM, Volume II" by C. N. Liu and D. T. Tang. */ static void m_out_of_n ( char *array, int m, int n ) { int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0; if( !m || m >= n ) return; /* Need to handle this simple case separately. */ if( m == 1 ) { for (i=0; i < n; i++ ) { if ( array[i] ) { array[i++] = 0; if( i >= n ) i = 0; array[i] = 1; return; } } BUG(); } for (j=1; j < n; j++ ) { if ( array[n-1] == array[n-j-1]) continue; j1 = j; break; } if ( (m & 1) ) { /* M is odd. */ if( array[n-1] ) { if( j1 & 1 ) { k1 = n - j1; k2 = k1+2; if( k2 > n ) k2 = n; goto leave; } goto scan; } k2 = n - j1 - 1; if( k2 == 0 ) { k1 = i; k2 = n - j1; } else if( array[k2] && array[k2-1] ) k1 = n; else k1 = k2 + 1; } else { /* M is even. */ if( !array[n-1] ) { k1 = n - j1; k2 = k1 + 1; goto leave; } if( !(j1 & 1) ) { k1 = n - j1; k2 = k1+2; if( k2 > n ) k2 = n; goto leave; } scan: jp = n - j1 - 1; for (i=1; i <= jp; i++ ) { i1 = jp + 2 - i; if( array[i1-1] ) { if( array[i1-2] ) { k1 = i1 - 1; k2 = n - j1; } else { k1 = i1 - 1; k2 = n + 1 - j1; } goto leave; } } k1 = 1; k2 = n + 1 - m; } leave: /* Now complement the two selected bits. */ array[k1-1] = !array[k1-1]; array[k2-1] = !array[k2-1]; } /* Generate a new prime number of PRIME_BITS bits and store it in PRIME. If FACTOR_BITS is non-zero, one of the prime factors of (prime - 1) / 2 must be FACTOR_BITS bits long. If FACTORS is non-zero, allocate a new, NULL-terminated array holding the prime factors and store it in FACTORS. FLAGS might be used to influence the prime number generation process. */ gcry_err_code_t _gcry_prime_generate (gcry_mpi_t *prime, unsigned int prime_bits, unsigned int factor_bits, gcry_mpi_t **factors, gcry_prime_check_func_t cb_func, void *cb_arg, gcry_random_level_t random_level, unsigned int flags) { gcry_err_code_t rc = 0; gcry_mpi_t *factors_generated = NULL; gcry_mpi_t prime_generated = NULL; unsigned int mode = 0; if (!prime) return GPG_ERR_INV_ARG; *prime = NULL; if (flags & GCRY_PRIME_FLAG_SPECIAL_FACTOR) mode = 1; /* Generate. */ rc = prime_generate_internal ((mode==1), &prime_generated, prime_bits, factor_bits, NULL, factors? &factors_generated : NULL, random_level, flags, 1, cb_func, cb_arg); if (!rc && cb_func) { /* Additional check. */ if ( !cb_func (cb_arg, GCRY_PRIME_CHECK_AT_FINISH, prime_generated)) { /* Failed, deallocate resources. */ unsigned int i; mpi_free (prime_generated); if (factors) { for (i = 0; factors_generated[i]; i++) mpi_free (factors_generated[i]); xfree (factors_generated); } rc = GPG_ERR_GENERAL; } } if (!rc) { if (factors) *factors = factors_generated; *prime = prime_generated; } return rc; } /* Check whether the number X is prime. */ gcry_err_code_t _gcry_prime_check (gcry_mpi_t x, unsigned int flags) { (void)flags; switch (mpi_cmp_ui (x, 2)) { case 0: return 0; /* 2 is a prime */ case -1: return GPG_ERR_NO_PRIME; /* Only numbers > 1 are primes. */ } /* We use 64 rounds because the prime we are going to test is not guaranteed to be a random one. */ if (check_prime (x, mpi_const (MPI_C_TWO), 64, NULL, NULL)) return 0; return GPG_ERR_NO_PRIME; } /* Find a generator for PRIME where the factorization of (prime-1) is in the NULL terminated array FACTORS. Return the generator as a newly allocated MPI in R_G. If START_G is not NULL, use this as s atart for the search. Returns 0 on success.*/ gcry_err_code_t _gcry_prime_group_generator (gcry_mpi_t *r_g, gcry_mpi_t prime, gcry_mpi_t *factors, gcry_mpi_t start_g) { gcry_mpi_t tmp, b, pmin1, g; int first, i, n; if (!r_g) return GPG_ERR_INV_ARG; *r_g = NULL; if (!factors || !prime) return GPG_ERR_INV_ARG; for (n=0; factors[n]; n++) ; if (n < 2) return GPG_ERR_INV_ARG; tmp = mpi_new (0); b = mpi_new (0); pmin1 = mpi_new (0); g = start_g? mpi_copy (start_g) : mpi_set_ui (NULL, 3); /* Extra sanity check - usually disabled. */ /* mpi_set (tmp, factors[0]); */ /* for(i = 1; i < n; i++) */ /* mpi_mul (tmp, tmp, factors[i]); */ /* mpi_add_ui (tmp, tmp, 1); */ /* if (mpi_cmp (prime, tmp)) */ /* return gpg_error (GPG_ERR_INV_ARG); */ mpi_sub_ui (pmin1, prime, 1); first = 1; do { if (first) first = 0; else mpi_add_ui (g, g, 1); if (DBG_CIPHER) log_printmpi ("checking g", g); else progress('^'); for (i = 0; i < n; i++) { mpi_fdiv_q (tmp, pmin1, factors[i]); mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } if (DBG_CIPHER) progress('\n'); } while (i < n); _gcry_mpi_release (tmp); _gcry_mpi_release (b); _gcry_mpi_release (pmin1); *r_g = g; return 0; } /* Convenience function to release the factors array. */ void _gcry_prime_release_factors (gcry_mpi_t *factors) { if (factors) { int i; for (i=0; factors[i]; i++) mpi_free (factors[i]); xfree (factors); } } /* Helper for _gcry_derive_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 = 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_has_sign (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 = 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; } /* Generate the two prime used for DSA using the algorithm specified in FIPS 186-2. PBITS is the desired length of the prime P and a QBITS the length of the prime Q. If SEED is not supplied and SEEDLEN is 0 the function generates an appropriate SEED. On success the generated primes are stored at R_Q and R_P, the counter value is stored at R_COUNTER and the seed actually used for generation is stored at R_SEED and R_SEEDVALUE. */ gpg_err_code_t _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, const void *seed, size_t seedlen, gcry_mpi_t *r_q, gcry_mpi_t *r_p, int *r_counter, void **r_seed, size_t *r_seedlen) { gpg_err_code_t ec; unsigned char seed_help_buffer[160/8]; /* Used to hold a generated SEED. */ unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ unsigned char digest[160/8]; /* Helper buffer for SHA-1 digest. */ gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ gcry_mpi_t tmpval = NULL; /* Helper variable. */ int i; unsigned char value_u[160/8]; int value_n, value_b, value_k; int counter; gcry_mpi_t value_w = NULL; gcry_mpi_t value_x = NULL; gcry_mpi_t prime_q = NULL; gcry_mpi_t prime_p = NULL; /* FIPS 186-2 allows only for 1024/160 bit. */ if (pbits != 1024 || qbits != 160) return GPG_ERR_INV_KEYLEN; if (!seed && !seedlen) ; /* No seed value given: We are asked to generate it. */ else if (!seed || seedlen < qbits/8) return GPG_ERR_INV_ARG; /* Allocate a buffer to later compute SEED+some_increment. */ seed_plus = xtrymalloc (seedlen < 20? 20:seedlen); if (!seed_plus) { ec = gpg_err_code_from_syserror (); goto leave; } val_2 = mpi_alloc_set_ui (2); value_n = (pbits - 1) / qbits; value_b = (pbits - 1) - value_n * qbits; value_w = mpi_new (pbits); value_x = mpi_new (pbits); restart: /* Generate Q. */ for (;;) { /* Step 1: Generate a (new) seed unless one has been supplied. */ if (!seed) { seedlen = sizeof seed_help_buffer; _gcry_create_nonce (seed_help_buffer, seedlen); seed = seed_help_buffer; } /* Step 2: U = sha1(seed) ^ sha1((seed+1) mod 2^{qbits}) */ memcpy (seed_plus, seed, seedlen); for (i=seedlen-1; i >= 0; i--) { seed_plus[i]++; if (seed_plus[i]) break; } _gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen); _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); for (i=0; i < sizeof value_u; i++) value_u[i] ^= digest[i]; /* Step 3: Form q from U */ _gcry_mpi_release (prime_q); prime_q = NULL; ec = _gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, value_u, sizeof value_u, NULL); if (ec) goto leave; mpi_set_highbit (prime_q, qbits-1 ); mpi_set_bit (prime_q, 0); /* Step 4: Test whether Q is prime using 64 round of Rabin-Miller. */ if (check_prime (prime_q, val_2, 64, NULL, NULL)) break; /* Yes, Q is prime. */ /* Step 5. */ seed = NULL; /* Force a new seed at Step 1. */ } /* Step 6. Note that we do no use an explicit offset but increment SEED_PLUS accordingly. SEED_PLUS is currently SEED+1. */ counter = 0; /* Generate P. */ prime_p = mpi_new (pbits); for (;;) { /* Step 7: For k = 0,...n let V_k = sha1(seed+offset+k) mod 2^{qbits} Step 8: W = V_0 + V_1*2^160 + ... + V_{n-1}*2^{(n-1)*160} + (V_{n} mod 2^b)*2^{n*160} */ mpi_set_ui (value_w, 0); for (value_k=0; value_k <= value_n; value_k++) { /* There is no need to have an explicit offset variable: In the first round we shall have an offset of 2, this is achieved by using SEED_PLUS which is already at SEED+1, thus we just need to increment it once again. The requirement for the next round is to update offset by N, which we implictly did at the end of this loop, and then to add one; this one is the same as in the first round. */ for (i=seedlen-1; i >= 0; i--) { seed_plus[i]++; if (seed_plus[i]) break; } _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); _gcry_mpi_release (tmpval); tmpval = NULL; ec = _gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, digest, sizeof digest, NULL); if (ec) goto leave; if (value_k == value_n) mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ mpi_lshift (tmpval, tmpval, value_k*qbits); mpi_add (value_w, value_w, tmpval); } /* Step 8 continued: X = W + 2^{L-1} */ mpi_set_ui (value_x, 0); mpi_set_highbit (value_x, pbits-1); mpi_add (value_x, value_x, value_w); /* Step 9: c = X mod 2q, p = X - (c - 1) */ mpi_mul_2exp (tmpval, prime_q, 1); mpi_mod (tmpval, value_x, tmpval); mpi_sub_ui (tmpval, tmpval, 1); mpi_sub (prime_p, value_x, tmpval); /* Step 10: If p < 2^{L-1} skip the primality test. */ /* Step 11 and 12: Primality test. */ if (mpi_get_nbits (prime_p) >= pbits-1 && check_prime (prime_p, val_2, 64, NULL, NULL) ) break; /* Yes, P is prime, continue with Step 15. */ /* Step 13: counter = counter + 1, offset = offset + n + 1. */ counter++; /* Step 14: If counter >= 2^12 goto Step 1. */ if (counter >= 4096) goto restart; } /* Step 15: Save p, q, counter and seed. */ /* log_debug ("fips186-2 pbits p=%u q=%u counter=%d\n", */ /* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */ /* log_printhex("fips186-2 seed:", seed, seedlen); */ /* log_mpidump ("fips186-2 prime p", prime_p); */ /* log_mpidump ("fips186-2 prime q", prime_q); */ if (r_q) { *r_q = prime_q; prime_q = NULL; } if (r_p) { *r_p = prime_p; prime_p = NULL; } if (r_counter) *r_counter = counter; if (r_seed && r_seedlen) { memcpy (seed_plus, seed, seedlen); *r_seed = seed_plus; seed_plus = NULL; *r_seedlen = seedlen; } leave: _gcry_mpi_release (tmpval); _gcry_mpi_release (value_x); _gcry_mpi_release (value_w); _gcry_mpi_release (prime_p); _gcry_mpi_release (prime_q); xfree (seed_plus); _gcry_mpi_release (val_2); return ec; } -/* WARNING: The code below has not yet been tested! However, it is - not yet used. We need to wait for FIPS 186-3 final and for test - vectors. - - Generate the two prime used for DSA using the algorithm specified - in FIPS 186-3, A.1.1.2. PBITS is the desired length of the prime P - and a QBITS the length of the prime Q. If SEED is not supplied and - SEEDLEN is 0 the function generates an appropriate SEED. On - success the generated primes are stored at R_Q and R_P, the counter - value is stored at R_COUNTER and the seed actually used for - generation is stored at R_SEED and R_SEEDVALUE. The hash algorithm - used is stored at R_HASHALGO. - - Note that this function is very similar to the fips186_2 code. Due - to the minor differences, other buffer sizes and for documentarion, - we use a separate function. -*/ +/* WARNING: The code below has not yet been tested! + * + * Generate the two prime used for DSA using the algorithm specified + * in FIPS 186-3, A.1.1.2. PBITS is the desired length of the prime P + * and a QBITS the length of the prime Q. If SEED is not supplied and + * SEEDLEN is 0 the function generates an appropriate SEED. On + * success the generated primes are stored at R_Q and R_P, the counter + * value is stored at R_COUNTER and the seed actually used for + * generation is stored at R_SEED and R_SEEDVALUE. The hash algorithm + * used is stored at R_HASHALGO. + * + * Note that this function is very similar to the fips186_2 code. Due + * to the minor differences, other buffer sizes and for documentarion, + * we use a separate function. + */ gpg_err_code_t _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, const void *seed, size_t seedlen, gcry_mpi_t *r_q, gcry_mpi_t *r_p, int *r_counter, void **r_seed, size_t *r_seedlen, int *r_hashalgo) { gpg_err_code_t ec; unsigned char seed_help_buffer[256/8]; /* Used to hold a generated SEED. */ unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ unsigned char digest[256/8]; /* Helper buffer for SHA-2 digest. */ gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ gcry_mpi_t tmpval = NULL; /* Helper variable. */ int hashalgo; /* The id of the Approved Hash Function. */ int i; unsigned char value_u[256/8]; int value_n, value_b, value_j; int counter; gcry_mpi_t value_w = NULL; gcry_mpi_t value_x = NULL; gcry_mpi_t prime_q = NULL; gcry_mpi_t prime_p = NULL; gcry_assert (sizeof seed_help_buffer == sizeof digest && sizeof seed_help_buffer == sizeof value_u); /* Step 1: Check the requested prime lengths. */ /* Note that due to the size of our buffers QBITS is limited to 256. */ if (pbits == 2048 && qbits == 224) hashalgo = GCRY_MD_SHA224; else if (pbits == 2048 && qbits == 256) hashalgo = GCRY_MD_SHA256; else if (pbits == 3072 && qbits == 256) hashalgo = GCRY_MD_SHA256; else return GPG_ERR_INV_KEYLEN; /* Also check that the hash algorithm is available. */ ec = _gcry_md_test_algo (hashalgo); if (ec) return ec; gcry_assert (qbits/8 <= sizeof digest); gcry_assert (_gcry_md_get_algo_dlen (hashalgo) == qbits/8); /* Step 2: Check seedlen. */ if (!seed && !seedlen) ; /* No seed value given: We are asked to generate it. */ else if (!seed || seedlen < qbits/8) return GPG_ERR_INV_ARG; /* Allocate a buffer to later compute SEED+some_increment and a few helper variables. */ seed_plus = xtrymalloc (seedlen < sizeof seed_help_buffer? sizeof seed_help_buffer : seedlen); if (!seed_plus) { ec = gpg_err_code_from_syserror (); goto leave; } val_2 = mpi_alloc_set_ui (2); value_w = mpi_new (pbits); value_x = mpi_new (pbits); /* Step 3: n = \lceil L / outlen \rceil - 1 */ value_n = (pbits + qbits - 1) / qbits - 1; /* Step 4: b = L - 1 - (n * outlen) */ value_b = pbits - 1 - (value_n * qbits); restart: /* Generate Q. */ for (;;) { /* Step 5: Generate a (new) seed unless one has been supplied. */ if (!seed) { seedlen = qbits/8; gcry_assert (seedlen <= sizeof seed_help_buffer); _gcry_create_nonce (seed_help_buffer, seedlen); seed = seed_help_buffer; } /* Step 6: U = hash(seed) */ _gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen); /* Step 7: q = 2^{N-1} + U + 1 - (U mod 2) */ if ( !(value_u[qbits/8-1] & 0x01) ) { for (i=qbits/8-1; i >= 0; i--) { value_u[i]++; if (value_u[i]) break; } } _gcry_mpi_release (prime_q); prime_q = NULL; ec = _gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, value_u, qbits/8, NULL); if (ec) goto leave; mpi_set_highbit (prime_q, qbits-1 ); /* Step 8: Test whether Q is prime using 64 round of Rabin-Miller. According to table C.1 this is sufficient for all supported prime sizes (i.e. up 3072/256). */ if (check_prime (prime_q, val_2, 64, NULL, NULL)) break; /* Yes, Q is prime. */ /* Step 8. */ seed = NULL; /* Force a new seed at Step 5. */ } /* Step 11. Note that we do no use an explicit offset but increment SEED_PLUS accordingly. */ memcpy (seed_plus, seed, seedlen); counter = 0; /* Generate P. */ prime_p = mpi_new (pbits); for (;;) { /* Step 11.1: For j = 0,...n let V_j = hash(seed+offset+j) Step 11.2: W = V_0 + V_1*2^outlen + ... + V_{n-1}*2^{(n-1)*outlen} + (V_{n} mod 2^b)*2^{n*outlen} */ mpi_set_ui (value_w, 0); for (value_j=0; value_j <= value_n; value_j++) { /* There is no need to have an explicit offset variable: In the first round we shall have an offset of 1 and a j of 0. This is achieved by incrementing SEED_PLUS here. For the next round offset is implicitly updated by using SEED_PLUS again. */ for (i=seedlen-1; i >= 0; i--) { seed_plus[i]++; if (seed_plus[i]) break; } _gcry_md_hash_buffer (hashalgo, digest, seed_plus, seedlen); _gcry_mpi_release (tmpval); tmpval = NULL; ec = _gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, digest, qbits/8, NULL); if (ec) goto leave; if (value_j == value_n) mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ mpi_lshift (tmpval, tmpval, value_j*qbits); mpi_add (value_w, value_w, tmpval); } /* Step 11.3: X = W + 2^{L-1} */ mpi_set_ui (value_x, 0); mpi_set_highbit (value_x, pbits-1); mpi_add (value_x, value_x, value_w); /* Step 11.4: c = X mod 2q */ mpi_mul_2exp (tmpval, prime_q, 1); mpi_mod (tmpval, value_x, tmpval); /* Step 11.5: p = X - (c - 1) */ mpi_sub_ui (tmpval, tmpval, 1); mpi_sub (prime_p, value_x, tmpval); /* Step 11.6: If p < 2^{L-1} skip the primality test. */ /* Step 11.7 and 11.8: Primality test. */ if (mpi_get_nbits (prime_p) >= pbits-1 && check_prime (prime_p, val_2, 64, NULL, NULL) ) break; /* Yes, P is prime, continue with Step 15. */ /* Step 11.9: counter = counter + 1, offset = offset + n + 1. If counter >= 4L goto Step 5. */ counter++; if (counter >= 4*pbits) goto restart; } /* Step 12: Save p, q, counter and seed. */ -/* - log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", - mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); - log_printhex ("fips186-3 seed", seed, seedlen); - log_printmpi ("fips186-3 p", prime_p); - log_printmpi ("fips186-3 q", prime_q); -*/ + /* log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", */ + /* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */ + /* log_printhex ("fips186-3 seed", seed, seedlen); */ + /* log_printmpi ("fips186-3 p", prime_p); */ + /* log_printmpi ("fips186-3 q", prime_q); */ + if (r_q) { *r_q = prime_q; prime_q = NULL; } if (r_p) { *r_p = prime_p; prime_p = NULL; } if (r_counter) *r_counter = counter; if (r_seed && r_seedlen) { memcpy (seed_plus, seed, seedlen); *r_seed = seed_plus; seed_plus = NULL; *r_seedlen = seedlen; } if (r_hashalgo) *r_hashalgo = hashalgo; leave: _gcry_mpi_release (tmpval); _gcry_mpi_release (value_x); _gcry_mpi_release (value_w); _gcry_mpi_release (prime_p); _gcry_mpi_release (prime_q); xfree (seed_plus); _gcry_mpi_release (val_2); return ec; } diff --git a/tests/fips186-dsa.c b/tests/fips186-dsa.c index 10b18abb..5ee829ea 100644 --- a/tests/fips186-dsa.c +++ b/tests/fips186-dsa.c @@ -1,465 +1,474 @@ /* fips186-dsa.c - FIPS 186 DSA tests * Copyright (C) 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 * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #ifdef _GCRYPT_IN_LIBGCRYPT # include "../src/gcrypt-int.h" #else # include #endif #define my_isascii(c) (!((c) & 0x80)) #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) static int verbose; static int error_count; static void info (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); } static void fail (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); error_count++; } static void die (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); exit (1); } 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 gcry_mpi_t mpi_from_string (const char *string) { gpg_error_t err; gcry_mpi_t a; err = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, string, 0, NULL); if (err) die ("error converting string to mpi: %s\n", gpg_strerror (err)); return a; } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * data_from_hex (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = gcry_xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) die ("error parsing hex string `%s'\n", string); ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } static void extract_cmp_mpi (gcry_sexp_t sexp, const char *name, const char *expected) { gcry_sexp_t l1; gcry_mpi_t a, b; l1 = gcry_sexp_find_token (sexp, name, 0); a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); b = mpi_from_string (expected); if (!a) fail ("parameter \"%s\" missing in key\n", name); else if ( gcry_mpi_cmp (a, b) ) fail ("parameter \"%s\" does not match expected value\n", name); gcry_mpi_release (b); gcry_mpi_release (a); gcry_sexp_release (l1); } static void extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected) { gcry_sexp_t l1; const void *a; size_t alen; void *b; size_t blen; l1 = gcry_sexp_find_token (sexp, name, 0); a = gcry_sexp_nth_data (l1, 1, &alen); b = data_from_hex (expected, &blen); if (!a) fail ("parameter \"%s\" missing in key\n", name); else if ( alen != blen || memcmp (a, b, alen) ) fail ("parameter \"%s\" does not match expected value\n", name); gcry_free (b); gcry_sexp_release (l1); } static void extract_cmp_int (gcry_sexp_t sexp, const char *name, int expected) { gcry_sexp_t l1; char *a; l1 = gcry_sexp_find_token (sexp, name, 0); a = gcry_sexp_nth_string (l1, 1); if (!a) fail ("parameter \"%s\" missing in key\n", name); else if ( strtoul (a, NULL, 10) != expected ) fail ("parameter \"%s\" does not match expected value\n", name); gcry_free (a); gcry_sexp_release (l1); } static void check_dsa_gen_186_2 (void) { static struct { int nbits; const char *p, *q, *g; const char *seed; int counter; const char *h; } tbl[] = { /* These tests are from FIPS 186-2, B.3.1. */ { 1024, "d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69", "9c916d121de9a03f71fb21bc2e1c0d116f065a4f", "8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44", "0cb1990c1fd3626055d7a0096f8fa99807399871", 98, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002" }, { 1024, "f5c73304080353357de1b5967597c27d65f70aa2fe9b6aed1d0afc2b499adf22f" "8e37937096d88548ac36c4a067f8353c7fed73f96f0d688b19b0624aedbae5dbb" "0ee8835a4c269288c0e1d69479e701ee266bb767af39d748fe7d6afc73fdf44be" "3eb6e661e599670061203e75fc8b3dbd59e40b54f358d0097013a0f3867f9", "f8751166cf4f6f3b07c081fd2a9071f23ca1988d", "1e288a442e02461c418ed67a66d24cacbeb8936fbde62ff995f5fd569dee6be62" "4e4f0f9f8c8093f5d192ab3b3f9ae3f2665d95d27fb10e382f45cd356e7f4eb7a" "665db432113ed06478f93b7cf188ec7a1ee97aec8f91ea7bfceaf8b6e7e5a349c" "4ad3225362ef440c57cbc6e69df15b6699caac85f733555075f04781b2b33", "34b3520d45d240a8861b82c8b61ffa16e67b5cce", 622, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, { 1024, "c6c6f4f4eed927fb1c3b0c81010967e530658e6f9698ebe058b4f47b2dc8fcbc7" "b69296b9e8b6cf55681181fe72492668061b262b0046a0d409902e269b0cb69a4" "55ed1a086caf41927f5912bf0e0cbc45ee81a4f98bf6146f6168a228aec80e9cc" "1162d6f6aa412efe82d4f18b95e34ab790daac5bd7aef0b22fa08ba5dbaad", "d32b29f065c1394a30490b6fcbf812a32a8634ab", "06f973c879e2e89345d0ac04f9c34ad69b9eff1680f18d1c8f3e1596c2e8fa8e1" "ecef6830409e9012d4788bef6ec7414d09c981b47c941b77f39dfc49caff5e714" "c97abe25a7a8b5d1fe88700bb96eff91cca64d53700a28b1146d81bad1212d231" "80154c95a01f5aeebb553a8365c38a5ebe05539b51734233776ce9aff98b2", "b6ec750da2f824cb42c5f7e28c81350d97f75125", 185, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, { 1024, "b827a9dc9221a6ed1bec7b64d61232aacb2812f888b0a0b3a95033d7a22e77d0b" "ff23bfeed0fb1281b21b8ff7421f0c727d1fb8aa2b843d6885f067e763f83d41f" "d800ab15a7e2b12f71ec2058ee7bd62cd72c26989b272e519785da57bfa1f974b" "c652e1a2d6cfb68477de5635fd019b37add656cff0b802558b31b6d2851e5", "de822c03445b77cec4ad3a6fb0ca39ff97059ddf", "65a9e2d43a378d7063813104586868cacf2fccd51aec1e0b6af8ba3e66dee6371" "681254c3fb5e3929d65e3c4bcd20abd4ddc7cf815623e17b9fc92f02b8d44278b" "848480ffd193104cf5612639511e45bd247708ff6028bd3824f8844c263b46c69" "1f2076f8cd13c5d0be95f1f2a1a17ab1f7e5bc73500bac27d57b473ba9748", "cd2221dd73815a75224e9fde7faf52829b81ac7a", 62, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, { 1024, "898a8d93e295c8ef2ffd46976225a1543640640d155a576fafa0be32136165803" "ba2eff2782a2be75cc9ec65db6bd3238cca695b3a5a14726a2a314775c377d891" "354b3de6c89e714a05599ca04132c987f889f72c4fe298ccb31f711c03b07e1d9" "8d72af590754cf3847398b60cecd55a4611692b308809560a83880404c227", "c6d786643d2acfc6b8d576863fda8cfbfbd5e03f", "2fd38b8d21c58e8fb5315a177b8d5dc4c450d574e69348b7b9da367c26e72438d" "af8372e7f0bee84ef5dcbbc3727194a2228431192f1779be24837f22a0e14d10d" "5344da1b8b403df9f9b2655095b3d0f67418ed6cd989f35aa4232e4b7001764fb" "e85d6b2c716980f13272fc4271ac1e234f7e24c023cfc2d2dc0aa1e9af2fb", "73483e697599871af983a281e3afa22e0ed86b68", 272, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, /* These tests are generated by the OpenSSL FIPS version. */ { 1024, "A404363903FDCE86839BCFD953AAD2DA2B0E70CAED3B5FF5D68F15A1C4BB0A793C" "A9D58FC956804C5901DE0AF99F345ED1A8617C687864BAC044B7C3C3E732A2B255" "EC986AA76EA8CB0E0815B3E0E605650AF7D8058EE7E8EBCDEFFDAB8100D3FC1033" "11BA3AB232EF06BB74BA9A949EC0C7ED324C19B202F4AB725BBB4080C9", "C643946CEA8748E12D430C48DB038F9165814389", "59B7E7BA0033CCE8E6837173420FBB382A784D4154A3C166043F5A68CB92945D16" "892D4CC5585F2D28C780E75A6C20A379E2B58304C1E5FC0D8C15E4E89C4498C8BC" "B90FB36ED8DC0489B9D0BC09EC4411FB0BFADF25485EEAB6700BE0ACF5C44A6ED7" "44A015382FF9B8DA7EAA00DEA135FADC59212DBBFFC1537336FA4B7225", "02708ab36e3f0bfd67ec3b8bd8829d03b84f56bd", 50, "02" }, { 1024, "9C664033DB8B203D826F896D2293C62EF9351D5CFD0F4C0AD7EFDA4DDC7F15987" "6A3C68CAB2586B44FD1BD4DEF7A17905D88D321DD77C4E1720D848CA21D79F9B3" "D8F537338E09B44E9F481E8DA3C56569F63146596A050EF8FAEE8ACA32C666450" "04F675C8806EB4025B0A5ECC39CE89983EA40A183A7CF5208BA958045ABD5", "AD0D8CBA369AF6CD0D2BAC0B4CFCAF0A1F9BCDF7", "74D717F7092A2AF725FDD6C2561D1DBE5AEE40203C638BA8B9F49003857873701" "95A44E515C4E8B344F5CDC7F4A6D38097CD57675E7643AB9700692C69F0A99B0E" "039FDDDFCA8CEB607BDB4ADF2834DE1690F5823FC8199FB8F6F29E5A583B6786A" "C14C7E67106C3B30568CBB9383F89287D578159778EB18216799D16D46498", "6481a12a50384888ee84b61024f7c9c685d6ac96", 289, "02" }, { 1024, "B0DFB602EB8462B1DC8C2214A52B587D3E6842CCF1C38D0F7C7F967ED30CF6828" "1E2675B3BAB594755FB1634E66B4C23936F0725A358F8DFF3C307E2601FD66D63" "5B17270450C50BD2BEC29E0E9A471DF1C15B0191517952268A2763D4BD28B8503" "B3399686272B76B11227F693D7833105EF70C2289C3194CF4527024B272DF", "EA649C04911FAB5A41440287A517EF752A40354B", "88C5A4563ECB949763E0B696CD04B21321360F54C0EE7B23E2CEDC30E9E486162" "01BFB1619E7C54B653D1F890C50E04B29205F5E3E2F93A13B0751AF25491C5194" "93C09DDF6B9C173B3846DFB0E7A5C870BBFC78419260C90E20315410691C8326C" "858D7063E7921F3F601158E912C7EE487FF259202BEEB10F6D9E99190F696", "5bf9d17bc62fbbf3d569c92bd4505586b2e5ef1a", 626, "02" }, { 1024, "F783C08D7F9463E48BA87893805C4B34B63C85DF7EBDD9EBEE94DB4AF4E4A415C" "F0F3793AE55096BA1199598798FA8403B28DED7F7C7AFD54FD535861A0150EF4D" "5871465B13837CCF46BEB0A22F8D38DC7D6AE0E14A3845FD0C027CFA97791B977" "CE2808BAD9B43CE69390C0F40016056722D82C0D7B1B27413D026A39D7DAD", "A40D9EE456AED4C8A653FDB47B6629C0B843FE8F", "DF876263E21F263AE6DA57409BD517DCEADB9216048F066D6B58867F8E59A5EEE" "700283A946C1455534618979BE6C227673C1B803910262BD93BC94D5089850614" "F3E29AB64E8C989A7E3E28FE670FFA3EE21DEEEC1AB0B60E1D8E2AA39663BADD7" "2C9F957D7F3D4F17D9FDAD050EB373A6DEFD09F5DA752EAFE046836E14B67", "8a9a57706f69f4f566252cdf6d5cbfdf2020150b", 397, "02" }, { 1024, "D40E4F6461E145859CCF60FD57962840BD75FFF12C22F76626F566842252AD068" "29745F0147056354F6C016CF12762B0E331787925B8128CF5AF81F9B176A51934" "96D792430FF83C7B79BD595BDA10787B34600787FA552EFE3662F37B99AAD3F3A" "093732680A01345192A19BECCE6BF5D498E44ED6BED5B0BA72AAD49E8276B", "D12F1BD0AA78B99247FD9F18EAFEE5C136686EA5", "468EBD20C99449C1E440E6F8E452C6A6BC7551C555FE5E94996E20CFD4DA3B9CC" "58499D6CC2374CCF9C392715A537DE10CFCA8A6A37AFBD187CF6B88D26881E5F5" "7521D9D2C9BBA51E7B87B070BBE73F5C5FE31E752CAF88183516D8503BAAC1159" "928EF50DEE52D96F396B93FB4138D786464C315401A853E57C9A0F9D25839", "30b3599944a914a330a3f49d11ec88f555422aef", 678, "02" } }; gpg_error_t err; int tno; gcry_sexp_t key_spec, key, pub_key, sec_key, seed_values; gcry_sexp_t l1; for (tno = 0; tno < DIM (tbl); tno++) { if (verbose) info ("generating FIPS 186-2 test key %d\n", tno); { void *data; size_t datalen; data = data_from_hex (tbl[tno].seed, &datalen); err = gcry_sexp_build (&key_spec, NULL, "(genkey (dsa (nbits %d)(use-fips186-2)" "(derive-parms(seed %b))))", tbl[tno].nbits, (int)datalen, data); gcry_free (data); } if (err) die ("error creating S-expression %d: %s\n", tno, gpg_strerror (err)); err = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (err) { fail ("error generating key %d: %s\n", tno, gpg_strerror (err)); continue; } if (verbose > 1) show_sexp ("generated key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) fail ("public part missing in key %d\n", tno); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) fail ("private part missing in key %d\n", tno); l1 = gcry_sexp_find_token (key, "misc-key-info", 0); if (!l1) fail ("misc_key_info part missing in key %d\n", tno); seed_values = gcry_sexp_find_token (l1, "seed-values", 0); if (!seed_values) fail ("seed-values part missing in key %d\n", tno); gcry_sexp_release (l1); extract_cmp_mpi (sec_key, "p", tbl[tno].p); extract_cmp_mpi (sec_key, "q", tbl[tno].q); extract_cmp_mpi (sec_key, "g", tbl[tno].g); extract_cmp_data (seed_values, "seed", tbl[tno].seed); extract_cmp_int (seed_values, "counter", tbl[tno].counter); extract_cmp_mpi (seed_values, "h", tbl[tno].h); gcry_sexp_release (seed_values); gcry_sexp_release (sec_key); gcry_sexp_release (pub_key); gcry_sexp_release (key); } } +static void +check_dsa_gen_186_3 (void) +{ + /* FIXME: Needs to be implemented. */ + if (verbose) + info ("generating FIPS 186-3 test keys - skipped\n"); +} + int main (int argc, char **argv) { int debug = 0; if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; else if (argc > 1 && !strcmp (argv[1], "--debug")) { verbose = 2; debug = 1; } gcry_control (GCRYCTL_DISABLE_SECMEM, 0); - if (!gcry_check_version ("1.4.4")) + if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (debug) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); /* No valuable keys are create, so we can speed up our RNG. */ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); check_dsa_gen_186_2 (); + check_dsa_gen_186_3 (); return error_count ? 1 : 0; } diff --git a/tests/pubkey.c b/tests/pubkey.c index ae5eea2d..26bd9e3a 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -1,1203 +1,1206 @@ /* pubkey.c - Public key encryption/decryption tests * Copyright (C) 2001, 2002, 2003, 2005 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 * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "../src/gcrypt-int.h" #define my_isascii(c) (!((c) & 0x80)) #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) /* Sample RSA keys, taken from basic.c. */ static const char sample_private_key_1[] = "(private-key\n" " (openpgp-rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" " (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n" " (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9" "35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)\n" " (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n" " )\n" ")\n"; /* The same key as above but without p, q and u to test the non CRT case. */ static const char sample_private_key_1_1[] = "(private-key\n" " (openpgp-rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" " )\n" ")\n"; /* The same key as above but just without q to test the non CRT case. This should fail. */ static const char sample_private_key_1_2[] = "(private-key\n" " (openpgp-rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" " (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n" " (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n" " )\n" ")\n"; static const char sample_public_key_1[] = "(public-key\n" " (rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " )\n" ")\n"; static int verbose; static int error_count; static void die (const char *format, ...) { va_list arg_ptr ; va_start( arg_ptr, format ) ; vfprintf (stderr, format, arg_ptr ); va_end(arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); exit (1); } static void fail (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); error_count++; } static void info (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); } 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); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * data_from_hex (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = gcry_xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) die ("error parsing hex string `%s'\n", string); ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } static void extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected) { gcry_sexp_t l1; const void *a; size_t alen; void *b; size_t blen; l1 = gcry_sexp_find_token (sexp, name, 0); a = gcry_sexp_nth_data (l1, 1, &alen); b = data_from_hex (expected, &blen); if (!a) fail ("parameter \"%s\" missing in key\n", name); else if ( alen != blen || memcmp (a, b, alen) ) { fail ("parameter \"%s\" does not match expected value\n", name); if (verbose) { info ("expected: %s\n", expected); show_sexp ("sexp: ", sexp); } } gcry_free (b); gcry_sexp_release (l1); } static void check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey, gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code) { gcry_sexp_t plain1, cipher, l; gcry_mpi_t x0, x1; int rc; int have_flags; /* Extract data from plaintext. */ l = gcry_sexp_find_token (plain0, "value", 0); x0 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l); /* Encrypt data. */ rc = gcry_pk_encrypt (&cipher, plain0, pkey); if (rc) die ("encryption failed: %s\n", gcry_strerror (rc)); l = gcry_sexp_find_token (cipher, "flags", 0); have_flags = !!l; gcry_sexp_release (l); /* Decrypt data. */ rc = gcry_pk_decrypt (&plain1, cipher, skey); gcry_sexp_release (cipher); if (rc) { if (decrypt_fail_code && gpg_err_code (rc) == decrypt_fail_code) { gcry_mpi_release (x0); return; /* This is the expected failure code. */ } die ("decryption failed: %s\n", gcry_strerror (rc)); } /* Extract decrypted data. Note that for compatibility reasons, the output of gcry_pk_decrypt depends on whether a flags lists (even if empty) occurs in its input data. Because we passed the output of encrypt directly to decrypt, such a flag value won't be there as of today. We check it anyway. */ l = gcry_sexp_find_token (plain1, "value", 0); if (l) { if (!have_flags) die ("compatibility mode of pk_decrypt broken\n"); gcry_sexp_release (plain1); x1 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l); } else { if (have_flags) die ("compatibility mode of pk_decrypt broken\n"); x1 = gcry_sexp_nth_mpi (plain1, 0, GCRYMPI_FMT_USG); gcry_sexp_release (plain1); } /* Compare. */ if (gcry_mpi_cmp (x0, x1)) die ("data corrupted\n"); gcry_mpi_release (x0); gcry_mpi_release (x1); } static void check_keys (gcry_sexp_t pkey, gcry_sexp_t skey, unsigned int nbits_data, gpg_err_code_t decrypt_fail_code) { gcry_sexp_t plain; gcry_mpi_t x; int rc; /* Create plain text. */ x = gcry_mpi_new (nbits_data); gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM); rc = gcry_sexp_build (&plain, NULL, "(data (flags raw) (value %m))", x); if (rc) die ("converting data for encryption failed: %s\n", gcry_strerror (rc)); check_keys_crypt (pkey, skey, plain, decrypt_fail_code); gcry_sexp_release (plain); gcry_mpi_release (x); /* Create plain text. */ x = gcry_mpi_new (nbits_data); gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM); rc = gcry_sexp_build (&plain, NULL, "(data (flags raw no-blinding) (value %m))", x); gcry_mpi_release (x); if (rc) die ("converting data for encryption failed: %s\n", gcry_strerror (rc)); check_keys_crypt (pkey, skey, plain, decrypt_fail_code); gcry_sexp_release (plain); } static void get_keys_sample (gcry_sexp_t *pkey, gcry_sexp_t *skey, int secret_variant) { gcry_sexp_t pub_key, sec_key; int rc; static const char *secret; switch (secret_variant) { case 0: secret = sample_private_key_1; break; case 1: secret = sample_private_key_1_1; break; case 2: secret = sample_private_key_1_2; break; default: die ("BUG\n"); } rc = gcry_sexp_sscan (&pub_key, NULL, sample_public_key_1, strlen (sample_public_key_1)); if (!rc) rc = gcry_sexp_sscan (&sec_key, NULL, secret, strlen (secret)); if (rc) die ("converting sample keys failed: %s\n", gcry_strerror (rc)); *pkey = pub_key; *skey = sec_key; } static void get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:1024)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating RSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated RSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (! pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (! sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_keys_x931_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:1024)(use-x931)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating RSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated RSA (X9.31) key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_elg_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int fixed_x) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, (fixed_x ? "(genkey (elg (nbits 4:1024)(xvalue my.not-so-secret.key)))" : "(genkey (elg (nbits 3:512)))"), 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating Elgamal key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated ELG key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int transient_key) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, transient_key ? "(genkey (dsa (nbits 4:1024)(transient-key)))" : "(genkey (dsa (nbits 4:1024)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_fips186_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new - (&key_spec, "(genkey (dsa (nbits 4:1024)(use-fips186)))", 0, 1); + (&key_spec, "(genkey (dsa (nbits 4:2048)(use-fips186)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key (fips 186):\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (transient-key)(domain" "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ")))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } +#if 0 static void get_dsa_key_fips186_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (transient-key)(use-fips186)(domain" "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ")))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } - +#endif /*0*/ static void get_dsa_key_fips186_with_seed_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey" " (dsa" - " (nbits 4:1024)" + " (nbits 4:2048)" " (use-fips186)" " (transient-key)" " (derive-parms" " (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key (fips 186 with seed):\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void check_run (void) { gpg_error_t err; gcry_sexp_t pkey, skey; int variant; for (variant=0; variant < 3; variant++) { if (verbose) fprintf (stderr, "Checking sample key (%d).\n", variant); get_keys_sample (&pkey, &skey, variant); /* Check gcry_pk_testkey which requires all elements. */ err = gcry_pk_testkey (skey); if ((variant == 0 && err) || (variant > 0 && gpg_err_code (err) != GPG_ERR_NO_OBJ)) die ("gcry_pk_testkey failed: %s\n", gpg_strerror (err)); /* Run the usual check but expect an error from variant 2. */ check_keys (pkey, skey, 800, variant == 2? GPG_ERR_NO_OBJ : 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); } if (verbose) fprintf (stderr, "Checking generated RSA key.\n"); get_keys_new (&pkey, &skey); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Checking generated RSA key (X9.31).\n"); get_keys_x931_new (&pkey, &skey); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Checking generated Elgamal key.\n"); get_elg_key_new (&pkey, &skey, 0); check_keys (pkey, skey, 400, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Checking passphrase generated Elgamal key.\n"); get_elg_key_new (&pkey, &skey, 1); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Generating DSA key.\n"); get_dsa_key_new (&pkey, &skey, 0); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); if (!gcry_fips_mode_active ()) { if (verbose) fprintf (stderr, "Generating transient DSA key.\n"); get_dsa_key_new (&pkey, &skey, 1); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); } if (verbose) fprintf (stderr, "Generating DSA key (FIPS 186).\n"); get_dsa_key_fips186_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Generating DSA key with given domain.\n"); get_dsa_key_with_domain_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); + /* We need new test vectors for get_dsa_key_fips186_with_domain_new. */ if (verbose) - fprintf (stderr, "Generating DSA key with given domain (FIPS 186).\n"); - get_dsa_key_fips186_with_domain_new (&pkey, &skey); - /* Fixme: Add a check function for DSA keys. */ - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + fprintf (stderr, "Generating DSA key with given domain (FIPS 186)" + " - skipped.\n"); + /* get_dsa_key_fips186_with_domain_new (&pkey, &skey); */ + /* /\* Fixme: Add a check function for DSA keys. *\/ */ + /* gcry_sexp_release (pkey); */ + /* gcry_sexp_release (skey); */ if (verbose) fprintf (stderr, "Generating DSA key with given seed (FIPS 186).\n"); get_dsa_key_fips186_with_seed_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); } 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 > 1) show_sexp ("generated key:\n", 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); } static void check_ecc_sample_key (void) { static const char ecc_private_key[] = "(private-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2BEB6644D3609FC781" "B71F9A8072F58CB66AE2F89BB12451873ABF7D91F9E1FBF96BF2F70E73AAC9A283#)\n" " (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F744715E1D5BBE70378#)" "))"; static const char ecc_private_key_wo_q[] = "(private-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F744715E1D5BBE70378#)" "))"; static const char ecc_public_key[] = "(public-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2BEB6644D3609FC781" "B71F9A8072F58CB66AE2F89BB12451873ABF7D91F9E1FBF96BF2F70E73AAC9A283#)" "))"; static const char hash_string[] = "(data (flags raw)\n" " (value #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; static const char hash2_string[] = "(data (flags raw)\n" " (hash sha1 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "00112233445566778899AABBCCDDEEFF#))"; /* hash2, but longer than curve length, so it will be truncated */ static const char hash3_string[] = "(data (flags raw)\n" " (hash sha1 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; gpg_error_t err; gcry_sexp_t key, hash, hash2, hash3, sig, sig2; if (verbose) fprintf (stderr, "Checking sample ECC key.\n"); if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&hash2, hash2_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&hash3, hash3_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Verify hash truncation */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig2, hash2, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash3, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash2, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); if ((err = gcry_pk_verify (sig2, hash3, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Now try signing without the Q parameter. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign without Q failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed without Q failed: %s", gpg_strerror (err)); gcry_sexp_release (sig); gcry_sexp_release (sig2); gcry_sexp_release (key); gcry_sexp_release (hash); gcry_sexp_release (hash2); gcry_sexp_release (hash3); } static void check_ed25519ecdsa_sample_key (void) { static const char ecc_private_key[] = "(private-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" "))"; static const char ecc_private_key_wo_q[] = "(private-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" "))"; static const char ecc_public_key[] = "(public-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" "))"; static const char ecc_public_key_comp[] = "(public-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #047b57c2c1d3ded93332b52d588dd45863478b658387413a718779c0dd1a6d95#)" "))"; static const char hash_string[] = "(data (flags rfc6979)\n" " (hash sha256 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; gpg_error_t err; gcry_sexp_t key, hash, sig; if (verbose) fprintf (stderr, "Checking sample Ed25519/ECDSA key.\n"); /* Sign. */ if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); /* Verify. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Verify again using a compressed public key. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed (comp): %s", gpg_strerror (err)); /* Sign without a Q parameter. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign w/o Q failed: %s", gpg_strerror (err)); /* Verify. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed w/o Q failed: %s", gpg_strerror (err)); /* Verify again using a compressed public key. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed w/o Q failed (comp): %s", gpg_strerror (err)); extract_cmp_data (sig, "r", ("a63123a783ef29b8276e08987daca4" "655d0179e22199bf63691fd88eb64e15")); extract_cmp_data (sig, "s", ("0d9b45c696ab90b96b08812b485df185" "623ddaf5d02fa65ca5056cb6bd0f16f1")); gcry_sexp_release (sig); gcry_sexp_release (key); gcry_sexp_release (hash); } int main (int argc, char **argv) { int debug = 0; int i; if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; else if (argc > 1 && !strcmp (argv[1], "--debug")) { verbose = 2; debug = 1; } gcry_control (GCRYCTL_DISABLE_SECMEM, 0); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (debug) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); /* No valuable keys are create, so we can speed up our RNG. */ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); for (i=0; i < 2; i++) check_run (); for (i=0; i < 4; i++) check_x931_derived_key (i); check_ecc_sample_key (); check_ed25519ecdsa_sample_key (); return !!error_count; }