rsa_gen.c revision 68651
110710Sddmitriev/* crypto/rsa/rsa_gen.c */
210710Sddmitriev/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
310710Sddmitriev * All rights reserved.
410710Sddmitriev *
510710Sddmitriev * This package is an SSL implementation written
610710Sddmitriev * by Eric Young (eay@cryptsoft.com).
710710Sddmitriev * The implementation was written so as to conform with Netscapes SSL.
810710Sddmitriev *
910710Sddmitriev * This library is free for commercial and non-commercial use as long as
1010710Sddmitriev * the following conditions are aheared to.  The following conditions
1110710Sddmitriev * apply to all code found in this distribution, be it the RC4, RSA,
1210710Sddmitriev * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1310710Sddmitriev * included with this distribution is covered by the same copyright terms
1410710Sddmitriev * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1510710Sddmitriev *
1610710Sddmitriev * Copyright remains Eric Young's, and as such any Copyright notices in
1710710Sddmitriev * the code are not to be removed.
1810710Sddmitriev * If this package is used in a product, Eric Young should be given attribution
1910710Sddmitriev * as the author of the parts of the library used.
2010710Sddmitriev * This can be in the form of a textual message at program startup or
2110710Sddmitriev * in documentation (online or textual) provided with the package.
2210710Sddmitriev *
2310710Sddmitriev * Redistribution and use in source and binary forms, with or without
2410710Sddmitriev * modification, are permitted provided that the following conditions
2510710Sddmitriev * are met:
2610710Sddmitriev * 1. Redistributions of source code must retain the copyright
2710710Sddmitriev *    notice, this list of conditions and the following disclaimer.
2810710Sddmitriev * 2. Redistributions in binary form must reproduce the above copyright
2910710Sddmitriev *    notice, this list of conditions and the following disclaimer in the
3010710Sddmitriev *    documentation and/or other materials provided with the distribution.
3110710Sddmitriev * 3. All advertising materials mentioning features or use of this software
3210710Sddmitriev *    must display the following acknowledgement:
3310710Sddmitriev *    "This product includes cryptographic software written by
3410710Sddmitriev *     Eric Young (eay@cryptsoft.com)"
3510710Sddmitriev *    The word 'cryptographic' can be left out if the rouines from the library
3610710Sddmitriev *    being used are not cryptographic related :-).
3710710Sddmitriev * 4. If you include any Windows specific code (or a derivative thereof) from
3810710Sddmitriev *    the apps directory (application code) you must include an acknowledgement:
3910710Sddmitriev *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4010710Sddmitriev *
4110710Sddmitriev * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4210710Sddmitriev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4310710Sddmitriev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4410710Sddmitriev * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4510710Sddmitriev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4610710Sddmitriev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4710710Sddmitriev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4810710Sddmitriev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4910710Sddmitriev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5010710Sddmitriev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5110710Sddmitriev * SUCH DAMAGE.
5210710Sddmitriev *
5310710Sddmitriev * The licence and distribution terms for any publically available version or
5410710Sddmitriev * derivative of this code cannot be changed.  i.e. this code cannot simply be
5510710Sddmitriev * copied and put under another distribution licence
5610710Sddmitriev * [including the GNU Public Licence.]
5710710Sddmitriev */
5810710Sddmitriev
5910710Sddmitriev#include <stdio.h>
6010710Sddmitriev#include <time.h>
6110710Sddmitriev#include "cryptlib.h"
6210710Sddmitriev#include <openssl/bn.h>
6310710Sddmitriev#include <openssl/rsa.h>
6410710Sddmitriev
6510710SddmitrievRSA *RSA_generate_key(int bits, unsigned long e_value,
6610710Sddmitriev	     void (*callback)(int,int,void *), void *cb_arg)
6710710Sddmitriev	{
6810710Sddmitriev	RSA *rsa=NULL;
6910710Sddmitriev	BIGNUM *r0=NULL,*r1=NULL,*r2=NULL,*r3=NULL,*tmp;
7010710Sddmitriev	int bitsp,bitsq,ok= -1,n=0,i;
7110710Sddmitriev	BN_CTX *ctx=NULL,*ctx2=NULL;
7210710Sddmitriev
7310710Sddmitriev	ctx=BN_CTX_new();
7410710Sddmitriev	if (ctx == NULL) goto err;
7510710Sddmitriev	ctx2=BN_CTX_new();
7610710Sddmitriev	if (ctx2 == NULL) goto err;
7710710Sddmitriev	BN_CTX_start(ctx);
7810710Sddmitriev	r0 = BN_CTX_get(ctx);
7910710Sddmitriev	r1 = BN_CTX_get(ctx);
8010710Sddmitriev	r2 = BN_CTX_get(ctx);
8110710Sddmitriev	r3 = BN_CTX_get(ctx);
8210710Sddmitriev	if (r3 == NULL) goto err;
8310710Sddmitriev
8410710Sddmitriev	bitsp=(bits+1)/2;
8510710Sddmitriev	bitsq=bits-bitsp;
8610710Sddmitriev	rsa=RSA_new();
8710710Sddmitriev	if (rsa == NULL) goto err;
8810710Sddmitriev
8910710Sddmitriev	/* set e */
9010710Sddmitriev	rsa->e=BN_new();
9110710Sddmitriev	if (rsa->e == NULL) goto err;
9210710Sddmitriev
9310710Sddmitriev#if 1
9410710Sddmitriev	/* The problem is when building with 8, 16, or 32 BN_ULONG,
9510710Sddmitriev	 * unsigned long can be larger */
9610710Sddmitriev	for (i=0; i<sizeof(unsigned long)*8; i++)
9710710Sddmitriev		{
9810710Sddmitriev		if (e_value & (1UL<<i))
9910710Sddmitriev			BN_set_bit(rsa->e,i);
10010710Sddmitriev		}
10110710Sddmitriev#else
10210710Sddmitriev	if (!BN_set_word(rsa->e,e_value)) goto err;
10310710Sddmitriev#endif
10410710Sddmitriev
10510710Sddmitriev	/* generate p and q */
10610710Sddmitriev	for (;;)
10710710Sddmitriev		{
10810710Sddmitriev		rsa->p=BN_generate_prime(NULL,bitsp,0,NULL,NULL,callback,cb_arg);
10910710Sddmitriev		if (rsa->p == NULL) goto err;
11010710Sddmitriev		if (!BN_sub(r2,rsa->p,BN_value_one())) goto err;
11110710Sddmitriev		if (!BN_gcd(r1,r2,rsa->e,ctx)) goto err;
11210710Sddmitriev		if (BN_is_one(r1)) break;
11310710Sddmitriev		if (callback != NULL) callback(2,n++,cb_arg);
11410710Sddmitriev		BN_free(rsa->p);
11510710Sddmitriev		}
11610710Sddmitriev	if (callback != NULL) callback(3,0,cb_arg);
11710710Sddmitriev	for (;;)
11810710Sddmitriev		{
11910710Sddmitriev		rsa->q=BN_generate_prime(NULL,bitsq,0,NULL,NULL,callback,cb_arg);
12010710Sddmitriev		if (rsa->q == NULL) goto err;
12110710Sddmitriev		if (!BN_sub(r2,rsa->q,BN_value_one())) goto err;
12210710Sddmitriev		if (!BN_gcd(r1,r2,rsa->e,ctx)) goto err;
12310710Sddmitriev		if (BN_is_one(r1) && (BN_cmp(rsa->p,rsa->q) != 0))
12410710Sddmitriev			break;
12510710Sddmitriev		if (callback != NULL) callback(2,n++,cb_arg);
12610710Sddmitriev		BN_free(rsa->q);
12710710Sddmitriev		}
12810710Sddmitriev	if (callback != NULL) callback(3,1,cb_arg);
12910710Sddmitriev	if (BN_cmp(rsa->p,rsa->q) < 0)
13010710Sddmitriev		{
13110710Sddmitriev		tmp=rsa->p;
13210710Sddmitriev		rsa->p=rsa->q;
13310710Sddmitriev		rsa->q=tmp;
13410710Sddmitriev		}
13510710Sddmitriev
13610710Sddmitriev	/* calculate n */
13710710Sddmitriev	rsa->n=BN_new();
13810710Sddmitriev	if (rsa->n == NULL) goto err;
13910710Sddmitriev	if (!BN_mul(rsa->n,rsa->p,rsa->q,ctx)) goto err;
14010710Sddmitriev
14110710Sddmitriev	/* calculate d */
14210710Sddmitriev	if (!BN_sub(r1,rsa->p,BN_value_one())) goto err;	/* p-1 */
14310710Sddmitriev	if (!BN_sub(r2,rsa->q,BN_value_one())) goto err;	/* q-1 */
14410710Sddmitriev	if (!BN_mul(r0,r1,r2,ctx)) goto err;	/* (p-1)(q-1) */
14510710Sddmitriev
14610710Sddmitriev/* should not be needed, since gcd(p-1,e) == 1 and gcd(q-1,e) == 1 */
14710710Sddmitriev/*	for (;;)
14810710Sddmitriev		{
14910710Sddmitriev		if (!BN_gcd(r3,r0,rsa->e,ctx)) goto err;
15010710Sddmitriev		if (BN_is_one(r3)) break;
15110710Sddmitriev
15210710Sddmitriev		if (1)
15310710Sddmitriev			{
15410710Sddmitriev			if (!BN_add_word(rsa->e,2L)) goto err;
15510710Sddmitriev			continue;
15610710Sddmitriev			}
15710710Sddmitriev		RSAerr(RSA_F_RSA_GENERATE_KEY,RSA_R_BAD_E_VALUE);
15810710Sddmitriev		goto err;
15910710Sddmitriev		}
16010710Sddmitriev*/
16110710Sddmitriev	rsa->d=BN_mod_inverse(NULL,rsa->e,r0,ctx2);	/* d */
16210710Sddmitriev	if (rsa->d == NULL) goto err;
16310710Sddmitriev
16410710Sddmitriev	/* calculate d mod (p-1) */
16510710Sddmitriev	rsa->dmp1=BN_new();
16610710Sddmitriev	if (rsa->dmp1 == NULL) goto err;
16710710Sddmitriev	if (!BN_mod(rsa->dmp1,rsa->d,r1,ctx)) goto err;
16810710Sddmitriev
16910710Sddmitriev	/* calculate d mod (q-1) */
17010710Sddmitriev	rsa->dmq1=BN_new();
17110710Sddmitriev	if (rsa->dmq1 == NULL) goto err;
17210710Sddmitriev	if (!BN_mod(rsa->dmq1,rsa->d,r2,ctx)) goto err;
17310710Sddmitriev
17410710Sddmitriev	/* calculate inverse of q mod p */
17510710Sddmitriev	rsa->iqmp=BN_mod_inverse(NULL,rsa->q,rsa->p,ctx2);
17610710Sddmitriev	if (rsa->iqmp == NULL) goto err;
17710710Sddmitriev
17810710Sddmitriev	ok=1;
17910710Sddmitrieverr:
18010710Sddmitriev	if (ok == -1)
18110710Sddmitriev		{
18210710Sddmitriev		RSAerr(RSA_F_RSA_GENERATE_KEY,ERR_LIB_BN);
18310710Sddmitriev		ok=0;
18410710Sddmitriev		}
18510710Sddmitriev	BN_CTX_end(ctx);
18610710Sddmitriev	BN_CTX_free(ctx);
18710710Sddmitriev	BN_CTX_free(ctx2);
18810710Sddmitriev
18910710Sddmitriev	if (!ok)
19010710Sddmitriev		{
19110710Sddmitriev		if (rsa != NULL) RSA_free(rsa);
19210710Sddmitriev		return(NULL);
19310710Sddmitriev		}
19410710Sddmitriev	else
19510710Sddmitriev		return(rsa);
19610710Sddmitriev	}
19710710Sddmitriev
19810710Sddmitriev