changeset 188:c9483550701b

- refactored random mp_int generation and byte->mp_int code - added RSA blinding
author Matt Johnston <matt@ucc.asn.au>
date Thu, 05 May 2005 03:58:21 +0000
parents c44df7123b0a
children 06e326daf16a
files bignum.c bignum.h common-kex.c dss.c gendss.c genrsa.c random.c random.h rsa.c
diffstat 9 files changed, 115 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/bignum.c	Wed May 04 15:31:17 2005 +0000
+++ b/bignum.c	Thu May 05 03:58:21 2005 +0000
@@ -52,9 +52,9 @@
     va_end(args);
 }
 
-void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len) {
+void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
 
-	if (mp_read_unsigned_bin(mp, bytes, len) != MP_OKAY) {
+	if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
 		dropbear_exit("mem alloc error");
 	}
 }
--- a/bignum.h	Wed May 04 15:31:17 2005 +0000
+++ b/bignum.h	Thu May 05 03:58:21 2005 +0000
@@ -29,7 +29,7 @@
 
 void m_mp_init(mp_int *mp);
 void m_mp_init_multi(mp_int *mp, ...);
-void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len);
+void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
 void sha1_process_mp(hash_state *hs, mp_int *mp);
 
 #endif /* _BIGNUM_H_ */
--- a/common-kex.c	Wed May 04 15:31:17 2005 +0000
+++ b/common-kex.c	Thu May 05 03:58:21 2005 +0000
@@ -469,18 +469,13 @@
 	DEF_MP_INT(dh_p);
 	DEF_MP_INT(dh_q);
 	DEF_MP_INT(dh_g);
-	unsigned char randbuf[DH_P_LEN];
-	int dh_q_len;
 
 	TRACE(("enter send_msg_kexdh_reply"))
 	
 	m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
 
 	/* read the prime and generator*/
-	if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
-			!= MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN);
 	
 	if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
@@ -495,16 +490,8 @@
 		dropbear_exit("Diffie-Hellman error");
 	}
 
-	dh_q_len = mp_unsigned_bin_size(&dh_q);
-
-	/* calculate our random value dh_y */
-	do {
-		assert((unsigned int)dh_q_len <= sizeof(randbuf));
-		genrandom(randbuf, dh_q_len);
-		if (mp_read_unsigned_bin(dh_priv, randbuf, dh_q_len) != MP_OKAY) {
-			dropbear_exit("Diffie-Hellman error");
-		}
-	} while (mp_cmp(dh_priv, &dh_q) == MP_GT || mp_cmp_d(dh_priv, 0) != MP_GT);
+	/* Generate a private portion 0 < dh_priv < dh_q */
+	gen_random_mpint(&dh_q, dh_priv);
 
 	/* f = g^y mod p */
 	if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
@@ -526,10 +513,7 @@
 
 	/* read the prime and generator*/
 	mp_init(&dh_p);
-	if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
-			!= MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);
 
 	/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
 	if (mp_cmp(dh_pub_them, &dh_p) != MP_LT 
--- a/dss.c	Wed May 04 15:31:17 2005 +0000
+++ b/dss.c	Thu May 05 03:58:21 2005 +0000
@@ -190,10 +190,8 @@
 	/* create the signature - s' and r' are the received signatures in buf */
 	/* w = (s')-1 mod q */
 	/* let val1 = s' */
-	if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE)
-			!= MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
+
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, s' >= q"))
 		goto out;
@@ -205,9 +203,8 @@
 
 	/* u1 = ((SHA(M')w) mod q */
 	/* let val1 = SHA(M') = msghash */
-	if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
+
 	/* let val3 = u1 = ((SHA(M')w) mod q */
 	if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
 		goto out;
@@ -215,10 +212,7 @@
 
 	/* u2 = ((r')w) mod q */
 	/* let val1 = r' */
-	if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE)
-			!= MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, r' >= q"))
 		goto out;
@@ -306,8 +300,6 @@
 	unsigned char *privkeytmp;
 	unsigned char proto_k[SHA512_HASH_SIZE];
 	DEF_MP_INT(dss_protok);
-#else
-	unsigned char kbuf[SHA1_HASH_SIZE];
 #endif
 	DEF_MP_INT(dss_k);
 	DEF_MP_INT(dss_m);
@@ -345,22 +337,16 @@
 
 	/* generate k */
 	m_mp_init(&dss_protok);
-	bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE);
+	bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
 	mp_mod(&dss_protok, key->q, &dss_k);
 	mp_clear(&dss_protok);
 	m_burn(proto_k, SHA512_HASH_SIZE);
 #else /* DSS_PROTOK not defined*/
-	do {
-		genrandom(kbuf, SHA1_HASH_SIZE);
-		if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) {
-			dropbear_exit("dss error");
-		}
-	} while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT);
-	m_burn(kbuf, SHA1_HASH_SIZE);
+	gen_random_mpint(key->q, &dss_k);
 #endif
 
 	/* now generate the actual signature */
-	bytestomp(&dss_m, msghash, SHA1_HASH_SIZE);
+	bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
 
 	/* g^k mod p */
 	if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) !=  MP_OKAY) {
--- a/gendss.c	Wed May 04 15:31:17 2005 +0000
+++ b/gendss.c	Thu May 05 03:58:21 2005 +0000
@@ -77,10 +77,7 @@
 	buf[0] |= 0x80; /* top bit high */
 	buf[QSIZE-1] |= 0x01; /* bottom bit high */
 
-	if (mp_read_unsigned_bin(key->q, buf, QSIZE) != MP_OKAY) {
-		fprintf(stderr, "dss key generation failed\n");
-		exit(1);
-	}
+	bytes_to_mp(key->q, buf, QSIZE);
 
 	/* 18 rounds are required according to HAC */
 	if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
@@ -116,10 +113,7 @@
 		buf[0] |= 0x80; /* set the top bit high */
 
 		/* X is a random mp_int */
-		if (mp_read_unsigned_bin(&tempX, buf, size) != MP_OKAY) {
-			fprintf(stderr, "dss key generation failed\n");
-			exit(1);
-		}
+		bytes_to_mp(&tempX, buf, size);
 
 		/* C = X mod 2q */
 		if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
@@ -147,6 +141,7 @@
 	} while (!result);
 
 	mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
+	m_burn(buf, size);
 	m_free(buf);
 }
 
@@ -189,22 +184,7 @@
 
 static void getx(dss_key *key) {
 
-	DEF_MP_INT(val);
-	char buf[QSIZE];
-	
-	m_mp_init(&val);
-	
-	do {
-		genrandom(buf, QSIZE);
-
-		if (mp_read_unsigned_bin(&val, buf, QSIZE) != MP_OKAY) {
-			fprintf(stderr, "dss key generation failed\n");
-		}
-	} while ((mp_cmp_d(&val, 1) == MP_GT) && (mp_cmp(&val, key->q) == MP_LT));
-
-	mp_copy(&val, key->x);
-	mp_clear(&val);
-
+	gen_random_mpint(key->q, key->x);
 }
 
 static void gety(dss_key *key) {
--- a/genrsa.c	Wed May 04 15:31:17 2005 +0000
+++ b/genrsa.c	Thu May 05 03:58:21 2005 +0000
@@ -108,10 +108,7 @@
 		genrandom(buf, size+1);
 		buf[0] |= 0x80; /* MSB set */
 
-		if (mp_read_unsigned_bin(prime, buf, size+1) != MP_OKAY) {
-			fprintf(stderr, "rsa generation failed\n");
-			exit(1);
-		}
+		bytes_to_mp(prime, buf, size+1);
 
 		/* find the next integer which is prime, 8 round of miller-rabin */
 		if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
--- a/random.c	Wed May 04 15:31:17 2005 +0000
+++ b/random.c	Thu May 05 03:58:21 2005 +0000
@@ -25,6 +25,7 @@
 #include "includes.h"
 #include "buffer.h"
 #include "dbutil.h"
+#include "bignum.h"
 
 int donerandinit = 0;
 
@@ -159,3 +160,38 @@
 	}
 	m_burn(hash, sizeof(hash));
 }
+
+/* Generates a random mp_int. 
+ * max is a *mp_int specifying an upper bound.
+ * rand must be an initialised *mp_int for the result.
+ * the result rand satisfies:  0 < rand < max 
+ * */
+void gen_random_mpint(mp_int *max, mp_int *rand) {
+
+	unsigned char *randbuf = NULL;
+	unsigned int len = 0;
+	const char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
+
+	const int size_bits = mp_count_bits(max);
+
+	len = size_bits / 8;
+	if ((size_bits % 8) != 0) {
+		len += 1;
+	}
+
+	randbuf = (unsigned char*)m_malloc(len);
+	do {
+		genrandom(randbuf, len);
+		/* Mask out the unrequired bits - mp_read_unsigned_bin expects
+		 * MSB first.*/
+		randbuf[0] &= masks[size_bits % 8];
+
+		bytes_to_mp(rand, randbuf, len);
+
+		/* keep regenerating until we get one satisfying
+		 * 0 < rand < max    */
+	} while ( ( (max != NULL) && (mp_cmp(rand, max) != MP_LT) )
+			|| (mp_cmp_d(rand, 0) != MP_GT) );
+	m_burn(randbuf, len);
+	m_free(randbuf);
+}
--- a/random.h	Wed May 04 15:31:17 2005 +0000
+++ b/random.h	Thu May 05 03:58:21 2005 +0000
@@ -25,8 +25,11 @@
 #ifndef _RANDOM_H_
 #define _RANDOM_H_
 
+struct mp_int;
+
 void seedrandom();
 void genrandom(unsigned char* buf, int len);
 void addrandom(unsigned char* buf, int len);
+void gen_random_mpint(mp_int *max, mp_int *rand);
 
 #endif /* _RANDOM_H_ */
--- a/rsa.c	Wed May 04 15:31:17 2005 +0000
+++ b/rsa.c	Thu May 05 03:58:21 2005 +0000
@@ -38,8 +38,9 @@
 
 #ifdef DROPBEAR_RSA 
 
-static mp_int * rsa_pad_em(rsa_key * key,
-		const unsigned char * data, unsigned int len);
+static void rsa_pad_em(rsa_key * key,
+		const unsigned char * data, unsigned int len,
+		mp_int * rsa_em);
 
 /* Load a public rsa key from a buffer, initialising the values.
  * The key will have the same format as buf_put_rsa_key.
@@ -203,14 +204,14 @@
 	unsigned int slen;
 	DEF_MP_INT(rsa_s);
 	DEF_MP_INT(rsa_mdash);
-	mp_int *rsa_em = NULL;
+	DEF_MP_INT(rsa_em);
 	int ret = DROPBEAR_FAILURE;
 
 	TRACE(("enter buf_rsa_verify"))
 
 	assert(key != NULL);
 
-	m_mp_init_multi(&rsa_mdash, &rsa_s, NULL);
+	m_mp_init_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);
 
 	slen = buf_getint(buf);
 	if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) {
@@ -231,29 +232,25 @@
 	}
 
 	/* create the magic PKCS padded value */
-	rsa_em = rsa_pad_em(key, data, len);
+	rsa_pad_em(key, data, len, &rsa_em);
 
 	if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
 		TRACE(("failed exptmod rsa_s"))
 		goto out;
 	}
 
-	if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) {
+	if (mp_cmp(&rsa_em, &rsa_mdash) == MP_EQ) {
 		/* signature is valid */
 		TRACE(("success!"))
 		ret = DROPBEAR_SUCCESS;
 	}
 
 out:
-	if (rsa_em) {
-		mp_clear(rsa_em);
-		m_free(rsa_em);
-	}
-	mp_clear_multi(&rsa_mdash, &rsa_s, NULL);
+	mp_clear_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);
 	TRACE(("leave buf_rsa_verify: ret %d", ret))
 	return ret;
+}
 
-}
 #endif /* DROPBEAR_SIGNKEY_VERIFY */
 
 /* Sign the data presented with key, writing the signature contents
@@ -264,22 +261,56 @@
 	unsigned int nsize, ssize;
 	unsigned int i;
 	DEF_MP_INT(rsa_s);
-	mp_int *rsa_em = NULL;
+	DEF_MP_INT(rsa_tmp1);
+	DEF_MP_INT(rsa_tmp2);
+	DEF_MP_INT(rsa_tmp3);
+	unsigned char *tmpbuf;
 	
 	TRACE(("enter buf_put_rsa_sign"))
 	assert(key != NULL);
 
-	rsa_em = rsa_pad_em(key, data, len);
+	m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
 
-	m_mp_init(&rsa_s);
+	rsa_pad_em(key, data, len, &rsa_tmp1);
 
 	/* the actual signing of the padded data */
+
+#define RSA_BLINDING
+#ifdef RSA_BLINDING
+
+	/* With blinding, s = (r^(-1))((em)*r^e)^d mod n */
+
+	/* generate the r blinding value */
+	/* rsa_tmp2 is r */
+	gen_random_mpint(key->n, &rsa_tmp2);
+
+	/* rsa_tmp1 is em */
+	/* em' = em * r^e mod n */
+
+	mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s); /* rsa_s used as a temp var*/
+	mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3);
+	mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2);
+
+	/* rsa_tmp2 is em' */
+	/* s' = (em')^d mod n */
+	mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1);
+
+	/* rsa_tmp1 is s' */
+	/* rsa_tmp3 is r^(-1) mod n */
+	/* s = (s')r^(-1) mod n */
+	mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s);
+
+#else
+
 	/* s = em^d mod n */
-	if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) {
+	/* rsa_tmp1 is em */
+	if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) {
 		dropbear_exit("rsa error");
 	}
-	mp_clear(rsa_em);
-	m_free(rsa_em);
+
+#endif /* RSA_BLINDING */
+
+	mp_clear_multi(&rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
 	
 	/* create the signature to return */
 	buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
@@ -318,9 +349,12 @@
  *
  * prefix is the ASN1 designator prefix,
  * hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14
+ *
+ * rsa_em must be a pointer to an initialised mp_int.
  */
-static mp_int * rsa_pad_em(rsa_key * key,
-		const unsigned char * data, unsigned int len) {
+static void rsa_pad_em(rsa_key * key,
+		const unsigned char * data, unsigned int len, 
+		mp_int * rsa_em) {
 
 	/* ASN1 designator (including the 0x00 preceding) */
 	const char rsa_asn1_magic[] = 
@@ -330,7 +364,6 @@
 	buffer * rsa_EM = NULL;
 	hash_state hs;
 	unsigned int nsize;
-	mp_int * rsa_em = NULL;
 	
 	assert(key != NULL);
 	assert(data != NULL);
@@ -358,16 +391,9 @@
 
 	/* Create the mp_int from the encoded bytes */
 	buf_setpos(rsa_EM, 0);
-	rsa_em = (mp_int*)m_malloc(sizeof(mp_int));
-	m_mp_init(rsa_em);
-	if (mp_read_unsigned_bin(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
-				rsa_EM->size) != MP_OKAY) {
-		dropbear_exit("rsa error");
-	}
+	bytes_to_mp(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
+			rsa_EM->size);
 	buf_free(rsa_EM);
-
-	return rsa_em;
-
 }
 
 #endif /* DROPBEAR_RSA */