xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/netpgpverify/rsa.c (revision 05c460ad06fc41fffebf804e499869c302af65e3)
125f78d91Sagc /*-
225f78d91Sagc  * Copyright (c) 2012 Alistair Crooks <agc@NetBSD.org>
325f78d91Sagc  * All rights reserved.
425f78d91Sagc  *
525f78d91Sagc  * Redistribution and use in source and binary forms, with or without
625f78d91Sagc  * modification, are permitted provided that the following conditions
725f78d91Sagc  * are met:
825f78d91Sagc  * 1. Redistributions of source code must retain the above copyright
925f78d91Sagc  *    notice, this list of conditions and the following disclaimer.
1025f78d91Sagc  * 2. Redistributions in binary form must reproduce the above copyright
1125f78d91Sagc  *    notice, this list of conditions and the following disclaimer in the
1225f78d91Sagc  *    documentation and/or other materials provided with the distribution.
1325f78d91Sagc  *
1425f78d91Sagc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1525f78d91Sagc  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1625f78d91Sagc  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1725f78d91Sagc  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1825f78d91Sagc  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1925f78d91Sagc  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2025f78d91Sagc  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2125f78d91Sagc  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2225f78d91Sagc  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2325f78d91Sagc  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2425f78d91Sagc  */
2525f78d91Sagc #include "config.h"
2625f78d91Sagc 
2725f78d91Sagc #include <sys/types.h>
2825f78d91Sagc 
2925f78d91Sagc #ifdef _KERNEL
3025f78d91Sagc # include <sys/kmem.h>
3125f78d91Sagc #else
3225f78d91Sagc # include <stdio.h>
3325f78d91Sagc # include <stdlib.h>
3425f78d91Sagc # include <string.h>
3525f78d91Sagc # include <unistd.h>
3625f78d91Sagc #endif
3725f78d91Sagc 
3825f78d91Sagc #include "misc.h"
3925f78d91Sagc #include "digest.h"
4025f78d91Sagc #include "rsa.h"
4125f78d91Sagc 
4225f78d91Sagc #ifndef USE_ARG
4325f78d91Sagc #define USE_ARG(x)	/*LINTED*/(void)&(x)
4425f78d91Sagc #endif
4525f78d91Sagc 
4625f78d91Sagc #define RSA_MAX_MODULUS_BITS	16384
4725f78d91Sagc #define RSA_SMALL_MODULUS_BITS	3072
4825f78d91Sagc #define RSA_MAX_PUBEXP_BITS	64 /* exponent limit enforced for "large" modulus only */
4925f78d91Sagc 
5025f78d91Sagc static int
rsa_padding_check_none(uint8_t * to,int tlen,const uint8_t * from,int flen,int num)5125f78d91Sagc rsa_padding_check_none(uint8_t *to, int tlen, const uint8_t *from, int flen, int num)
5225f78d91Sagc {
5325f78d91Sagc 	USE_ARG(num);
5425f78d91Sagc 	if (flen > tlen) {
5525f78d91Sagc 		printf("r too large\n");
5625f78d91Sagc 		return -1;
5725f78d91Sagc 	}
5825f78d91Sagc 	(void) memset(to, 0x0, tlen - flen);
5925f78d91Sagc 	(void) memcpy(to + tlen - flen, from, flen);
6025f78d91Sagc 	return tlen;
6125f78d91Sagc }
6225f78d91Sagc 
6325f78d91Sagc static int
lowlevel_rsa_private_encrypt(int plainc,const unsigned char * plain,unsigned char * encbuf,NETPGPV_RSA * rsa)64472564b2Sagc lowlevel_rsa_private_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, NETPGPV_RSA *rsa)
6525f78d91Sagc {
66dd98b26dSagc 	PGPV_BIGNUM	*decbn;
67dd98b26dSagc 	PGPV_BIGNUM	*signedbn;
6825f78d91Sagc 	uint8_t	*decbuf;
6925f78d91Sagc 	int	 nbytes;
7025f78d91Sagc 	int	 signc;
7125f78d91Sagc 	int	 signedbytes;
7225f78d91Sagc 	int	 r;
7325f78d91Sagc 
7425f78d91Sagc 	decbuf = NULL;
7525f78d91Sagc 	r = -1;
76dd98b26dSagc 	decbn = PGPV_BN_new();
77dd98b26dSagc 	signedbn = PGPV_BN_new();
78dd98b26dSagc 	nbytes = PGPV_BN_num_bytes(rsa->n);
7925f78d91Sagc 	decbuf = netpgp_allocate(1, nbytes);
8025f78d91Sagc 	/* add no padding */
8125f78d91Sagc 	memcpy(decbuf, plain, plainc);
82dd98b26dSagc 	PGPV_BN_bin2bn(decbuf, nbytes, decbn);
83dd98b26dSagc 	if (PGPV_BN_cmp(decbn, rsa->n) >= 0) {
8425f78d91Sagc 		printf("decbn too big\n");
8525f78d91Sagc 		goto err;
8625f78d91Sagc 	}
87dd98b26dSagc 	if (!PGPV_BN_mod_exp(signedbn, decbn, rsa->d, rsa->n, NULL)) {
8825f78d91Sagc 		printf("bad mod_exp\n");
8925f78d91Sagc 		goto err;
9025f78d91Sagc 	}
91dd98b26dSagc 	signedbytes = PGPV_BN_num_bytes(signedbn);
92dd98b26dSagc 	signc = PGPV_BN_bn2bin(signedbn, &encbuf[nbytes - signedbytes]);
9325f78d91Sagc 	memset(encbuf, 0x0, nbytes - signc);
9425f78d91Sagc 	r = nbytes;
9525f78d91Sagc err:
9625f78d91Sagc 	netpgp_deallocate(decbuf, nbytes);
97dd98b26dSagc 	PGPV_BN_clear_free(decbn);
98dd98b26dSagc 	PGPV_BN_clear_free(signedbn);
9925f78d91Sagc 	return r;
10025f78d91Sagc }
10125f78d91Sagc 
10225f78d91Sagc static int
lowlevel_rsa_public_encrypt(int plainc,const unsigned char * plain,unsigned char * encbuf,NETPGPV_RSA * rsa)103472564b2Sagc lowlevel_rsa_public_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, NETPGPV_RSA *rsa)
10425f78d91Sagc {
105dd98b26dSagc 	PGPV_BIGNUM	*decbn;
106dd98b26dSagc 	PGPV_BIGNUM	*encbn;
10725f78d91Sagc 	uint8_t	*decbuf;
10825f78d91Sagc 	int	 nbytes;
10925f78d91Sagc 	int	 encc;
11025f78d91Sagc 	int	 r;
11125f78d91Sagc 	int	 i;
11225f78d91Sagc 
11325f78d91Sagc 	r = -1;
114dd98b26dSagc 	decbn = PGPV_BN_new();
115dd98b26dSagc 	encbn = PGPV_BN_new();
116dd98b26dSagc 	nbytes = PGPV_BN_num_bytes(rsa->n);
11725f78d91Sagc 	decbuf = netpgp_allocate(1, nbytes);
11825f78d91Sagc 	(void) memcpy(decbuf, plain, plainc);
119dd98b26dSagc 	if (PGPV_BN_bin2bn(decbuf, nbytes, decbn) == NULL) {
12025f78d91Sagc 		printf("bin2bn failed\n");
12125f78d91Sagc 		goto err;
12225f78d91Sagc 	}
123dd98b26dSagc 	if (PGPV_BN_cmp(decbn, rsa->n) >= 0) {
124dd98b26dSagc 		printf("PGPV_BN_cmp failed\n");
12525f78d91Sagc 		goto err;
12625f78d91Sagc 	}
127dd98b26dSagc 	if (!PGPV_BN_mod_exp(encbn, decbn, rsa->e, rsa->n, NULL)) {
128dd98b26dSagc 		printf("PGPV_BN_mod_exp failed\n");
12925f78d91Sagc 		goto err;
13025f78d91Sagc 	}
131dd98b26dSagc 	encc = PGPV_BN_num_bytes(encbn);
132dd98b26dSagc 	i = PGPV_BN_bn2bin(encbn, &encbuf[nbytes - encc]);
13325f78d91Sagc 	(void) memset(encbuf, 0x0, nbytes - i);
13425f78d91Sagc 	r = nbytes;
13525f78d91Sagc err:
13625f78d91Sagc 	if (decbuf) {
13725f78d91Sagc 		memset(decbuf, 0x0, nbytes);
13825f78d91Sagc 		netpgp_deallocate(decbuf, nbytes);
13925f78d91Sagc 	}
140dd98b26dSagc 	PGPV_BN_clear_free(decbn);
141dd98b26dSagc 	PGPV_BN_clear_free(encbn);
14225f78d91Sagc 	return r;
14325f78d91Sagc }
14425f78d91Sagc 
14525f78d91Sagc static int
lowlevel_rsa_private_decrypt(int enclen,const unsigned char * encbuf,unsigned char * to,NETPGPV_RSA * rsa)146472564b2Sagc lowlevel_rsa_private_decrypt(int enclen, const unsigned char *encbuf, unsigned char *to, NETPGPV_RSA *rsa)
14725f78d91Sagc {
148dd98b26dSagc 	PGPV_BIGNUM	*encbn;
149dd98b26dSagc 	PGPV_BIGNUM	*decbn;
15025f78d91Sagc 	uint8_t	*buf;
15125f78d91Sagc 	int	 nbytes;
15225f78d91Sagc 	int	 j;
15325f78d91Sagc 	int	 r;
15425f78d91Sagc 
15525f78d91Sagc 	r = -1;
15625f78d91Sagc 	decbn = encbn = NULL;
15725f78d91Sagc 	buf = NULL;
158dd98b26dSagc 	if (PGPV_BN_num_bits(rsa->n) > RSA_MAX_MODULUS_BITS) {
15925f78d91Sagc 		return -1;
16025f78d91Sagc 	}
161dd98b26dSagc 	if (PGPV_BN_cmp(rsa->n, rsa->e) <= 0) {
16225f78d91Sagc 		return -1;
16325f78d91Sagc 	}
164dd98b26dSagc 	encbn = PGPV_BN_new();
165dd98b26dSagc 	decbn = PGPV_BN_new();
166dd98b26dSagc 	nbytes = PGPV_BN_num_bytes(rsa->n);
16725f78d91Sagc 	buf = netpgp_allocate(1, nbytes);
16825f78d91Sagc 	if (enclen > nbytes) {
16925f78d91Sagc 		printf("bad enclen\n");
17025f78d91Sagc 		goto err;
17125f78d91Sagc 	}
172dd98b26dSagc 	PGPV_BN_bin2bn(encbuf, enclen, encbn);
173dd98b26dSagc 	if (PGPV_BN_cmp(encbn, rsa->n) >= 0) {
17425f78d91Sagc 		printf("bad encbn\n");
17525f78d91Sagc 		goto err;
17625f78d91Sagc 	}
177dd98b26dSagc 	PGPV_BN_mod_exp(decbn, encbn, rsa->d, rsa->n, NULL);
178dd98b26dSagc 	j = PGPV_BN_bn2bin(decbn, buf);
17925f78d91Sagc 	r = rsa_padding_check_none(to, nbytes, buf, j, nbytes);
18025f78d91Sagc err:
181dd98b26dSagc 	PGPV_BN_clear_free(encbn);
182dd98b26dSagc 	PGPV_BN_clear_free(decbn);
18325f78d91Sagc 	netpgp_deallocate(buf, nbytes);
18425f78d91Sagc 	return r;
18525f78d91Sagc }
18625f78d91Sagc 
18725f78d91Sagc static int
lowlevel_rsa_public_decrypt(const uint8_t * encbuf,int enclen,uint8_t * dec,const netpgpv_rsa_pubkey_t * rsa)188472564b2Sagc lowlevel_rsa_public_decrypt(const uint8_t *encbuf, int enclen, uint8_t *dec, const netpgpv_rsa_pubkey_t *rsa)
18925f78d91Sagc {
19025f78d91Sagc 	uint8_t		*decbuf;
191dd98b26dSagc 	PGPV_BIGNUM		*decbn;
192dd98b26dSagc 	PGPV_BIGNUM		*encbn;
19325f78d91Sagc 	int		 decbytes;
19425f78d91Sagc 	int		 nbytes;
19525f78d91Sagc 	int		 r;
19625f78d91Sagc 
19725f78d91Sagc 	nbytes = 0;
19825f78d91Sagc 	r = -1;
19925f78d91Sagc 	decbuf = NULL;
20025f78d91Sagc 	decbn = encbn = NULL;
201dd98b26dSagc 	if (PGPV_BN_num_bits(rsa->n) > RSA_MAX_MODULUS_BITS) {
20225f78d91Sagc 		printf("rsa r modulus too large\n");
20325f78d91Sagc 		goto err;
20425f78d91Sagc 	}
205dd98b26dSagc 	if (PGPV_BN_cmp(rsa->n, rsa->e) <= 0) {
20625f78d91Sagc 		printf("rsa r bad n value\n");
20725f78d91Sagc 		goto err;
20825f78d91Sagc 	}
209dd98b26dSagc 	if (PGPV_BN_num_bits(rsa->n) > RSA_SMALL_MODULUS_BITS &&
210dd98b26dSagc 	    PGPV_BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) {
21125f78d91Sagc 		printf("rsa r bad exponent limit\n");
21225f78d91Sagc 		goto err;
21325f78d91Sagc 	}
214dd98b26dSagc 	if ((encbn = PGPV_BN_new()) == NULL ||
215dd98b26dSagc 	    (decbn = PGPV_BN_new()) == NULL ||
216dd98b26dSagc 	    (decbuf = netpgp_allocate(1, nbytes = PGPV_BN_num_bytes(rsa->n))) == NULL) {
21725f78d91Sagc 		printf("allocation failure\n");
21825f78d91Sagc 		goto err;
21925f78d91Sagc 	}
22025f78d91Sagc 	if (enclen > nbytes) {
22125f78d91Sagc 		printf("rsa r > mod len\n");
22225f78d91Sagc 		goto err;
22325f78d91Sagc 	}
224dd98b26dSagc 	if (PGPV_BN_bin2bn(encbuf, enclen, encbn) == NULL) {
22525f78d91Sagc 		printf("null encrypted BN\n");
22625f78d91Sagc 		goto err;
22725f78d91Sagc 	}
228dd98b26dSagc 	if (PGPV_BN_cmp(encbn, rsa->n) >= 0) {
22925f78d91Sagc 		printf("rsa r data too large for modulus\n");
23025f78d91Sagc 		goto err;
23125f78d91Sagc 	}
232dd98b26dSagc 	if (PGPV_BN_mod_exp(decbn, encbn, rsa->e, rsa->n, NULL) < 0) {
233dd98b26dSagc 		printf("PGPV_BN_mod_exp < 0\n");
23425f78d91Sagc 		goto err;
23525f78d91Sagc 	}
236dd98b26dSagc 	decbytes = PGPV_BN_num_bytes(decbn);
237dd98b26dSagc 	(void) PGPV_BN_bn2bin(decbn, decbuf);
23825f78d91Sagc 	if ((r = rsa_padding_check_none(dec, nbytes, decbuf, decbytes, 0)) < 0) {
23925f78d91Sagc 		printf("rsa r padding check failed\n");
24025f78d91Sagc 	}
24125f78d91Sagc err:
242dd98b26dSagc 	PGPV_BN_free(encbn);
243dd98b26dSagc 	PGPV_BN_free(decbn);
24425f78d91Sagc 	if (decbuf != NULL) {
24525f78d91Sagc 		(void) memset(decbuf, 0x0, nbytes);
24625f78d91Sagc 		netpgp_deallocate(decbuf, nbytes);
24725f78d91Sagc 	}
24825f78d91Sagc 	return r;
24925f78d91Sagc }
25025f78d91Sagc 
25125f78d91Sagc #if 0
25225f78d91Sagc /**
25325f78d91Sagc   @file rsa_make_key.c
25425f78d91Sagc   RSA key generation, Tom St Denis
25525f78d91Sagc */
25625f78d91Sagc 
25725f78d91Sagc /**
25825f78d91Sagc    Create an RSA key
25925f78d91Sagc    @param prng     An active PRNG state
26025f78d91Sagc    @param wprng    The index of the PRNG desired
26125f78d91Sagc    @param size     The size of the modulus (key size) desired (octets)
26225f78d91Sagc    @param e        The "e" value (public key).  e==65537 is a good choice
26325f78d91Sagc    @param key      [out] Destination of a newly created private key pair
26425f78d91Sagc    @return CRYPT_OK if successful, upon error all allocated ram is freed
26525f78d91Sagc */
26625f78d91Sagc static int
26725f78d91Sagc rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key)
26825f78d91Sagc {
26925f78d91Sagc 	void *p, *q, *tmp1, *tmp2, *tmp3;
27025f78d91Sagc 	int    err;
27125f78d91Sagc 
27225f78d91Sagc 	LTC_ARGCHK(ltc_mp.name != NULL);
27325f78d91Sagc 	LTC_ARGCHK(key         != NULL);
27425f78d91Sagc 
27525f78d91Sagc 	if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) {
27625f78d91Sagc 		return CRYPT_INVALID_KEYSIZE;
27725f78d91Sagc 	}
27825f78d91Sagc 
27925f78d91Sagc 	if ((e < 3) || ((e & 1) == 0)) {
28025f78d91Sagc 		return CRYPT_INVALID_ARG;
28125f78d91Sagc 	}
28225f78d91Sagc 
28325f78d91Sagc 	if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
28425f78d91Sagc 		return err;
28525f78d91Sagc 	}
28625f78d91Sagc 
28725f78d91Sagc 	if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != CRYPT_OK) {
28825f78d91Sagc 		return err;
28925f78d91Sagc 	}
29025f78d91Sagc 
29125f78d91Sagc 	/* make primes p and q (optimization provided by Wayne Scott) */
29225f78d91Sagc 		/* tmp3 = e */
29325f78d91Sagc 	if ((err = mp_set_int(tmp3, e)) != CRYPT_OK) {
29425f78d91Sagc 		goto errkey;
29525f78d91Sagc 	}
29625f78d91Sagc 
29725f78d91Sagc 	/* make prime "p" */
29825f78d91Sagc 	do {
29925f78d91Sagc 		if ((err = rand_prime( p, size/2, prng, wprng)) != CRYPT_OK) {
30025f78d91Sagc 			goto errkey;
30125f78d91Sagc 		}
30225f78d91Sagc 		/* tmp1 = p-1 */
30325f78d91Sagc 		if ((err = mp_sub_d( p, 1,  tmp1)) != CRYPT_OK) {
30425f78d91Sagc 			goto errkey;
30525f78d91Sagc 		}
30625f78d91Sagc 		/* tmp2 = gcd(p-1, e) */
30725f78d91Sagc 		if ((err = mp_gcd( tmp1,  tmp3,  tmp2)) != CRYPT_OK) {
30825f78d91Sagc 			goto errkey;
30925f78d91Sagc 		}
31025f78d91Sagc 	} while (mp_cmp_d( tmp2, 1) != 0);
31125f78d91Sagc 	/* while e divides p-1 */
31225f78d91Sagc 
31325f78d91Sagc 	/* make prime "q" */
31425f78d91Sagc 	do {
31525f78d91Sagc 		if ((err = rand_prime( q, size/2, prng, wprng)) != CRYPT_OK) {
31625f78d91Sagc 			goto errkey;
31725f78d91Sagc 		}
31825f78d91Sagc 		/* tmp1 = q-1 */
31925f78d91Sagc 		if ((err = mp_sub_d( q, 1,  tmp1)) != CRYPT_OK) {
32025f78d91Sagc 			goto errkey;
32125f78d91Sagc 		}
32225f78d91Sagc 		/* tmp2 = gcd(q-1, e) */
32325f78d91Sagc 		if ((err = mp_gcd( tmp1,  tmp3,  tmp2)) != CRYPT_OK) {
32425f78d91Sagc 			goto errkey;
32525f78d91Sagc 		}
32625f78d91Sagc 	} while (mp_cmp_d( tmp2, 1) != 0);
32725f78d91Sagc 	/* while e divides q-1 */
32825f78d91Sagc 
32925f78d91Sagc 	/* tmp1 = lcm(p-1, q-1) */
33025f78d91Sagc 		/* tmp2 = p-1 */
33125f78d91Sagc 	if ((err = mp_sub_d( p, 1,  tmp2)) != CRYPT_OK) {
33225f78d91Sagc 		goto errkey;
33325f78d91Sagc 	}
33425f78d91Sagc 	/* tmp1 = q-1 (previous do/while loop) */
33525f78d91Sagc 		/* tmp1 = lcm(p-1, q-1) */
33625f78d91Sagc 	if ((err = mp_lcm( tmp1,  tmp2,  tmp1)) != CRYPT_OK) {
33725f78d91Sagc 		goto errkey;
33825f78d91Sagc 	}
33925f78d91Sagc 
34025f78d91Sagc 	/* make key */
34125f78d91Sagc 	if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
34225f78d91Sagc 		goto errkey;
34325f78d91Sagc 	}
34425f78d91Sagc 
34525f78d91Sagc 	/* key->e =  e */
34625f78d91Sagc 	if ((err = mp_set_int( key->e, e)) != CRYPT_OK) {
34725f78d91Sagc 		goto errkey;
34825f78d91Sagc 	}
34925f78d91Sagc 	/* key->d = 1/e mod lcm(p-1,q-1) */
35025f78d91Sagc 	if ((err = mp_invmod( key->e,  tmp1,  key->d)) != CRYPT_OK) {
35125f78d91Sagc 		goto errkey;
35225f78d91Sagc 	}
35325f78d91Sagc 	/* key->N = pq */
35425f78d91Sagc 	if ((err = mp_mul( p,  q,  key->N)) != CRYPT_OK) {
35525f78d91Sagc 		goto errkey;
35625f78d91Sagc 	}
35725f78d91Sagc 
35825f78d91Sagc 	/* optimize for CRT now */
35925f78d91Sagc 	/* find d mod q-1 and d mod p-1 */
36025f78d91Sagc 	/* tmp1 = q-1 */
36125f78d91Sagc 	if ((err = mp_sub_d( p, 1,  tmp1)) != CRYPT_OK) {
36225f78d91Sagc 		goto errkey;
36325f78d91Sagc 	}
36425f78d91Sagc 	/* tmp2 = p-1 */
36525f78d91Sagc 	if ((err = mp_sub_d( q, 1,  tmp2)) != CRYPT_OK) {
36625f78d91Sagc 		goto errkey;
36725f78d91Sagc 	}
36825f78d91Sagc 	/* dP = d mod p-1 */
36925f78d91Sagc 	if ((err = mp_mod( key->d,  tmp1,  key->dP)) != CRYPT_OK) {
37025f78d91Sagc 		goto errkey;
37125f78d91Sagc 	}
37225f78d91Sagc 	/* dQ = d mod q-1 */
37325f78d91Sagc 	if ((err = mp_mod( key->d,  tmp2,  key->dQ)) != CRYPT_OK) {
37425f78d91Sagc 		goto errkey;
37525f78d91Sagc 	}
37625f78d91Sagc 	/* qP = 1/q mod p */
37725f78d91Sagc 	if ((err = mp_invmod( q,  p,  key->qP)) != CRYPT_OK) {
37825f78d91Sagc 		got oerrkey;
37925f78d91Sagc 	}
38025f78d91Sagc 
38125f78d91Sagc 	if ((err = mp_copy( p,  key->p)) != CRYPT_OK) {
38225f78d91Sagc 		goto errkey;
38325f78d91Sagc 		}
38425f78d91Sagc 	if ((err = mp_copy( q,  key->q)) != CRYPT_OK) {
38525f78d91Sagc 		goto errkey;
38625f78d91Sagc 	}
38725f78d91Sagc 
38825f78d91Sagc 	/* set key type (in this case it's CRT optimized) */
38925f78d91Sagc 	key->type = PK_PRIVATE;
39025f78d91Sagc 
39125f78d91Sagc 	/* return ok and free temps */
39225f78d91Sagc 	err = CRYPT_OK;
39325f78d91Sagc 	goto cleanup;
39425f78d91Sagc errkey:
39525f78d91Sagc 	mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL);
39625f78d91Sagc cleanup:
39725f78d91Sagc 	mp_clear_multi(tmp3, tmp2, tmp1, p, q, NULL);
39825f78d91Sagc 	return err;
39925f78d91Sagc }
40025f78d91Sagc #endif
40125f78d91Sagc 
40225f78d91Sagc #define HASHBUF_LEN	512
40325f78d91Sagc 
40425f78d91Sagc #define DSA_MAX_MODULUS_BITS	10000
40525f78d91Sagc 
40625f78d91Sagc static int
dsa_do_verify(const unsigned char * calculated,int dgst_len,const netpgpv_dsasig_t * sig,netpgpv_mpi_dsa_t * dsa)407472564b2Sagc dsa_do_verify(const unsigned char *calculated, int dgst_len, const netpgpv_dsasig_t *sig, netpgpv_mpi_dsa_t *dsa)
40825f78d91Sagc {
409dd98b26dSagc 	PGPV_BIGNUM		 *M;
410dd98b26dSagc 	PGPV_BIGNUM		 *W;
411dd98b26dSagc 	PGPV_BIGNUM		 *t1;
41225f78d91Sagc 	int		 ret = -1;
41325f78d91Sagc 	int		 qbits;
41425f78d91Sagc 
41525f78d91Sagc 	if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
41625f78d91Sagc 		return 0;
41725f78d91Sagc 	}
41825f78d91Sagc 	M = W = t1 = NULL;
419dd98b26dSagc 	qbits = PGPV_BN_num_bits(dsa->q);
42025f78d91Sagc 	switch(qbits) {
42125f78d91Sagc 	case 160:
42225f78d91Sagc 	case 224:
42325f78d91Sagc 	case 256:
42425f78d91Sagc 		/* openssl sources say these are the valid values */
42525f78d91Sagc 		/* according to FIPS 186-3 */
42625f78d91Sagc 		break;
42725f78d91Sagc 	default:
42825f78d91Sagc 		printf("dsa: bad # of Q bits\n");
42925f78d91Sagc 		return 0;
43025f78d91Sagc 	}
431dd98b26dSagc 	if (PGPV_BN_num_bits(dsa->p) > DSA_MAX_MODULUS_BITS) {
43225f78d91Sagc 		printf("dsa: p too large\n");
43325f78d91Sagc 		return 0;
43425f78d91Sagc 	}
43525f78d91Sagc 	/* no love for SHA512? */
43625f78d91Sagc 	if (dgst_len > SHA256_DIGEST_LENGTH) {
43725f78d91Sagc 		printf("dsa: digest too long\n");
43825f78d91Sagc 		return 0;
43925f78d91Sagc 	}
44025f78d91Sagc 	ret = 0;
441dd98b26dSagc 	if ((M = PGPV_BN_new()) == NULL ||
442dd98b26dSagc 	    (W = PGPV_BN_new()) == NULL ||
443dd98b26dSagc 	    (t1 = PGPV_BN_new()) == NULL) {
44425f78d91Sagc 		goto err;
44525f78d91Sagc 	}
446dd98b26dSagc 	if (PGPV_BN_is_zero(sig->r) ||
447dd98b26dSagc 	    PGPV_BN_is_negative(sig->r) ||
448dd98b26dSagc 	    PGPV_BN_cmp(sig->r, dsa->q) >= 0) {
44925f78d91Sagc 		goto err;
45025f78d91Sagc 	}
451dd98b26dSagc 	if (PGPV_BN_is_zero(sig->s) ||
452dd98b26dSagc 	    PGPV_BN_is_negative(sig->s) ||
453dd98b26dSagc 	    PGPV_BN_cmp(sig->s, dsa->q) >= 0) {
45425f78d91Sagc 		goto err;
45525f78d91Sagc 	}
456dd98b26dSagc 	if (PGPV_BN_mod_inverse(W, sig->s, dsa->q, NULL) != MP_OKAY) {
45725f78d91Sagc 		goto err;
45825f78d91Sagc 	}
45925f78d91Sagc 	if (dgst_len > qbits / 8) {
46025f78d91Sagc 		dgst_len = qbits / 8;
46125f78d91Sagc 	}
462dd98b26dSagc 	if (PGPV_BN_bin2bn(calculated, dgst_len, M) == NULL) {
46325f78d91Sagc 		goto err;
46425f78d91Sagc 	}
465dd98b26dSagc 	if (!PGPV_BN_mod_mul(M, M, W, dsa->q, NULL)) {
46625f78d91Sagc 		goto err;
46725f78d91Sagc 	}
468dd98b26dSagc 	if (!PGPV_BN_mod_mul(W, sig->r, W, dsa->q, NULL)) {
46925f78d91Sagc 		goto err;
47025f78d91Sagc 	}
471dd98b26dSagc 	if (!PGPV_BN_mod_exp(dsa->p, t1, dsa->g, M, NULL)) {
47225f78d91Sagc 		goto err;
47325f78d91Sagc 	}
474dd98b26dSagc 	if (!PGPV_BN_div(NULL, M, t1, dsa->q, NULL)) {
47525f78d91Sagc 		goto err;
47625f78d91Sagc 	}
477dd98b26dSagc 	ret = (PGPV_BN_cmp(M, sig->r) == 0);
47825f78d91Sagc err:
47925f78d91Sagc 	if (M) {
480dd98b26dSagc 		PGPV_BN_free(M);
48125f78d91Sagc 	}
48225f78d91Sagc 	if (W) {
483dd98b26dSagc 		PGPV_BN_free(W);
48425f78d91Sagc 	}
48525f78d91Sagc 	if (t1) {
486dd98b26dSagc 		PGPV_BN_free(t1);
48725f78d91Sagc 	}
48825f78d91Sagc 	return ret;
48925f78d91Sagc }
49025f78d91Sagc 
49125f78d91Sagc /*************************************************************************/
49225f78d91Sagc 
49325f78d91Sagc int
netpgpv_RSA_size(const NETPGPV_RSA * rsa)494472564b2Sagc netpgpv_RSA_size(const NETPGPV_RSA *rsa)
49525f78d91Sagc {
496dd98b26dSagc 	return (rsa == NULL) ? 0 : PGPV_BN_num_bits(rsa->n);
49725f78d91Sagc }
49825f78d91Sagc 
49925f78d91Sagc int
netpgpv_DSA_size(const NETPGPV_DSA * dsa)500472564b2Sagc netpgpv_DSA_size(const NETPGPV_DSA *dsa)
50125f78d91Sagc {
502dd98b26dSagc 	return (dsa == NULL) ? 0 : PGPV_BN_num_bits(dsa->p);
50325f78d91Sagc }
50425f78d91Sagc 
50525f78d91Sagc unsigned
netpgpv_dsa_verify(const signature_t * signature,const netpgpv_dsa_pubkey_t * pubdsa,const uint8_t * calculated,size_t hash_length)506472564b2Sagc netpgpv_dsa_verify(const signature_t *signature,
507472564b2Sagc 	const netpgpv_dsa_pubkey_t *pubdsa, const uint8_t *calculated,
508472564b2Sagc 	size_t hash_length)
50925f78d91Sagc {
510472564b2Sagc 	netpgpv_mpi_dsa_t	odsa;
511472564b2Sagc 	netpgpv_dsasig_t	osig;
51225f78d91Sagc 	unsigned		qlen;
51325f78d91Sagc 	int	             ret;
51425f78d91Sagc 
51525f78d91Sagc 	if (signature == NULL || pubdsa == NULL || calculated == NULL) {
516*05c460adSrillig 		return (unsigned)-1;
51725f78d91Sagc 	}
51825f78d91Sagc 	(void) memset(&osig, 0x0, sizeof(osig));
51925f78d91Sagc 	(void) memset(&odsa, 0x0, sizeof(odsa));
520dd98b26dSagc 	PGPV_BN_copy(osig.r, signature->dsa.r);
521dd98b26dSagc 	PGPV_BN_copy(osig.s, signature->dsa.s);
52225f78d91Sagc 	odsa.p = pubdsa->p;
52325f78d91Sagc 	odsa.q = pubdsa->q;
52425f78d91Sagc 	odsa.g = pubdsa->g;
52525f78d91Sagc 	odsa.pub_key = pubdsa->y;
526dd98b26dSagc 	if ((qlen = PGPV_BN_num_bytes(odsa.q)) < hash_length) {
52725f78d91Sagc 		hash_length = qlen;
52825f78d91Sagc 	}
52925f78d91Sagc 	ret = dsa_do_verify(calculated, (int)hash_length, &signature->dsa, &odsa);
53025f78d91Sagc 	if (ret < 0) {
53125f78d91Sagc 		return 0;
53225f78d91Sagc 	}
533dd98b26dSagc 	PGPV_BN_free(odsa.p);
534dd98b26dSagc 	PGPV_BN_free(odsa.q);
535dd98b26dSagc 	PGPV_BN_free(odsa.g);
536dd98b26dSagc 	PGPV_BN_free(odsa.pub_key);
53725f78d91Sagc 	odsa.p = odsa.q = odsa.g = odsa.pub_key = NULL;
538dd98b26dSagc 	PGPV_BN_free(osig.r);
539dd98b26dSagc 	PGPV_BN_free(osig.s);
54025f78d91Sagc 	osig.r = osig.s = NULL;
54125f78d91Sagc 	return (unsigned)ret;
54225f78d91Sagc }
54325f78d91Sagc 
544472564b2Sagc NETPGPV_RSA *
netpgpv_RSA_new(void)545472564b2Sagc netpgpv_RSA_new(void)
54625f78d91Sagc {
547472564b2Sagc 	return netpgp_allocate(1, sizeof(NETPGPV_RSA));
54825f78d91Sagc }
54925f78d91Sagc 
55025f78d91Sagc void
netpgpv_RSA_free(NETPGPV_RSA * rsa)551472564b2Sagc netpgpv_RSA_free(NETPGPV_RSA *rsa)
55225f78d91Sagc {
55325f78d91Sagc 	if (rsa) {
55425f78d91Sagc 		netpgp_deallocate(rsa, sizeof(*rsa));
55525f78d91Sagc 	}
55625f78d91Sagc }
55725f78d91Sagc 
55825f78d91Sagc int
netpgpv_RSA_check_key(NETPGPV_RSA * rsa)559472564b2Sagc netpgpv_RSA_check_key(NETPGPV_RSA *rsa)
56025f78d91Sagc {
561dd98b26dSagc 	PGPV_BIGNUM	*calcn;
56225f78d91Sagc 	int	 ret;
56325f78d91Sagc 
56425f78d91Sagc 	ret = 0;
56525f78d91Sagc 	if (rsa == NULL || rsa->p == NULL || rsa->q == NULL || rsa->n == NULL) {
56625f78d91Sagc 		return -1;
56725f78d91Sagc 	}
56825f78d91Sagc 	/* check that p and q are coprime, and that n = p*q. */
569dd98b26dSagc 	if (!PGPV_BN_is_prime(rsa->p, 1, NULL, NULL, NULL) ||
570dd98b26dSagc 	    !PGPV_BN_is_prime(rsa->q, 1, NULL, NULL, NULL)) {
57125f78d91Sagc 		return 0;
57225f78d91Sagc 	}
573dd98b26dSagc 	calcn = PGPV_BN_new();
574dd98b26dSagc         PGPV_BN_mul(calcn, rsa->p, rsa->q, NULL);
575dd98b26dSagc 	if (PGPV_BN_cmp(calcn, rsa->n) != 0) {
57625f78d91Sagc 		goto errout;
57725f78d91Sagc 	}
57825f78d91Sagc 	/* XXX - check that d*e = 1 mod (p-1*q-1) */
57925f78d91Sagc 	ret = 1;
58025f78d91Sagc errout:
581dd98b26dSagc 	PGPV_BN_clear_free(calcn);
58225f78d91Sagc 	return ret;
58325f78d91Sagc }
58425f78d91Sagc 
585472564b2Sagc NETPGPV_RSA *
netpgpv_RSA_generate_key(int num,unsigned long e,void (* callback)(int,int,void *),void * cb_arg)586472564b2Sagc netpgpv_RSA_generate_key(int num, unsigned long e, void (*callback)(int,int,void *), void *cb_arg)
58725f78d91Sagc {
58825f78d91Sagc 	/* STUBBED */
58925f78d91Sagc 	USE_ARG(num);
59025f78d91Sagc 	USE_ARG(e);
59125f78d91Sagc 	USE_ARG(callback);
59225f78d91Sagc 	USE_ARG(cb_arg);
59325f78d91Sagc 	printf("RSA_generate_key stubbed\n");
594472564b2Sagc 	return netpgpv_RSA_new();
59525f78d91Sagc }
59625f78d91Sagc 
59725f78d91Sagc /* encrypt */
59825f78d91Sagc int
netpgpv_RSA_public_encrypt(int plainc,const unsigned char * plain,unsigned char * encbuf,NETPGPV_RSA * rsa,int padding)599472564b2Sagc netpgpv_RSA_public_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, NETPGPV_RSA *rsa, int padding)
60025f78d91Sagc {
60125f78d91Sagc 	USE_ARG(padding);
60225f78d91Sagc 	if (plain == NULL || encbuf == NULL || rsa == NULL) {
60325f78d91Sagc 		return -1;
60425f78d91Sagc 	}
60525f78d91Sagc 	return lowlevel_rsa_public_encrypt(plainc, plain, encbuf, rsa);
60625f78d91Sagc }
60725f78d91Sagc 
60825f78d91Sagc /* decrypt */
60925f78d91Sagc int
netpgpv_RSA_private_decrypt(int flen,const unsigned char * from,unsigned char * to,NETPGPV_RSA * rsa,int padding)610472564b2Sagc netpgpv_RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to, NETPGPV_RSA *rsa, int padding)
61125f78d91Sagc {
61225f78d91Sagc 	USE_ARG(padding);
61325f78d91Sagc 	if (from == NULL || to == NULL || rsa == NULL) {
61425f78d91Sagc 		return -1;
61525f78d91Sagc 	}
61625f78d91Sagc 	return lowlevel_rsa_private_decrypt(flen, from, to, rsa);
61725f78d91Sagc }
61825f78d91Sagc 
61925f78d91Sagc /* sign */
62025f78d91Sagc int
netpgpv_RSA_private_encrypt(int plainc,const unsigned char * plain,unsigned char * encbuf,NETPGPV_RSA * rsa,int padding)621472564b2Sagc netpgpv_RSA_private_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, NETPGPV_RSA *rsa, int padding)
62225f78d91Sagc {
62325f78d91Sagc 	USE_ARG(padding);
62425f78d91Sagc 	if (plain == NULL || encbuf == NULL || rsa == NULL) {
62525f78d91Sagc 		return -1;
62625f78d91Sagc 	}
62725f78d91Sagc 	return lowlevel_rsa_private_encrypt(plainc, plain, encbuf, rsa);
62825f78d91Sagc }
62925f78d91Sagc 
63025f78d91Sagc /* verify */
63125f78d91Sagc int
netpgpv_RSA_public_decrypt(int enclen,const unsigned char * enc,unsigned char * dec,NETPGPV_RSA * rsa,int padding)632472564b2Sagc netpgpv_RSA_public_decrypt(int enclen, const unsigned char *enc, unsigned char *dec, NETPGPV_RSA *rsa, int padding)
63325f78d91Sagc {
634472564b2Sagc 	netpgpv_rsa_pubkey_t	pub;
63525f78d91Sagc 	int			ret;
63625f78d91Sagc 
63725f78d91Sagc 	if (enc == NULL || dec == NULL || rsa == NULL) {
63825f78d91Sagc 		return 0;
63925f78d91Sagc 	}
64025f78d91Sagc 	USE_ARG(padding);
64125f78d91Sagc 	(void) memset(&pub, 0x0, sizeof(pub));
642dd98b26dSagc 	pub.n = PGPV_BN_dup(rsa->n);
643dd98b26dSagc 	pub.e = PGPV_BN_dup(rsa->e);
64425f78d91Sagc 	ret = lowlevel_rsa_public_decrypt(enc, enclen, dec, &pub);
645dd98b26dSagc 	PGPV_BN_free(pub.n);
646dd98b26dSagc 	PGPV_BN_free(pub.e);
64725f78d91Sagc 	return ret;
64825f78d91Sagc }
64925f78d91Sagc 
65025f78d91Sagc /***********************************************************************/
65125f78d91Sagc 
652472564b2Sagc NETPGPV_DSA *
netpgpv_DSA_new(void)653472564b2Sagc netpgpv_DSA_new(void)
65425f78d91Sagc {
655472564b2Sagc 	return netpgp_allocate(1, sizeof(NETPGPV_DSA));
65625f78d91Sagc }
65725f78d91Sagc 
65825f78d91Sagc void
netpgpv_DSA_free(NETPGPV_DSA * dsa)659472564b2Sagc netpgpv_DSA_free(NETPGPV_DSA *dsa)
66025f78d91Sagc {
66125f78d91Sagc 	if (dsa) {
66225f78d91Sagc 		netpgp_deallocate(dsa, sizeof(*dsa));
66325f78d91Sagc 	}
66425f78d91Sagc }
66525f78d91Sagc 
666472564b2Sagc NETPGPV_DSA_SIG *
netpgpv_DSA_SIG_new(void)667472564b2Sagc netpgpv_DSA_SIG_new(void)
66825f78d91Sagc {
669472564b2Sagc 	return netpgp_allocate(1, sizeof(NETPGPV_DSA_SIG));
67025f78d91Sagc }
67125f78d91Sagc 
67225f78d91Sagc void
netpgpv_DSA_SIG_free(NETPGPV_DSA_SIG * sig)673472564b2Sagc netpgpv_DSA_SIG_free(NETPGPV_DSA_SIG *sig)
67425f78d91Sagc {
67525f78d91Sagc 	if (sig) {
67625f78d91Sagc 		netpgp_deallocate(sig, sizeof(*sig));
67725f78d91Sagc 	}
67825f78d91Sagc }
67925f78d91Sagc 
680472564b2Sagc NETPGPV_DSA_SIG *
netpgpv_DSA_do_sign(const unsigned char * dgst,int dlen,NETPGPV_DSA * dsa)681472564b2Sagc netpgpv_DSA_do_sign(const unsigned char *dgst, int dlen, NETPGPV_DSA *dsa)
68225f78d91Sagc {
68325f78d91Sagc 	/* STUBBED */
68425f78d91Sagc 	USE_ARG(dgst);
68525f78d91Sagc 	USE_ARG(dlen);
68625f78d91Sagc 	USE_ARG(dsa);
68725f78d91Sagc 	printf("DSA_do_sign stubbed\n");
688472564b2Sagc 	return netpgpv_DSA_SIG_new();
68925f78d91Sagc }
69025f78d91Sagc 
69125f78d91Sagc int
netpgpv_DSA_do_verify(const unsigned char * dgst,int dgst_len,NETPGPV_DSA_SIG * sig,NETPGPV_DSA * dsa)692472564b2Sagc netpgpv_DSA_do_verify(const unsigned char *dgst, int dgst_len, NETPGPV_DSA_SIG *sig, NETPGPV_DSA *dsa)
69325f78d91Sagc {
69425f78d91Sagc 	if (dgst == NULL || dgst_len == 0 || sig == NULL || dsa == NULL) {
69525f78d91Sagc 		return -1;
69625f78d91Sagc 	}
69725f78d91Sagc 	return dsa_do_verify(dgst, dgst_len, sig, dsa);
69825f78d91Sagc }
699