sl@0: /* crypto/dsa/dsa_gen.c */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: sl@0: #undef GENUINE_DSA sl@0: sl@0: #ifdef GENUINE_DSA sl@0: /* Parameter generation follows the original release of FIPS PUB 186, sl@0: * Appendix 2.2 (i.e. use SHA as defined in FIPS PUB 180) */ sl@0: #define HASH EVP_sha() sl@0: #else sl@0: /* Parameter generation follows the updated Appendix 2.2 for FIPS PUB 186, sl@0: * also Appendix 2.2 of FIPS PUB 186-1 (i.e. use SHA as defined in sl@0: * FIPS PUB 180-1) */ sl@0: #define HASH EVP_sha1() sl@0: #endif sl@0: sl@0: #include /* To see if OPENSSL_NO_SHA is defined */ sl@0: sl@0: #ifndef OPENSSL_NO_SHA sl@0: sl@0: #include sl@0: #include sl@0: #include "cryptlib.h" sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: static int dsa_builtin_paramgen(DSA *ret, int bits, sl@0: unsigned char *seed_in, int seed_len, sl@0: int *counter_ret, unsigned long *h_ret, BN_GENCB *cb); sl@0: sl@0: EXPORT_C int DSA_generate_parameters_ex(DSA *ret, int bits, sl@0: unsigned char *seed_in, int seed_len, sl@0: int *counter_ret, unsigned long *h_ret, BN_GENCB *cb) sl@0: { sl@0: if(ret->meth->dsa_paramgen) sl@0: return ret->meth->dsa_paramgen(ret, bits, seed_in, seed_len, sl@0: counter_ret, h_ret, cb); sl@0: return dsa_builtin_paramgen(ret, bits, seed_in, seed_len, sl@0: counter_ret, h_ret, cb); sl@0: } sl@0: sl@0: static int dsa_builtin_paramgen(DSA *ret, int bits, sl@0: unsigned char *seed_in, int seed_len, sl@0: int *counter_ret, unsigned long *h_ret, BN_GENCB *cb) sl@0: { sl@0: int ok=0; sl@0: unsigned char seed[SHA_DIGEST_LENGTH]; sl@0: unsigned char md[SHA_DIGEST_LENGTH]; sl@0: unsigned char buf[SHA_DIGEST_LENGTH],buf2[SHA_DIGEST_LENGTH]; sl@0: BIGNUM *r0,*W,*X,*c,*test; sl@0: BIGNUM *g=NULL,*q=NULL,*p=NULL; sl@0: BN_MONT_CTX *mont=NULL; sl@0: int k,n=0,i,b,m=0; sl@0: int counter=0; sl@0: int r=0; sl@0: BN_CTX *ctx=NULL; sl@0: unsigned int h=2; sl@0: sl@0: if (bits < 512) bits=512; sl@0: bits=(bits+63)/64*64; sl@0: sl@0: /* NB: seed_len == 0 is special case: copy generated seed to sl@0: * seed_in if it is not NULL. sl@0: */ sl@0: if (seed_len && (seed_len < 20)) sl@0: seed_in = NULL; /* seed buffer too small -- ignore */ sl@0: if (seed_len > 20) sl@0: seed_len = 20; /* App. 2.2 of FIPS PUB 186 allows larger SEED, sl@0: * but our internal buffers are restricted to 160 bits*/ sl@0: if ((seed_in != NULL) && (seed_len == 20)) sl@0: { sl@0: memcpy(seed,seed_in,seed_len); sl@0: /* set seed_in to NULL to avoid it being copied back */ sl@0: seed_in = NULL; sl@0: } sl@0: sl@0: if ((ctx=BN_CTX_new()) == NULL) goto err; sl@0: sl@0: if ((mont=BN_MONT_CTX_new()) == NULL) goto err; sl@0: sl@0: BN_CTX_start(ctx); sl@0: r0 = BN_CTX_get(ctx); sl@0: g = BN_CTX_get(ctx); sl@0: W = BN_CTX_get(ctx); sl@0: q = BN_CTX_get(ctx); sl@0: X = BN_CTX_get(ctx); sl@0: c = BN_CTX_get(ctx); sl@0: p = BN_CTX_get(ctx); sl@0: test = BN_CTX_get(ctx); sl@0: sl@0: if (!BN_lshift(test,BN_value_one(),bits-1)) sl@0: goto err; sl@0: sl@0: for (;;) sl@0: { sl@0: for (;;) /* find q */ sl@0: { sl@0: int seed_is_random; sl@0: sl@0: /* step 1 */ sl@0: if(!BN_GENCB_call(cb, 0, m++)) sl@0: goto err; sl@0: sl@0: if (!seed_len) sl@0: { sl@0: RAND_pseudo_bytes(seed,SHA_DIGEST_LENGTH); sl@0: seed_is_random = 1; sl@0: } sl@0: else sl@0: { sl@0: seed_is_random = 0; sl@0: seed_len=0; /* use random seed if 'seed_in' turns out to be bad*/ sl@0: } sl@0: memcpy(buf,seed,SHA_DIGEST_LENGTH); sl@0: memcpy(buf2,seed,SHA_DIGEST_LENGTH); sl@0: /* precompute "SEED + 1" for step 7: */ sl@0: for (i=SHA_DIGEST_LENGTH-1; i >= 0; i--) sl@0: { sl@0: buf[i]++; sl@0: if (buf[i] != 0) break; sl@0: } sl@0: sl@0: /* step 2 */ sl@0: EVP_Digest(seed,SHA_DIGEST_LENGTH,md,NULL,HASH, NULL); sl@0: EVP_Digest(buf,SHA_DIGEST_LENGTH,buf2,NULL,HASH, NULL); sl@0: for (i=0; i 0) sl@0: break; sl@0: if (r != 0) sl@0: goto err; sl@0: sl@0: /* do a callback call */ sl@0: /* step 5 */ sl@0: } sl@0: sl@0: if(!BN_GENCB_call(cb, 2, 0)) goto err; sl@0: if(!BN_GENCB_call(cb, 3, 0)) goto err; sl@0: sl@0: /* step 6 */ sl@0: counter=0; sl@0: /* "offset = 2" */ sl@0: sl@0: n=(bits-1)/160; sl@0: b=(bits-1)-n*160; sl@0: sl@0: for (;;) sl@0: { sl@0: if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) sl@0: goto err; sl@0: sl@0: /* step 7 */ sl@0: BN_zero(W); sl@0: /* now 'buf' contains "SEED + offset - 1" */ sl@0: for (k=0; k<=n; k++) sl@0: { sl@0: /* obtain "SEED + offset + k" by incrementing: */ sl@0: for (i=SHA_DIGEST_LENGTH-1; i >= 0; i--) sl@0: { sl@0: buf[i]++; sl@0: if (buf[i] != 0) break; sl@0: } sl@0: sl@0: EVP_Digest(buf,SHA_DIGEST_LENGTH,md,NULL,HASH, NULL); sl@0: sl@0: /* step 8 */ sl@0: if (!BN_bin2bn(md,SHA_DIGEST_LENGTH,r0)) sl@0: goto err; sl@0: if (!BN_lshift(r0,r0,160*k)) goto err; sl@0: if (!BN_add(W,W,r0)) goto err; sl@0: } sl@0: sl@0: /* more of step 8 */ sl@0: if (!BN_mask_bits(W,bits-1)) goto err; sl@0: if (!BN_copy(X,W)) goto err; sl@0: if (!BN_add(X,X,test)) goto err; sl@0: sl@0: /* step 9 */ sl@0: if (!BN_lshift1(r0,q)) goto err; sl@0: if (!BN_mod(c,X,r0,ctx)) goto err; sl@0: if (!BN_sub(r0,c,BN_value_one())) goto err; sl@0: if (!BN_sub(p,X,r0)) goto err; sl@0: sl@0: /* step 10 */ sl@0: if (BN_cmp(p,test) >= 0) sl@0: { sl@0: /* step 11 */ sl@0: r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, sl@0: ctx, 1, cb); sl@0: if (r > 0) sl@0: goto end; /* found it */ sl@0: if (r != 0) sl@0: goto err; sl@0: } sl@0: sl@0: /* step 13 */ sl@0: counter++; sl@0: /* "offset = offset + n + 1" */ sl@0: sl@0: /* step 14 */ sl@0: if (counter >= 4096) break; sl@0: } sl@0: } sl@0: end: sl@0: if(!BN_GENCB_call(cb, 2, 1)) sl@0: goto err; sl@0: sl@0: /* We now need to generate g */ sl@0: /* Set r0=(p-1)/q */ sl@0: if (!BN_sub(test,p,BN_value_one())) goto err; sl@0: if (!BN_div(r0,NULL,test,q,ctx)) goto err; sl@0: sl@0: if (!BN_set_word(test,h)) goto err; sl@0: if (!BN_MONT_CTX_set(mont,p,ctx)) goto err; sl@0: sl@0: for (;;) sl@0: { sl@0: /* g=test^r0%p */ sl@0: if (!BN_mod_exp_mont(g,test,r0,p,ctx,mont)) goto err; sl@0: if (!BN_is_one(g)) break; sl@0: if (!BN_add(test,test,BN_value_one())) goto err; sl@0: h++; sl@0: } sl@0: sl@0: if(!BN_GENCB_call(cb, 3, 1)) sl@0: goto err; sl@0: sl@0: ok=1; sl@0: err: sl@0: if (ok) sl@0: { sl@0: if(ret->p) BN_free(ret->p); sl@0: if(ret->q) BN_free(ret->q); sl@0: if(ret->g) BN_free(ret->g); sl@0: ret->p=BN_dup(p); sl@0: ret->q=BN_dup(q); sl@0: ret->g=BN_dup(g); sl@0: if (ret->p == NULL || ret->q == NULL || ret->g == NULL) sl@0: { sl@0: ok=0; sl@0: goto err; sl@0: } sl@0: if (seed_in != NULL) memcpy(seed_in,seed,20); sl@0: if (counter_ret != NULL) *counter_ret=counter; sl@0: if (h_ret != NULL) *h_ret=h; sl@0: } sl@0: if(ctx) sl@0: { sl@0: BN_CTX_end(ctx); sl@0: BN_CTX_free(ctx); sl@0: } sl@0: if (mont != NULL) BN_MONT_CTX_free(mont); sl@0: return ok; sl@0: } sl@0: #endif