X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frsa%2Frsa_gen.c;h=6ec27495e740c8876e6920d83f687d4142788048;hp=00c25adbc588485e022a9a0b1608ca0b6ce16ba2;hb=330fad61af7323d5cf786fa76c7b31b4e4cac413;hpb=db82b8f9bd432a59aea8e1014694e15fc457c2bb diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 00c25adbc5..6ec27495e7 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -1,25 +1,24 @@ -/* crypto/rsa/rsa_gen.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. - * + * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * + * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,10 +33,10 @@ * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from + * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * + * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -49,149 +48,212 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ +/* + * NB: these functions have been "upgraded", the deprecated versions (which + * are compatibility wrappers using these functions) are in rsa_depr.c. - + * Geoff + */ + #include #include -#include "cryptlib.h" +#include "internal/cryptlib.h" #include #include -RSA *RSA_generate_key(int bits, unsigned long e_value, - void (*callback)(int,int,void *), void *cb_arg) - { - RSA *rsa=NULL; - BIGNUM *r0=NULL,*r1=NULL,*r2=NULL,*r3=NULL,*tmp; - int bitsp,bitsq,ok= -1,n=0,i; - BN_CTX *ctx=NULL,*ctx2=NULL; - - ctx=BN_CTX_new(); - if (ctx == NULL) goto err; - ctx2=BN_CTX_new(); - if (ctx2 == NULL) goto err; - BN_CTX_start(ctx); - r0 = BN_CTX_get(ctx); - r1 = BN_CTX_get(ctx); - r2 = BN_CTX_get(ctx); - r3 = BN_CTX_get(ctx); - if (r3 == NULL) goto err; - - bitsp=(bits+1)/2; - bitsq=bits-bitsp; - rsa=RSA_new(); - if (rsa == NULL) goto err; - - /* set e */ - rsa->e=BN_new(); - if (rsa->e == NULL) goto err; - -#if 1 - /* The problem is when building with 8, 16, or 32 BN_ULONG, - * unsigned long can be larger */ - for (i=0; ie,i); - } -#else - if (!BN_set_word(rsa->e,e_value)) goto err; -#endif - - /* generate p and q */ - for (;;) - { - rsa->p=BN_generate_prime(NULL,bitsp,0,NULL,NULL,callback,cb_arg); - if (rsa->p == NULL) goto err; - if (!BN_sub(r2,rsa->p,BN_value_one())) goto err; - if (!BN_gcd(r1,r2,rsa->e,ctx)) goto err; - if (BN_is_one(r1)) break; - if (callback != NULL) callback(2,n++,cb_arg); - BN_free(rsa->p); - } - if (callback != NULL) callback(3,0,cb_arg); - for (;;) - { - rsa->q=BN_generate_prime(NULL,bitsq,0,NULL,NULL,callback,cb_arg); - if (rsa->q == NULL) goto err; - if (!BN_sub(r2,rsa->q,BN_value_one())) goto err; - if (!BN_gcd(r1,r2,rsa->e,ctx)) goto err; - if (BN_is_one(r1) && (BN_cmp(rsa->p,rsa->q) != 0)) - break; - if (callback != NULL) callback(2,n++,cb_arg); - BN_free(rsa->q); - } - if (callback != NULL) callback(3,1,cb_arg); - if (BN_cmp(rsa->p,rsa->q) < 0) - { - tmp=rsa->p; - rsa->p=rsa->q; - rsa->q=tmp; - } - - /* calculate n */ - rsa->n=BN_new(); - if (rsa->n == NULL) goto err; - if (!BN_mul(rsa->n,rsa->p,rsa->q,ctx)) goto err; - - /* calculate d */ - if (!BN_sub(r1,rsa->p,BN_value_one())) goto err; /* p-1 */ - if (!BN_sub(r2,rsa->q,BN_value_one())) goto err; /* q-1 */ - if (!BN_mul(r0,r1,r2,ctx)) goto err; /* (p-1)(q-1) */ - -/* should not be needed, since gcd(p-1,e) == 1 and gcd(q-1,e) == 1 */ -/* for (;;) - { - if (!BN_gcd(r3,r0,rsa->e,ctx)) goto err; - if (BN_is_one(r3)) break; - - if (1) - { - if (!BN_add_word(rsa->e,2L)) goto err; - continue; - } - RSAerr(RSA_F_RSA_GENERATE_KEY,RSA_R_BAD_E_VALUE); - goto err; - } -*/ - rsa->d=BN_mod_inverse(NULL,rsa->e,r0,ctx2); /* d */ - if (rsa->d == NULL) goto err; - - /* calculate d mod (p-1) */ - rsa->dmp1=BN_new(); - if (rsa->dmp1 == NULL) goto err; - if (!BN_mod(rsa->dmp1,rsa->d,r1,ctx)) goto err; - - /* calculate d mod (q-1) */ - rsa->dmq1=BN_new(); - if (rsa->dmq1 == NULL) goto err; - if (!BN_mod(rsa->dmq1,rsa->d,r2,ctx)) goto err; - - /* calculate inverse of q mod p */ - rsa->iqmp=BN_mod_inverse(NULL,rsa->q,rsa->p,ctx2); - if (rsa->iqmp == NULL) goto err; - - ok=1; -err: - if (ok == -1) - { - RSAerr(RSA_F_RSA_GENERATE_KEY,ERR_LIB_BN); - ok=0; - } - BN_CTX_end(ctx); - BN_CTX_free(ctx); - BN_CTX_free(ctx2); - - if (!ok) - { - if (rsa != NULL) RSA_free(rsa); - return(NULL); - } - else - return(rsa); - } +static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value, + BN_GENCB *cb); + +/* + * NB: this wrapper would normally be placed in rsa_lib.c and the static + * implementation would probably be in rsa_eay.c. Nonetheless, is kept here + * so that we don't introduce a new linker dependency. Eg. any application + * that wasn't previously linking object code related to key-generation won't + * have to now just because key-generation is part of RSA_METHOD. + */ +int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) +{ + if (rsa->meth->rsa_keygen) + return rsa->meth->rsa_keygen(rsa, bits, e_value, cb); + return rsa_builtin_keygen(rsa, bits, e_value, cb); +} + +static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value, + BN_GENCB *cb) +{ + BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp; + int bitsp, bitsq, ok = -1, n = 0; + BN_CTX *ctx = NULL; + + ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + r3 = BN_CTX_get(ctx); + if (r3 == NULL) + goto err; + + bitsp = (bits + 1) / 2; + bitsq = bits - bitsp; + + /* We need the RSA components non-NULL */ + if (!rsa->n && ((rsa->n = BN_new()) == NULL)) + goto err; + if (!rsa->d && ((rsa->d = BN_secure_new()) == NULL)) + goto err; + if (!rsa->e && ((rsa->e = BN_new()) == NULL)) + goto err; + if (!rsa->p && ((rsa->p = BN_secure_new()) == NULL)) + goto err; + if (!rsa->q && ((rsa->q = BN_secure_new()) == NULL)) + goto err; + if (!rsa->dmp1 && ((rsa->dmp1 = BN_secure_new()) == NULL)) + goto err; + if (!rsa->dmq1 && ((rsa->dmq1 = BN_secure_new()) == NULL)) + goto err; + if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL)) + goto err; + + BN_copy(rsa->e, e_value); + + /* generate p and q */ + for (;;) { + if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb)) + goto err; + if (!BN_sub(r2, rsa->p, BN_value_one())) + goto err; + if (!BN_gcd(r1, r2, rsa->e, ctx)) + goto err; + if (BN_is_one(r1)) + break; + if (!BN_GENCB_call(cb, 2, n++)) + goto err; + } + if (!BN_GENCB_call(cb, 3, 0)) + goto err; + for (;;) { + /* + * When generating ridiculously small keys, we can get stuck + * continually regenerating the same prime values. Check for this and + * bail if it happens 3 times. + */ + unsigned int degenerate = 0; + do { + if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb)) + goto err; + } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3)); + if (degenerate == 3) { + ok = 0; /* we set our own err */ + RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_SIZE_TOO_SMALL); + goto err; + } + if (!BN_sub(r2, rsa->q, BN_value_one())) + goto err; + if (!BN_gcd(r1, r2, rsa->e, ctx)) + goto err; + if (BN_is_one(r1)) + break; + if (!BN_GENCB_call(cb, 2, n++)) + goto err; + } + if (!BN_GENCB_call(cb, 3, 1)) + goto err; + if (BN_cmp(rsa->p, rsa->q) < 0) { + tmp = rsa->p; + rsa->p = rsa->q; + rsa->q = tmp; + } + + /* calculate n */ + if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx)) + goto err; + + /* calculate d */ + if (!BN_sub(r1, rsa->p, BN_value_one())) + goto err; /* p-1 */ + if (!BN_sub(r2, rsa->q, BN_value_one())) + goto err; /* q-1 */ + if (!BN_mul(r0, r1, r2, ctx)) + goto err; /* (p-1)(q-1) */ + { + BIGNUM *local_r0 = NULL, *pr0; + if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { + pr0 = local_r0 = BN_new(); + if (local_r0 == NULL) + goto err; + BN_with_flags(pr0, r0, BN_FLG_CONSTTIME); + } else { + pr0 = r0; + } + if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) { + BN_free(local_r0); + goto err; /* d */ + } + /* We MUST free local_r0 before any further use of r0 */ + BN_free(local_r0); + } + + { + BIGNUM *local_d = NULL, *d; + /* set up d for correct BN_FLG_CONSTTIME flag */ + if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { + d = local_d = BN_new(); + if (local_d == NULL) + goto err; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + } else { + d = rsa->d; + } + + if ( /* calculate d mod (p-1) */ + !BN_mod(rsa->dmp1, d, r1, ctx) + /* calculate d mod (q-1) */ + || !BN_mod(rsa->dmq1, d, r2, ctx)) { + BN_free(local_d); + goto err; + } + /* We MUST free local_d before any further use of rsa->d */ + BN_free(local_d); + } + + { + BIGNUM *local_p = NULL, *p; + + /* calculate inverse of q mod p */ + if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { + p = local_p = BN_new(); + if (local_p == NULL) + goto err; + BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); + } else { + p = rsa->p; + } + if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) { + BN_free(local_p); + goto err; + } + /* We MUST free local_p before any further use of rsa->p */ + BN_free(local_p); + } + + ok = 1; + err: + if (ok == -1) { + RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, ERR_LIB_BN); + ok = 0; + } + if (ctx != NULL) + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ok; +}