changeset 801:7dcb46da72d9 ecc

merge in HEAD
author Matt Johnston <matt@ucc.asn.au>
date Tue, 21 May 2013 12:09:35 +0800
parents c344607b7341 (diff) 1d1f80fcbcb3 (current diff)
children 4029d3432a4f
files Makefile.in algo.h bignum.h buffer.c cli-algo.c cli-chansession.c cli-kex.c cli-main.c cli-service.c cli-session.c common-algo.c common-kex.c common-session.c configure.ac dbutil.c dbutil.h debug.h dss.c ecdsa.c kex.h options.h random.c rsa.c runopts.h session.h signkey.c svr-algo.c svr-auth.c svr-kex.c svr-session.c sysoptions.h
diffstat 61 files changed, 1894 insertions(+), 491 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Mon May 13 21:35:13 2013 +0800
+++ b/Makefile.in	Tue May 21 12:09:35 2013 +0800
@@ -17,16 +17,17 @@
 LTM=libtommath/libtommath.a
 
 ifeq (@BUNDLED_LIBTOM@, 1)
-LIBTOM_DEPS=$(LTC) $(LTM)
-CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ 
-LIBS+=$(LTC) $(LTM)
+LIBTOM_DEPS=$(LTM) $(LTC)
+CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
+LIBS+=$(LTM) $(LTC)
 endif
 
 COMMONOBJS=dbutil.o buffer.o \
 		dss.o bignum.o \
 		signkey.o rsa.o random.o \
 		queue.o \
-		atomicio.o compat.o  fake-rfc2553.o 
+		atomicio.o compat.o fake-rfc2553.o \
+		ltc_prng.o ecc.o ecdsa.o crypto_desc.o
 
 SVROBJS=svr-kex.o svr-auth.o sshpty.o \
 		svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
@@ -54,7 +55,7 @@
 		debug.h channel.h chansession.h config.h queue.h sshpty.h \
 		termcodes.h gendss.h genrsa.h runopts.h includes.h \
 		loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
-		listener.h fake-rfc2553.h
+		listener.h fake-rfc2553.h ecc.h ecdsa.h
 
 dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@ 
 dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
@@ -185,7 +186,7 @@
 	-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
 
 $(LTC): options.h
-	cd libtomcrypt && $(MAKE) clean && $(MAKE)
+	cd libtomcrypt && $(MAKE)
 
 $(LTM): options.h
 	cd libtommath && $(MAKE)
--- a/agentfwd.h	Mon May 13 21:35:13 2013 +0800
+++ b/agentfwd.h	Tue May 21 12:09:35 2013 +0800
@@ -40,7 +40,7 @@
 /* client functions */
 void cli_load_agent_keys(m_list * ret_list);
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
-    const unsigned char *data, unsigned int len);
+	buffer *data_buf);
 void cli_setup_agent(struct Channel *channel);
 
 #ifdef __hpux
--- a/algo.h	Mon May 13 21:35:13 2013 +0800
+++ b/algo.h	Tue May 21 12:09:35 2013 +0800
@@ -35,7 +35,7 @@
 
 struct Algo_Type {
 
-	unsigned char *name; /* identifying name */
+	const unsigned char *name; /* identifying name */
 	char val; /* a value for this cipher, or -1 for invalid */
 	const void *data; /* algorithm specific data */
 	char usable; /* whether we can use this algorithm */
@@ -59,8 +59,8 @@
 
 struct dropbear_cipher {
 	const struct ltc_cipher_descriptor *cipherdesc;
-	unsigned long keysize;
-	unsigned char blocksize;
+	const unsigned long keysize;
+	const unsigned char blocksize;
 };
 
 struct dropbear_cipher_mode {
@@ -74,12 +74,27 @@
 };
 
 struct dropbear_hash {
-	const struct ltc_hash_descriptor *hashdesc;
-	unsigned long keysize;
-	unsigned char hashsize;
+	const struct ltc_hash_descriptor *hash_desc;
+	const unsigned long keysize;
+	// hashsize may be truncated from the size returned by hash_desc,
+	// eg sha1-96
+	const unsigned char hashsize;
 };
 
-void crypto_init();
+struct dropbear_kex {
+	// "normal" DH KEX
+	const unsigned char *dh_p_bytes;
+	const int dh_p_len;
+
+	// elliptic curve DH KEX
+#ifdef DROPBEAR_ECDH
+	const struct dropbear_ecc_curve *ecc_curve;
+#endif
+
+	// both
+	const struct ltc_hash_descriptor *hash_desc;
+};
+
 int have_algo(char* algo, size_t algolen, algo_type algos[]);
 void buf_put_algolist(buffer * buf, algo_type localalgos[]);
 
@@ -102,5 +117,16 @@
 char * algolist_string(algo_type algos[]);
 #endif
 
+#ifdef DROPBEAR_ECDH
+#define IS_NORMAL_DH(algo) ((algo)->dh_p_bytes != NULL)
+#else
+#define IS_NORMAL_DH(algo) 1
+#endif
+
+enum {
+	DROPBEAR_COMP_NONE,
+	DROPBEAR_COMP_ZLIB,
+	DROPBEAR_COMP_ZLIB_DELAY,
+};
 
 #endif /* _ALGO_H_ */
--- a/bignum.c	Mon May 13 21:35:13 2013 +0800
+++ b/bignum.c	Tue May 21 12:09:35 2013 +0800
@@ -60,7 +60,8 @@
 }
 
 /* hash the ssh representation of the mp_int mp */
-void sha1_process_mp(hash_state *hs, mp_int *mp) {
+void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, 
+				hash_state *hs, mp_int *mp) {
 
 	int i;
 	buffer * buf;
@@ -68,8 +69,6 @@
 	buf = buf_new(512 + 20); /* max buffer is a 4096 bit key, 
 								plus header + some leeway*/
 	buf_putmpint(buf, mp);
-	i = buf->pos;
-	buf_setpos(buf, 0);
-	sha1_process(hs, buf_getptr(buf, i), i);
+	hash_desc->process(hs, buf->data, buf->len);
 	buf_free(buf);
 }
--- a/bignum.h	Mon May 13 21:35:13 2013 +0800
+++ b/bignum.h	Tue May 21 12:09:35 2013 +0800
@@ -31,6 +31,7 @@
 void m_mp_init(mp_int *mp);
 void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
 void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
-void sha1_process_mp(hash_state *hs, mp_int *mp);
+void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, 
+				hash_state *hs, mp_int *mp);
 
 #endif /* _BIGNUM_H_ */
--- a/buffer.c	Mon May 13 21:35:13 2013 +0800
+++ b/buffer.c	Tue May 21 12:09:35 2013 +0800
@@ -269,6 +269,11 @@
 
 }
 
+/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
+void buf_putbufstring(buffer *buf, const buffer* buf_str) {
+	buf_putstring(buf, buf_str->data, buf_str->len);
+}
+
 /* put the set of len bytes into the buffer, incrementing the pos, increasing
  * len if required */
 void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
--- a/buffer.h	Mon May 13 21:35:13 2013 +0800
+++ b/buffer.h	Tue May 21 12:09:35 2013 +0800
@@ -59,6 +59,7 @@
 void buf_eatstring(buffer *buf);
 void buf_putint(buffer* buf, unsigned int val);
 void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
+void buf_putbufstring(buffer *buf, const buffer* buf_str);
 void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
 void buf_putmpint(buffer* buf, mp_int * mp);
 int buf_getmpint(buffer* buf, mp_int* mp);
--- a/cli-agentfwd.c	Mon May 13 21:35:13 2013 +0800
+++ b/cli-agentfwd.c	Tue May 21 12:09:35 2013 +0800
@@ -254,7 +254,7 @@
 }
 
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
-		const unsigned char *data, unsigned int len) {
+		buffer *data_buf) {
 	buffer *request_data = NULL;
 	buffer *response = NULL;
 	unsigned int siglen;
@@ -266,10 +266,10 @@
 	string			data
 	uint32			flags
 	*/
-	request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
+	request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
 	buf_put_pub_key(request_data, key, key->type);
 	
-	buf_putstring(request_data, data, len);
+	buf_putbufstring(request_data, data_buf);
 	buf_putint(request_data, 0);
 	
 	response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
--- a/cli-authpubkey.c	Mon May 13 21:35:13 2013 +0800
+++ b/cli-authpubkey.c	Tue May 21 12:09:35 2013 +0800
@@ -121,23 +121,19 @@
 }
 
 void cli_buf_put_sign(buffer* buf, sign_key *key, int type, 
-			const unsigned char *data, unsigned int len)
-{
+			buffer *data_buf) {
 #ifdef ENABLE_CLI_AGENTFWD
 	if (key->source == SIGNKEY_SOURCE_AGENT) {
 		/* Format the agent signature ourselves, as buf_put_sign would. */
 		buffer *sigblob;
 		sigblob = buf_new(MAX_PUBKEY_SIZE);
-		agent_buf_sign(sigblob, key, data, len);
-		buf_setpos(sigblob, 0);
-		buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
-				sigblob->len);
-
+		agent_buf_sign(sigblob, key, data_buf);
+		buf_putbufstring(buf, sigblob);
 		buf_free(sigblob);
 	} else 
 #endif /* ENABLE_CLI_AGENTFWD */
 	{
-		buf_put_sign(buf, key, type, data, len);
+		buf_put_sign(buf, key, type, data_buf);
 	}
 }
 
@@ -173,10 +169,10 @@
 		TRACE(("realsign"))
 		/* We put the signature as well - this contains string(session id), then
 		 * the contents of the write payload to this point */
-		sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
-		buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
+		sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
+		buf_putbufstring(sigbuf, ses.session_id);
 		buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
-		cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
+		cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
 		buf_free(sigbuf); /* Nothing confidential in the buffer */
 	}
 
--- a/cli-chansession.c	Mon May 13 21:35:13 2013 +0800
+++ b/cli-chansession.c	Tue May 21 12:09:35 2013 +0800
@@ -453,7 +453,7 @@
 }
 
 static
-void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) {
+void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
 	char c;
 	int skip_char = 0;
 
--- a/cli-kex.c	Mon May 13 21:35:13 2013 +0800
+++ b/cli-kex.c	Tue May 21 12:09:35 2013 +0800
@@ -36,6 +36,7 @@
 #include "random.h"
 #include "runopts.h"
 #include "signkey.h"
+#include "ecc.h"
 
 
 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
@@ -43,23 +44,31 @@
 
 void send_msg_kexdh_init() {
 	TRACE(("send_msg_kexdh_init()"))	
-	if ((cli_ses.dh_e && cli_ses.dh_x 
-				&& cli_ses.dh_val_algo == ses.newkeys->algo_kex)) {
-		TRACE(("reusing existing dh_e from first_kex_packet_follows"))
-	} else {
-		if (!cli_ses.dh_e || !cli_ses.dh_e) {
-			cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
-			cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
-			m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
-		}
-
-		gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
-		cli_ses.dh_val_algo = ses.newkeys->algo_kex;
-	}
 
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
-	buf_putmpint(ses.writepayload, cli_ses.dh_e);
+	if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
+		if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
+			|| !cli_ses.dh_param) {
+			if (cli_ses.dh_param) {
+				free_kexdh_param(cli_ses.dh_param);
+			}
+			cli_ses.dh_param = gen_kexdh_param();
+		}
+		buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
+	} else {
+#ifdef DROPBEAR_ECDH
+		if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
+			|| !cli_ses.ecdh_param) {
+			if (cli_ses.ecdh_param) {
+				free_kexecdh_param(cli_ses.ecdh_param);
+			}
+			cli_ses.ecdh_param = gen_kexecdh_param();
+		}
+		buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
+#endif
+	}
+	cli_ses.param_kex_algo = ses.newkeys->algo_kex;
 	encrypt_packet();
 	ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
 	ses.requirenext[1] = SSH_MSG_KEXINIT;
@@ -68,18 +77,15 @@
 /* Handle a diffie-hellman key exchange reply. */
 void recv_msg_kexdh_reply() {
 
-	DEF_MP_INT(dh_f);
 	sign_key *hostkey = NULL;
 	unsigned int type, keybloblen;
 	unsigned char* keyblob = NULL;
 
-
 	TRACE(("enter recv_msg_kexdh_reply"))
 
 	if (cli_ses.kex_state != KEXDH_INIT_SENT) {
 		dropbear_exit("Received out-of-order kexdhreply");
 	}
-	m_mp_init(&dh_f);
 	type = ses.newkeys->algo_hostkey;
 	TRACE(("type is %d", type))
 
@@ -97,20 +103,38 @@
 		dropbear_exit("Bad KEX packet");
 	}
 
-	if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
-		TRACE(("failed getting mpint"))
-		dropbear_exit("Bad KEX packet");
+	if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
+		// Normal diffie-hellman
+		DEF_MP_INT(dh_f);
+		m_mp_init(&dh_f);
+		if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
+			TRACE(("failed getting mpint"))
+			dropbear_exit("Bad KEX packet");
+		}
+
+		kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
+		mp_clear(&dh_f);
+	} else {
+#ifdef DROPBEAR_ECDH
+		buffer *ecdh_qs = buf_getstringbuf(ses.payload);
+		kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
+		buf_free(ecdh_qs);
+#endif
 	}
 
-	kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
-	mp_clear(&dh_f);
-	mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
-	m_free(cli_ses.dh_e);
-	m_free(cli_ses.dh_x);
-	cli_ses.dh_val_algo = DROPBEAR_KEX_NONE;
+	if (cli_ses.dh_param) {
+		free_kexdh_param(cli_ses.dh_param);
+		cli_ses.dh_param = NULL;
+	}
+#ifdef DROPBEAR_ECDH
+	if (cli_ses.ecdh_param) {
+		free_kexecdh_param(cli_ses.ecdh_param);
+		cli_ses.ecdh_param = NULL;
+	}
+#endif
 
-	if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) 
-			!= DROPBEAR_SUCCESS) {
+	cli_ses.param_kex_algo = NULL;
+	if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
 		dropbear_exit("Bad hostkey signature");
 	}
 
--- a/cli-main.c	Mon May 13 21:35:13 2013 +0800
+++ b/cli-main.c	Tue May 21 12:09:35 2013 +0800
@@ -28,6 +28,8 @@
 #include "dbutil.h"
 #include "runopts.h"
 #include "session.h"
+#include "random.h"
+#include "crypto_desc.h"
 
 static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
 static void cli_dropbear_log(int priority, const char* format, va_list param);
@@ -51,6 +53,9 @@
 
 	disallow_core();
 
+	seedrandom();
+	crypto_init();
+
 	cli_getopts(argc, argv);
 
 	TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
--- a/cli-session.c	Mon May 13 21:35:13 2013 +0800
+++ b/cli-session.c	Tue May 21 12:09:35 2013 +0800
@@ -36,6 +36,7 @@
 #include "runopts.h"
 #include "chansession.h"
 #include "agentfwd.h"
+#include "crypto_desc.h"
 
 static void cli_remoteclosed();
 static void cli_sessionloop();
@@ -86,10 +87,6 @@
 
 void cli_session(int sock_in, int sock_out) {
 
-	seedrandom();
-
-	crypto_init();
-
 	common_session_init(sock_in, sock_out);
 
 	chaninitialise(cli_chantypes);
--- a/common-algo.c	Mon May 13 21:35:13 2013 +0800
+++ b/common-algo.c	Tue May 21 12:09:35 2013 +0800
@@ -23,24 +23,28 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE. */
 
+#include "includes.h"
 #include "algo.h"
 #include "session.h"
 #include "dbutil.h"
+#include "kex.h"
+#include "ltc_prng.h"
+#include "ecc.h"
 
 /* This file (algo.c) organises the ciphers which can be used, and is used to
  * decide which ciphers/hashes/compression/signing to use during key exchange*/
 
 static int void_cipher(const unsigned char* in, unsigned char* out,
-		unsigned long len, void *cipher_state) {
+		unsigned long len, void* UNUSED(cipher_state)) {
 	if (in != out) {
 		memmove(out, in, len);
 	}
 	return CRYPT_OK;
 }
 
-static int void_start(int cipher, const unsigned char *IV, 
-			const unsigned char *key, 
-			int keylen, int num_rounds, void *cipher_state) {
+static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV), 
+			const unsigned char* UNUSED(key), 
+			int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
 	return CRYPT_OK;
 }
 
@@ -204,6 +208,17 @@
 };
 
 algo_type sshhostkey[] = {
+#ifdef DROPBEAR_ECDSA
+#ifdef DROPBEAR_ECC_256
+	{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
+#endif
+#ifdef DROPBEAR_ECC_384
+	{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
+#endif
+#ifdef DROPBEAR_ECC_521
+	{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
+#endif
+#endif
 #ifdef DROPBEAR_RSA
 	{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
 #endif
@@ -213,65 +228,42 @@
 	{NULL, 0, NULL, 0, NULL}
 };
 
+static struct dropbear_kex kex_dh_group1 = {dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
+static struct dropbear_kex kex_dh_group14 = {dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
+
+#ifdef DROPBEAR_ECDH
+#ifdef DROPBEAR_ECC_256
+static struct dropbear_kex kex_ecdh_nistp256 = {NULL, 0, &ecc_curve_nistp256, &sha256_desc };
+#endif
+#ifdef DROPBEAR_ECC_384
+static struct dropbear_kex kex_ecdh_nistp384 = {NULL, 0, &ecc_curve_nistp384, &sha384_desc };
+#endif
+#ifdef DROPBEAR_ECC_521
+static struct dropbear_kex kex_ecdh_nistp521 = {NULL, 0, &ecc_curve_nistp521, &sha512_desc };
+#endif
+#endif // DROPBEAR_ECDH
+
+
 algo_type sshkex[] = {
-	{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
-	{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
+#ifdef DROPBEAR_ECDH
+#ifdef DROPBEAR_ECC_256
+	{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
+#endif
+#ifdef DROPBEAR_ECC_384
+	{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
+#endif
+#ifdef DROPBEAR_ECC_521
+	{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
+#endif
+#endif
+	{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
+	{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
 #ifdef USE_KEXGUESS2
 	{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
 #endif
 	{NULL, 0, NULL, 0, NULL}
 };
 
-
-/* Register the compiled in ciphers.
- * This should be run before using any of the ciphers/hashes */
-void crypto_init() {
-
-	const struct ltc_cipher_descriptor *regciphers[] = {
-#ifdef DROPBEAR_AES
-		&aes_desc,
-#endif
-#ifdef DROPBEAR_BLOWFISH
-		&blowfish_desc,
-#endif
-#ifdef DROPBEAR_TWOFISH
-		&twofish_desc,
-#endif
-#ifdef DROPBEAR_3DES
-		&des3_desc,
-#endif
-		NULL
-	};
-
-	const struct ltc_hash_descriptor *reghashes[] = {
-		/* we need sha1 for hostkey stuff regardless */
-		&sha1_desc,
-#ifdef DROPBEAR_MD5_HMAC
-		&md5_desc,
-#endif
-#ifdef DROPBEAR_SHA2_256_HMAC
-		&sha256_desc,
-#endif
-#ifdef DROPBEAR_SHA2_512_HMAC
-		&sha512_desc,
-#endif
-		NULL
-	};	
-	int i;
-	
-	for (i = 0; regciphers[i] != NULL; i++) {
-		if (register_cipher(regciphers[i]) == -1) {
-			dropbear_exit("Error registering crypto");
-		}
-	}
-
-	for (i = 0; reghashes[i] != NULL; i++) {
-		if (register_hash(reghashes[i]) == -1) {
-			dropbear_exit("Error registering crypto");
-		}
-	}
-}
-
 /* algolen specifies the length of algo, algos is our local list to match
  * against.
  * Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
--- a/common-kex.c	Mon May 13 21:35:13 2013 +0800
+++ b/common-kex.c	Tue May 21 12:09:35 2013 +0800
@@ -34,10 +34,11 @@
 #include "bignum.h"
 #include "random.h"
 #include "runopts.h"
+#include "ecc.h"
+#include "crypto_desc.h"
 
 /* diffie-hellman-group1-sha1 value for p */
-#define DH_P_1_LEN 128
-static const unsigned char dh_p_1[DH_P_1_LEN] = {
+const unsigned char dh_p_1[DH_P_1_LEN] = {
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
     0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
@@ -51,8 +52,7 @@
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
 /* diffie-hellman-group14-sha1 value for p */
-#define DH_P_14_LEN 256
-static const unsigned char dh_p_14[DH_P_14_LEN] = {
+const unsigned char dh_p_14[DH_P_14_LEN] = {
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 
     0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 
 	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
@@ -87,8 +87,9 @@
 #endif
 static void read_kex_algos();
 /* helper function for gen_new_keys */
-static void hashkeys(unsigned char *out, int outlen, 
-		const hash_state * hs, unsigned const char X);
+static void hashkeys(unsigned char *out, unsigned int outlen, 
+		const hash_state * hs, const unsigned char X);
+static void finish_kexhashbuf(void);
 
 
 /* Send our list of algorithms we can use */
@@ -150,7 +151,7 @@
 	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
 
 	if (ses.send_kex_first_guess) {
-		ses.newkeys->algo_kex = sshkex[0].val;
+		ses.newkeys->algo_kex = sshkex[0].data;
 		ses.newkeys->algo_hostkey = sshhostkey[0].val;
 		ses.send_kex_first_guess();
 	}
@@ -279,26 +280,28 @@
  * out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
  *
  * See Section 7.2 of rfc4253 (ssh transport) for details */
-static void hashkeys(unsigned char *out, int outlen, 
+static void hashkeys(unsigned char *out, unsigned int outlen, 
 		const hash_state * hs, const unsigned char X) {
 
+	const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
 	hash_state hs2;
-	int offset;
+	unsigned int offset;
+	unsigned char tmpout[hash_desc->hashsize];
 
 	memcpy(&hs2, hs, sizeof(hash_state));
-	sha1_process(&hs2, &X, 1);
-	sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
-	sha1_done(&hs2, out);
-	for (offset = SHA1_HASH_SIZE; 
+	hash_desc->process(&hs2, &X, 1);
+	hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len);
+	hash_desc->done(&hs2, tmpout);
+	memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen));
+	for (offset = hash_desc->hashsize; 
 			offset < outlen; 
-			offset += SHA1_HASH_SIZE)
+			offset += hash_desc->hashsize)
 	{
 		/* need to extend */
-		unsigned char k2[SHA1_HASH_SIZE];
 		memcpy(&hs2, hs, sizeof(hash_state));
-		sha1_process(&hs2, out, offset);
-		sha1_done(&hs2, k2);
-		memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
+		hash_desc->process(&hs2, out, offset);
+		hash_desc->done(&hs2, tmpout);
+		memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
 	}
 }
 
@@ -319,26 +322,26 @@
 	unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
 
 	hash_state hs;
-	unsigned int C2S_keysize, S2C_keysize;
+	const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
 	char mactransletter, macrecvletter; /* Client or server specific */
 
 	TRACE(("enter gen_new_keys"))
 	/* the dh_K and hash are the start of all hashes, we make use of that */
 
-	sha1_init(&hs);
-	sha1_process_mp(&hs, ses.dh_K);
+	hash_desc->init(&hs);
+	hash_process_mp(hash_desc, &hs, ses.dh_K);
 	mp_clear(ses.dh_K);
 	m_free(ses.dh_K);
-	sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
-	m_burn(ses.hash, SHA1_HASH_SIZE);
+	hash_desc->process(&hs, ses.hash->data, ses.hash->len);
+	buf_burn(ses.hash);
+	buf_free(ses.hash);
+	ses.hash = NULL;
 
 	if (IS_DROPBEAR_CLIENT) {
 	    trans_IV	= C2S_IV;
 	    recv_IV		= S2C_IV;
 	    trans_key	= C2S_key;
 	    recv_key	= S2C_key;
-	    C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
-	    S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
 		mactransletter = 'E';
 		macrecvletter = 'F';
 	} else {
@@ -346,16 +349,14 @@
 	    recv_IV		= C2S_IV;
 	    trans_key	= S2C_key;
 	    recv_key	= C2S_key;
-	    C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
-	    S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
 		mactransletter = 'F';
 		macrecvletter = 'E';
 	}
 
-	hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A');
-	hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B');
-	hashkeys(C2S_key, C2S_keysize, &hs, 'C');
-	hashkeys(S2C_key, S2C_keysize, &hs, 'D');
+	hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A');
+	hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B');
+	hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C');
+	hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
 
 	if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
 		int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
@@ -381,16 +382,16 @@
 		}
 	}
 
-	if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
+	if (ses.newkeys->trans.algo_mac->hash_desc != NULL) {
 		hashkeys(ses.newkeys->trans.mackey, 
 				ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
-		ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
+		ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name);
 	}
 
-	if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
+	if (ses.newkeys->recv.algo_mac->hash_desc != NULL) {
 		hashkeys(ses.newkeys->recv.mackey, 
 				ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
-		ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
+		ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name);
 	}
 
 	/* Ready to switch over */
@@ -560,28 +561,23 @@
 
 static void load_dh_p(mp_int * dh_p)
 {
-	switch (ses.newkeys->algo_kex) {
-		case DROPBEAR_KEX_DH_GROUP1:
-			bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
-			break;
-		case DROPBEAR_KEX_DH_GROUP14:
-			bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
-			break;
-	}
+	bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes, 
+		ses.newkeys->algo_kex->dh_p_len);
 }
 
 /* Initialises and generate one side of the diffie-hellman key exchange values.
  * See the transport rfc 4253 section 8 for details */
 /* dh_pub and dh_priv MUST be already initialised */
-void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
+struct kex_dh_param *gen_kexdh_param() {
 
 	DEF_MP_INT(dh_p);
 	DEF_MP_INT(dh_q);
 	DEF_MP_INT(dh_g);
 
 	TRACE(("enter gen_kexdh_vals"))
-	
-	m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
+
+	struct kex_dh_param *param = m_malloc(sizeof(*param));
+	m_mp_init_multi(&param->pub, &param->priv, NULL);
 
 	/* read the prime and generator*/
 	load_dh_p(&dh_p);
@@ -592,33 +588,39 @@
 
 	/* calculate q = (p-1)/2 */
 	/* dh_priv is just a temp var here */
-	if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) { 
+	if (mp_sub_d(&dh_p, 1, &param->priv) != MP_OKAY) { 
 		dropbear_exit("Diffie-Hellman error");
 	}
-	if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
+	if (mp_div_2(&param->priv, &dh_q) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
 	}
 
 	/* Generate a private portion 0 < dh_priv < dh_q */
-	gen_random_mpint(&dh_q, dh_priv);
+	gen_random_mpint(&dh_q, &param->priv);
 
 	/* f = g^y mod p */
-	if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
+	if (mp_exptmod(&dh_g, &param->priv, &dh_p, &param->pub) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
 	}
 	mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
+	return param;
+}
+
+void free_kexdh_param(struct kex_dh_param *param)
+{
+	mp_clear_multi(&param->pub, &param->priv, NULL);
+	m_free(param);
 }
 
 /* This function is fairly common between client/server, with some substitution
  * of dh_e/dh_f etc. Hence these arguments:
  * dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is 
  * vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
-void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
+void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
 		sign_key *hostkey) {
 
 	mp_int dh_p;
 	mp_int *dh_e = NULL, *dh_f = NULL;
-	hash_state hs;
 
 	/* read the prime and generator*/
 	m_mp_init(&dh_p);
@@ -633,7 +635,7 @@
 	/* K = e^y mod p = f^x mod p */
 	ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
 	m_mp_init(ses.dh_K);
-	if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
+	if (mp_exptmod(dh_pub_them, &param->priv, &dh_p, ses.dh_K) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
 	}
 
@@ -643,11 +645,11 @@
 	/* From here on, the code needs to work with the _same_ vars on each side,
 	 * not vice-versaing for client/server */
 	if (IS_DROPBEAR_CLIENT) {
-		dh_e = dh_pub_us;
+		dh_e = &param->pub;
 		dh_f = dh_pub_them;
 	} else {
 		dh_e = dh_pub_them;
-		dh_f = dh_pub_us;
+		dh_f = &param->pub;
 	} 
 
 	/* Create the remainder of the hash buffer, to generate the exchange hash */
@@ -661,11 +663,70 @@
 	buf_putmpint(ses.kexhashbuf, ses.dh_K);
 
 	/* calculate the hash H to sign */
-	sha1_init(&hs);
+	finish_kexhashbuf();
+}
+
+#ifdef DROPBEAR_ECDH
+struct kex_ecdh_param *gen_kexecdh_param() {
+	struct kex_ecdh_param *param = m_malloc(sizeof(*param));
+	if (ecc_make_key_ex(NULL, dropbear_ltc_prng, 
+		&param->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) {
+		dropbear_exit("ECC error");
+	}
+	return param;
+}
+
+void free_kexecdh_param(struct kex_ecdh_param *param) {
+	ecc_free(&param->key);
+	m_free(param);
+
+}
+void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
+		sign_key *hostkey) {
+	const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex;
+	// public keys from client and server
+	ecc_key *Q_C, *Q_S, *Q_them;
+
+	Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
+
+	ses.dh_K = dropbear_ecc_shared_secret(Q_them, &param->key);
+
+	/* From here on, the code needs to work with the _same_ vars on each side,
+	 * not vice-versaing for client/server */
+	if (IS_DROPBEAR_CLIENT) {
+		Q_C = &param->key;
+		Q_S = Q_them;
+	} else {
+		Q_C = Q_them;
+		Q_S = &param->key;
+	} 
+
+	/* Create the remainder of the hash buffer, to generate the exchange hash */
+	/* K_S, the host key */
+	buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
+	/* Q_C, client's ephemeral public key octet string */
+	buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_C);
+	/* Q_S, server's ephemeral public key octet string */
+	buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_S);
+	/* K, the shared secret */
+	buf_putmpint(ses.kexhashbuf, ses.dh_K);
+
+	/* calculate the hash H to sign */
+	finish_kexhashbuf();
+}
+#endif
+
+static void finish_kexhashbuf(void) {
+	hash_state hs;
+	const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
+
+	hash_desc->init(&hs);
 	buf_setpos(ses.kexhashbuf, 0);
-	sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
+	hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
 			ses.kexhashbuf->len);
-	sha1_done(&hs, ses.hash);
+	ses.hash = buf_new(hash_desc->hashsize);
+	hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize));
+	buf_setlen(ses.hash, hash_desc->hashsize);
 
 	buf_burn(ses.kexhashbuf);
 	buf_free(ses.kexhashbuf);
@@ -674,9 +735,9 @@
 	/* first time around, we set the session_id to H */
 	if (ses.session_id == NULL) {
 		/* create the session_id, this never needs freeing */
-		ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
-		memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
+		ses.session_id = buf_newcopy(ses.hash);
 	}
+
 }
 
 /* read the other side's algo list. buf_match_algo is a callback to match
@@ -719,7 +780,7 @@
 	}
 	TRACE(("kexguess2 %d", kexguess2))
 	TRACE(("kex algo %s", algo->name))
-	ses.newkeys->algo_kex = algo->val;
+	ses.newkeys->algo_kex = algo->data;
 
 	/* server_host_key_algorithms */
 	algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
--- a/common-session.c	Mon May 13 21:35:13 2013 +0800
+++ b/common-session.c	Tue May 21 12:09:35 2013 +0800
@@ -101,7 +101,7 @@
 	ses.keys->recv.algo_mac = &dropbear_nohash;
 	ses.keys->trans.algo_mac = &dropbear_nohash;
 
-	ses.keys->algo_kex = -1;
+	ses.keys->algo_kex = NULL;
 	ses.keys->algo_hostkey = -1;
 	ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
 	ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
@@ -245,7 +245,16 @@
 		ses.extra_session_cleanup();
 	}
 	
-	m_free(ses.session_id);
+	if (ses.session_id) {
+		buf_burn(ses.session_id);
+		buf_free(ses.session_id);
+		ses.session_id = NULL;
+	}
+	if (ses.hash) {
+		buf_burn(ses.hash);
+		buf_free(ses.hash);
+		ses.hash = NULL;
+	}
 	m_burn(ses.keys, sizeof(struct key_context));
 	m_free(ses.keys);
 
--- a/configure.ac	Mon May 13 21:35:13 2013 +0800
+++ b/configure.ac	Tue May 21 12:09:35 2013 +0800
@@ -685,7 +685,7 @@
 AS_MKDIR_P(libtomcrypt/src/pk/ecc)
 AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
 AS_MKDIR_P(libtomcrypt/src/pk/rsa)
-AS_MKDIR_P(libtomcrypt/src/prng)
+AS_MKDIR_P(libtomcrypt/src/prngs)
 AC_CONFIG_HEADER(config.h)
 AC_OUTPUT(Makefile)
 AC_OUTPUT(libtomcrypt/Makefile)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto_desc.c	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,75 @@
+#include "includes.h"
+#include "dbutil.h"
+#include "crypto_desc.h"
+#include "ltc_prng.h"
+#include "ecc.h"
+
+#ifdef DROPBEAR_LTC_PRNG
+	int dropbear_ltc_prng = -1;
+#endif
+
+
+/* Register the compiled in ciphers.
+ * This should be run before using any of the ciphers/hashes */
+void crypto_init() {
+
+	const struct ltc_cipher_descriptor *regciphers[] = {
+#ifdef DROPBEAR_AES
+		&aes_desc,
+#endif
+#ifdef DROPBEAR_BLOWFISH
+		&blowfish_desc,
+#endif
+#ifdef DROPBEAR_TWOFISH
+		&twofish_desc,
+#endif
+#ifdef DROPBEAR_3DES
+		&des3_desc,
+#endif
+		NULL
+	};
+
+	const struct ltc_hash_descriptor *reghashes[] = {
+		/* we need sha1 for hostkey stuff regardless */
+		&sha1_desc,
+#ifdef DROPBEAR_MD5_HMAC
+		&md5_desc,
+#endif
+#ifdef DROPBEAR_SHA256
+		&sha256_desc,
+#endif
+#ifdef DROPBEAR_SHA384
+		&sha384_desc,
+#endif
+#ifdef DROPBEAR_SHA512
+		&sha512_desc,
+#endif
+		NULL
+	};	
+	int i;
+	
+	for (i = 0; regciphers[i] != NULL; i++) {
+		if (register_cipher(regciphers[i]) == -1) {
+			dropbear_exit("Error registering crypto");
+		}
+	}
+
+	for (i = 0; reghashes[i] != NULL; i++) {
+		if (register_hash(reghashes[i]) == -1) {
+			dropbear_exit("Error registering crypto");
+		}
+	}
+
+#ifdef DROPBEAR_LTC_PRNG
+	dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
+	if (dropbear_ltc_prng == -1) {
+		dropbear_exit("Error registering crypto");
+	}
+#endif
+
+#ifdef DROPBEAR_ECC
+	ltc_mp = ltm_desc;
+	dropbear_ecc_fill_dp();
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto_desc.h	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,9 @@
+#ifndef _CRYPTO_DESC_H
+#define _CRYPTO_DESC_H
+
+void crypto_init();
+
+extern int dropbear_ltc_prng;
+
+#endif // _CRYPTO_DESC_H
+
--- a/dbutil.c	Mon May 13 21:35:13 2013 +0800
+++ b/dbutil.c	Tue May 21 12:09:35 2013 +0800
@@ -675,6 +675,14 @@
 	}
 	fprintf(stderr, "\n");
 }
+
+void printmpint(const char *label, mp_int *mp) {
+	buffer *buf = buf_new(1000);
+	buf_putmpint(buf, mp);
+	printhex(label, buf->data, buf->len);
+	buf_free(buf);
+
+}
 #endif
 
 /* Strip all control characters from text (a null-terminated string), except
--- a/dbutil.h	Mon May 13 21:35:13 2013 +0800
+++ b/dbutil.h	Tue May 21 12:09:35 2013 +0800
@@ -57,6 +57,7 @@
 void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
 void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
 void printhex(const char * label, const unsigned char * buf, int len);
+void printmpint(const char *label, mp_int *mp);
 extern int debug_trace;
 #endif
 
--- a/debug.h	Mon May 13 21:35:13 2013 +0800
+++ b/debug.h	Tue May 21 12:09:35 2013 +0800
@@ -40,6 +40,7 @@
  * since the printing may not sanitise strings etc. This will add a reasonable
  * amount to your executable size. */
 /* #define DEBUG_TRACE */
+#define DEBUG_TRACE
 
 /* All functions writing to the cleartext payload buffer call
  * CHECKCLEARTOWRITE() before writing. This is only really useful if you're
@@ -71,7 +72,7 @@
 
 /* To debug with GDB it is easier to run with no forking of child processes.
    You will need to pass "-F" as well. */
-/* #define DEBUG_NOFORK */
+#define DEBUG_NOFORK
 
 
 /* For testing as non-root on shadowed systems, include the crypt of a password
--- a/dropbearkey.c	Mon May 13 21:35:13 2013 +0800
+++ b/dropbearkey.c	Tue May 21 12:09:35 2013 +0800
@@ -51,11 +51,14 @@
 
 #include "genrsa.h"
 #include "gendss.h"
+#include "ecdsa.h"
+#include "crypto_desc.h"
+#include "random.h"
 
 static void printhelp(char * progname);
 
-#define RSA_SIZE (1024/8) /* 1024 bit */
-#define DSS_SIZE (1024/8) /* 1024 bit */
+#define RSA_DEFAULT_SIZE 1024
+#define DSS_DEFAULT_SIZE 1024
 
 static void buf_writefile(buffer * buf, const char * filename);
 static void printpubkey(sign_key * key, int keytype);
@@ -72,9 +75,27 @@
 #ifdef DROPBEAR_DSS
 					"		dss\n"
 #endif
+#ifdef DROPBEAR_ECDSA
+					"		ecdsa\n"
+#endif
 					"-f filename	Use filename for the secret key\n"
 					"-s bits	Key size in bits, should be a multiple of 8 (optional)\n"
-					"           (DSS has a fixed size of 1024 bits)\n"
+#ifdef DROPBEAR_DSS
+					"           DSS has a fixed size of 1024 bits\n"
+#endif
+#ifdef DROPBEAR_ECDSA
+					"           ECDSA has sizes "
+#ifdef DROPBEAR_ECC_256
+					"256 "
+#endif
+#ifdef DROPBEAR_ECC_384
+					"384 "
+#endif
+#ifdef DROPBEAR_ECC_521
+					"521 "
+#endif
+					"\n"
+#endif
 					"-y		Just print the publickey and fingerprint for the\n		private key in <filename>.\n"
 #ifdef DEBUG_TRACE
 					"-v		verbose\n"
@@ -94,13 +115,15 @@
 	sign_key *key = NULL;
 	buffer *buf = NULL;
 	char * filename = NULL;
-	int keytype = -1;
+	enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
 	char * typetext = NULL;
 	char * sizetext = NULL;
 	unsigned int bits;
-	unsigned int keysize;
 	int printpub = 0;
 
+	crypto_init();
+	seedrandom();
+
 	/* get the commandline options */
 	for (i = 1; i < argc; i++) {
 		if (argv[i] == NULL) {
@@ -162,21 +185,9 @@
 		exit(EXIT_FAILURE);
 	}
 
-	if (strlen(typetext) == 3) {
-#ifdef DROPBEAR_RSA
-		if (strncmp(typetext, "rsa", 3) == 0) {
-			keytype = DROPBEAR_SIGNKEY_RSA;
-			TRACE(("type is rsa"))
-		}
-#endif
-#ifdef DROPBEAR_DSS
-		if (strncmp(typetext, "dss", 3) == 0) {
-			keytype = DROPBEAR_SIGNKEY_DSS;
-			TRACE(("type is dss"))
-		}
-#endif
-	}
-	if (keytype == -1) {
+	keytype = signkey_type_from_name(typetext, strlen(typetext));
+
+	if (keytype == DROPBEAR_SIGNKEY_NONE) {
 		fprintf(stderr, "Unknown key type '%s'\n", typetext);
 		printhelp(argv[0]);
 		exit(EXIT_FAILURE);
@@ -188,28 +199,51 @@
 			exit(EXIT_FAILURE);
 		}
 		
-		if (keytype == DROPBEAR_SIGNKEY_DSS && bits != 1024) {
-			fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
-			exit(EXIT_FAILURE);			
-		} else if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
-			fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
-					" multiple of 8\n");
-			exit(EXIT_FAILURE);
-		}
+		// TODO: put RSA and DSS size checks into genrsa.c etc
+        switch (keytype) {
+#ifdef DROPBEAR_RSA
+            case DROPBEAR_SIGNKEY_RSA:
+                if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
+                    fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
+                            " multiple of 8\n");
+                    exit(EXIT_FAILURE);
+                }
+                break;
+#endif
+#ifdef DROPEAR_DSS
+            case DROPBEAR_SIGNKEY_DSS:
+                if (bits != 1024) {
+                    fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
+                    exit(EXIT_FAILURE);			
+                }
+#endif
+			default:
+				(void)0; /* quiet, compiler. ecdsa handles checks itself */
+        }
 
-		keysize = bits / 8;
-	} else {
-		if (keytype == DROPBEAR_SIGNKEY_DSS) {
-			keysize = DSS_SIZE;
-		} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
-			keysize = RSA_SIZE;
-		} else {
-			exit(EXIT_FAILURE); /* not reached */
+        switch (keytype) {
+#ifdef DROPBEAR_RSA
+            case DROPBEAR_SIGNKEY_RSA:
+                bits = RSA_DEFAULT_SIZE;
+                break;
+#endif
+#ifdef DROPBEAR_DSS
+            case DROPBEAR_SIGNKEY_DSS:
+                bits = DSS_DEFAULT_SIZE;
+                break;
+#endif
+#ifdef DROPBEAR_ECDSA
+            case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
+                bits = ECDSA_DEFAULT_SIZE;
+                break;
+#endif
+            default:
+                exit(EXIT_FAILURE); /* not reached */
 		}
 	}
 
 
-	fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
+	fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", bits,
 			typetext, filename);
 
 	/* don't want the file readable by others */
@@ -222,12 +256,18 @@
 	switch(keytype) {
 #ifdef DROPBEAR_RSA
 		case DROPBEAR_SIGNKEY_RSA:
-			key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
+			key->rsakey = gen_rsa_priv_key(bits);
 			break;
 #endif
 #ifdef DROPBEAR_DSS
 		case DROPBEAR_SIGNKEY_DSS:
-			key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
+			key->dsskey = gen_dss_priv_key(bits);
+			break;
+#endif
+#ifdef DROPBEAR_ECDSA
+		case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
+			key->ecckey = gen_ecdsa_priv_key(bits);
+			keytype = ecdsa_signkey_type(key->ecckey);
 			break;
 #endif
 		default:
@@ -319,7 +359,7 @@
 		fprintf(stderr, "base64 failed");
 	}
 
-	typestring = signkey_name_from_type(keytype, &err);
+	typestring = signkey_name_from_type(keytype, NULL);
 
 	fp = sign_key_fingerprint(buf_getptr(buf, len), len);
 
--- a/dss.c	Mon May 13 21:35:13 2013 +0800
+++ b/dss.c	Tue May 21 12:09:35 2013 +0800
@@ -161,9 +161,7 @@
 #ifdef DROPBEAR_SIGNKEY_VERIFY
 /* Verify a DSS signature (in buf) made on data by the key given. 
  * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
-		unsigned int len) {
-
+int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
 	unsigned char msghash[SHA1_HASH_SIZE];
 	hash_state hs;
 	int ret = DROPBEAR_FAILURE;
@@ -187,7 +185,7 @@
 
 	/* hash the data */
 	sha1_init(&hs);
-	sha1_process(&hs, data, len);
+	sha1_process(&hs, data_buf->data, data_buf->len);
 	sha1_done(&hs, msghash);
 
 	/* create the signature - s' and r' are the received signatures in buf */
@@ -260,9 +258,7 @@
 
 /* Sign the data presented with key, writing the signature contents
  * to the buffer */
-void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
-		unsigned int len) {
-
+void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
 	unsigned char msghash[SHA1_HASH_SIZE];
 	unsigned int writelen;
 	unsigned int i;
@@ -279,7 +275,7 @@
 	
 	/* hash the data */
 	sha1_init(&hs);
-	sha1_process(&hs, data, len);
+	sha1_process(&hs, data_buf->data, data_buf->len);
 	sha1_done(&hs, msghash);
 
 	m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
--- a/dss.h	Mon May 13 21:35:13 2013 +0800
+++ b/dss.h	Tue May 21 12:09:35 2013 +0800
@@ -30,8 +30,6 @@
 
 #ifdef DROPBEAR_DSS 
 
-#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
-
 typedef struct {
 
 	mp_int* p;
@@ -43,11 +41,9 @@
 
 } dropbear_dss_key;
 
-void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
-		unsigned int len);
+void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
 #ifdef DROPBEAR_SIGNKEY_VERIFY
-int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
-		unsigned int len);
+int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
 #endif
 int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
 int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ecc.c	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,274 @@
+#include "includes.h"
+#include "options.h"
+#include "ecc.h"
+#include "dbutil.h"
+#include "bignum.h"
+
+#ifdef DROPBEAR_ECC
+
+// .dp members are filled out by dropbear_ecc_fill_dp() at startup
+#ifdef DROPBEAR_ECC_256
+struct dropbear_ecc_curve ecc_curve_nistp256 = {
+	.ltc_size = 32,
+	.hash_desc = &sha256_desc,
+	.name = "nistp256"
+};
+#endif
+#ifdef DROPBEAR_ECC_384
+struct dropbear_ecc_curve ecc_curve_nistp384 = {
+	.ltc_size = 48,
+	.hash_desc = &sha384_desc,
+	.name = "nistp384"
+};
+#endif
+#ifdef DROPBEAR_ECC_521
+struct dropbear_ecc_curve ecc_curve_nistp521 = {
+	.ltc_size = 66,
+	.hash_desc = &sha512_desc,
+	.name = "nistp521"
+};
+#endif
+
+struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
+#ifdef DROPBEAR_ECC_256
+	&ecc_curve_nistp256,
+#endif
+#ifdef DROPBEAR_ECC_384
+	&ecc_curve_nistp384,
+#endif
+#ifdef DROPBEAR_ECC_521
+	&ecc_curve_nistp521,
+#endif
+	NULL
+};
+
+void dropbear_ecc_fill_dp() {
+	struct dropbear_ecc_curve **curve;
+	// libtomcrypt guarantees they're ordered by size
+	const ltc_ecc_set_type *dp = ltc_ecc_sets;
+	for (curve = dropbear_ecc_curves; *curve; curve++) {
+		for (;dp->size > 0; dp++) {
+			if (dp->size == (*curve)->ltc_size) {
+				(*curve)->dp = dp;
+				break;
+			}
+		}
+		if (!(*curve)->dp) {
+			dropbear_exit("Missing ECC params %s", (*curve)->name);
+		}
+	}
+}
+
+struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
+	struct dropbear_ecc_curve **curve = NULL;
+	for (curve = dropbear_ecc_curves; *curve; curve++) {
+		if ((*curve)->dp == dp) {
+			break;
+		}
+	}
+	assert(*curve);
+	return *curve;
+}
+
+ecc_key * new_ecc_key(void) {
+	ecc_key *key = m_malloc(sizeof(*key));
+	key->pubkey.x = m_malloc(sizeof(mp_int));
+	key->pubkey.y = m_malloc(sizeof(mp_int));
+	key->pubkey.z = m_malloc(sizeof(mp_int));
+	key->k = m_malloc(sizeof(mp_int));
+	m_mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);
+	return key;
+}
+
+// Copied from libtomcrypt ecc_import.c (version there is static), modified
+// for different mp_int pointer without LTC_SOURCE
+static int ecc_is_point(ecc_key *key)
+{
+	mp_int *prime, *b, *t1, *t2;
+	int err;
+
+	prime = m_malloc(sizeof(mp_int));
+	b = m_malloc(sizeof(mp_int));
+	t1 = m_malloc(sizeof(mp_int));
+	t2 = m_malloc(sizeof(mp_int));
+	
+	m_mp_init_multi(prime, b, t1, t2, NULL);
+	
+   /* load prime and b */
+	if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK)                          { goto error; }
+	if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK)                                  { goto error; }
+	
+   /* compute y^2 */
+	if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK)                                         { goto error; }
+	
+   /* compute x^3 */
+	if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK)                                         { goto error; }
+	if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK)                                             { goto error; }
+	if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK)                                     { goto error; }
+	
+   /* compute y^2 - x^3 */
+	if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK)                                                { goto error; }
+	
+   /* compute y^2 - x^3 + 3x */
+	if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK)                                     { goto error; }
+	if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK)                                     { goto error; }
+	if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK)                                     { goto error; }
+	if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK)                                             { goto error; }
+	while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
+		if ((err = mp_add(t1, prime, t1)) != CRYPT_OK)                                          { goto error; }
+	}
+	while (mp_cmp(t1, prime) != LTC_MP_LT) {
+		if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK)                                          { goto error; }
+	}
+	
+   /* compare to b */
+	if (mp_cmp(t1, b) != LTC_MP_EQ) {
+		err = CRYPT_INVALID_PACKET;
+	} else {
+		err = CRYPT_OK;
+	}
+	
+	error:
+	mp_clear_multi(prime, b, t1, t2, NULL);
+	m_free(prime);
+	m_free(b);
+	m_free(t1);
+	m_free(t2);
+	return err;
+}
+
+/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
+void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) {
+	unsigned long len = key->dp->size*2 + 1;
+	buf_putint(buf, len);
+	int err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len);
+	if (err != CRYPT_OK) {
+		dropbear_exit("ECC error");
+	}
+	buf_incrwritepos(buf, len);
+}
+
+/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
+ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) {
+	ecc_key *key = NULL;
+	int ret = DROPBEAR_FAILURE;
+	const unsigned int size = curve->dp->size;
+	unsigned char first;
+
+	TRACE(("enter buf_get_ecc_raw_pubkey"))
+
+	buf_setpos(buf, 0);
+	first = buf_getbyte(buf);
+	if (first == 2 || first == 3) {
+		dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression");
+		return NULL;
+	}
+	if (first != 4 || buf->len != 1+2*size) {
+		TRACE(("leave, wrong size"))
+		return NULL;
+	}
+
+	key = new_ecc_key();
+	key->dp = curve->dp;
+
+	if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
+		TRACE(("failed to read x"))
+		goto out;
+	}
+	buf_incrpos(buf, size);
+
+	if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
+		TRACE(("failed to read y"))
+		goto out;
+	}
+	buf_incrpos(buf, size);
+
+	mp_set(key->pubkey.z, 1);
+
+	if (ecc_is_point(key) != CRYPT_OK) {
+		TRACE(("failed, not a point"))
+		goto out;
+	}
+
+   // SEC1 3.2.3.1 Check that Q != 0
+	if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) {
+		TRACE(("failed, x == 0"))
+		goto out;
+	}
+	if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) {
+		TRACE(("failed, y == 0"))
+		goto out;
+	}
+
+	ret = DROPBEAR_SUCCESS;
+
+	out:
+	if (ret == DROPBEAR_FAILURE) {
+		if (key) {
+			ecc_free(key);
+			m_free(key);
+			key = NULL;
+		}
+	}
+
+	return key;
+
+}
+
+// a modified version of libtomcrypt's "ecc_shared_secret" to output
+// a mp_int instead.
+mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
+{
+	ecc_point *result = NULL;
+	mp_int *prime = NULL, *shared_secret = NULL;
+	int err = DROPBEAR_FAILURE;
+
+   /* type valid? */
+	if (private_key->type != PK_PRIVATE) {
+		goto done;
+	}
+
+	if (private_key->dp != public_key->dp) {
+		goto done;
+	}
+
+   /* make new point */
+	result = ltc_ecc_new_point();
+	if (result == NULL) {
+		goto done;
+	}
+
+	prime = m_malloc(sizeof(*prime));
+	m_mp_init(prime);
+
+	if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) { 
+		goto done; 
+	}
+	if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) { 
+		goto done; 
+	}
+
+	err = DROPBEAR_SUCCESS;
+	done:
+	if (err == DROPBEAR_SUCCESS) {
+		shared_secret = m_malloc(sizeof(*shared_secret));
+		m_mp_init(shared_secret);
+		mp_copy(result->x, shared_secret);
+	}
+
+	if (prime) {
+		mp_clear(prime);
+		m_free(prime);
+	}
+	if (result)
+	{
+		ltc_ecc_del_point(result);
+	}
+
+	if (err == DROPBEAR_FAILURE) {
+		dropbear_exit("ECC error");
+	}
+	return shared_secret;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ecc.h	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,36 @@
+#ifndef _DROPBEAR_ECC_H
+#define _DROPBEAR_ECC_H
+
+#include "includes.h"
+#include "options.h"
+
+#include "buffer.h"
+
+#ifdef DROPBEAR_ECC
+
+struct dropbear_ecc_curve {
+	int ltc_size; // to match the byte sizes in ltc_ecc_sets[]
+	const ltc_ecc_set_type *dp; // curve domain parameters
+	const struct ltc_hash_descriptor *hash_desc;
+	const unsigned char *name;
+};
+
+extern struct dropbear_ecc_curve ecc_curve_nistp256;
+extern struct dropbear_ecc_curve ecc_curve_nistp384;
+extern struct dropbear_ecc_curve ecc_curve_nistp521;
+extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
+
+void dropbear_ecc_fill_dp();
+struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
+
+// "pubkey" refers to a point, but LTC uses ecc_key structure for both public
+// and private keys
+void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key);
+ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve);
+int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
+
+mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
+
+#endif
+
+#endif // _DROPBEAR_ECC_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ecdsa.c	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,412 @@
+#include "options.h"
+#include "includes.h"
+#include "dbutil.h"
+#include "crypto_desc.h"
+#include "ecc.h"
+#include "ecdsa.h"
+#include "signkey.h"
+
+#ifdef DROPBEAR_ECDSA
+
+enum signkey_type ecdsa_signkey_type(ecc_key * key) {
+#ifdef DROPBEAR_ECC_256
+	if (key->dp == ecc_curve_nistp256.dp) {
+		return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
+	}
+#endif
+#ifdef DROPBEAR_ECC_384
+	if (key->dp == ecc_curve_nistp384.dp) {
+		return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
+	}
+#endif
+#ifdef DROPBEAR_ECC_521
+	if (key->dp == ecc_curve_nistp521.dp) {
+		return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
+	}
+#endif
+	return DROPBEAR_SIGNKEY_NONE;
+}
+
+ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
+	const ltc_ecc_set_type *dp = NULL; // curve domain parameters
+	switch (bit_size) {
+#ifdef DROPBEAR_ECC_256
+		case 256:
+			dp = ecc_curve_nistp256.dp;
+			break;
+#endif
+#ifdef DROPBEAR_ECC_384
+		case 384:
+			dp = ecc_curve_nistp384.dp;
+			break;
+#endif
+#ifdef DROPBEAR_ECC_521
+		case 521:
+			dp = ecc_curve_nistp521.dp;
+			break;
+#endif
+	}
+	if (!dp) {
+		dropbear_exit("Key size %d isn't valid. Try "
+#ifdef DROPBEAR_ECC_256
+			"256 "
+#endif
+#ifdef DROPBEAR_ECC_384
+			"384 "
+#endif
+#ifdef DROPBEAR_ECC_521
+			"521 "
+#endif
+			, bit_size);
+	}
+
+	ecc_key *new_key = m_malloc(sizeof(*new_key));
+	if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) {
+		dropbear_exit("ECC error");
+	}
+	return new_key;
+}
+
+ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
+	unsigned char *key_ident = NULL, *identifier = NULL;
+	unsigned int key_ident_len, identifier_len;
+	buffer *q_buf = NULL;
+	struct dropbear_ecc_curve **curve;
+	ecc_key *new_key = NULL;
+
+	// string   "ecdsa-sha2-[identifier]"
+	key_ident = buf_getstring(buf, &key_ident_len);
+	// string   "[identifier]"
+	identifier = buf_getstring(buf, &identifier_len);
+
+	if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
+		TRACE(("Bad identifier lengths"))
+		goto out;
+	}
+	if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
+		TRACE(("mismatching identifiers"))
+		goto out;
+	}
+
+	for (curve = dropbear_ecc_curves; *curve; curve++) {
+		if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) {
+			break;
+		}
+	}
+	if (!*curve) {
+		TRACE(("couldn't match ecc curve"))
+		goto out;
+	}
+
+	// string Q
+	q_buf = buf_getstringbuf(buf);
+	new_key = buf_get_ecc_raw_pubkey(q_buf, *curve);
+
+out:
+	m_free(key_ident);
+	m_free(identifier);
+	if (q_buf) {
+		buf_free(q_buf);
+		q_buf = NULL;
+	}
+	TRACE(("leave buf_get_ecdsa_pub_key"))	
+	return new_key;
+}
+
+ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
+	ecc_key *new_key = NULL;
+	TRACE(("enter buf_get_ecdsa_priv_key"))
+	new_key = buf_get_ecdsa_pub_key(buf);
+	if (!new_key) {
+		return NULL;
+	}
+
+	if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
+		ecc_free(new_key);
+		return NULL;
+	}
+
+	return new_key;
+}
+
+void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
+	struct dropbear_ecc_curve *curve = NULL;
+	unsigned char key_ident[30];
+
+	curve = curve_for_dp(key->dp);
+	snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
+	buf_putstring(buf, key_ident, strlen(key_ident));
+	buf_putstring(buf, curve->name, strlen(curve->name));
+	buf_put_ecc_raw_pubkey_string(buf, key);
+}
+
+void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
+	buf_put_ecdsa_pub_key(buf, key);
+	buf_putmpint(buf, key->k);
+}
+
+void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
+	/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
+	int err = DROPBEAR_FAILURE;
+	struct dropbear_ecc_curve *curve = NULL;
+	hash_state hs;
+	unsigned char hash[64];
+	void *e = NULL, *p = NULL, *s = NULL, *r;
+	unsigned char key_ident[30];
+	buffer *sigbuf = NULL;
+
+	TRACE(("buf_put_ecdsa_sign"))
+	curve = curve_for_dp(key->dp);
+
+	if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) { 
+		goto out;
+	}
+
+	curve->hash_desc->init(&hs);
+	curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
+	curve->hash_desc->done(&hs, hash);
+
+	if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
+		goto out;
+	}
+
+	if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) { 
+		goto out; 
+	}
+
+	for (;;) {
+		ecc_key R_key; // ephemeral key
+		if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) {
+			goto out;
+		}
+		if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) {
+			goto out;
+		}
+		if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) {
+			// try again
+			ecc_free(&R_key);
+			continue;
+		}
+		/* k = 1/k */
+		if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) {
+			goto out;
+		}
+		/* s = xr */
+		if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) {
+			goto out;
+		}
+		/* s = e +  xr */
+		if (ltc_mp.add(e, s, s) != CRYPT_OK) {
+			goto out;
+		}
+		if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) {
+			goto out;
+		}
+		/* s = (e + xr)/k */
+		if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) {
+			goto out;
+		}
+		ecc_free(&R_key);
+
+		if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) {
+			break;
+		}
+	}
+
+	snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
+	buf_putstring(buf, key_ident, strlen(key_ident));
+	// enough for nistp521
+	sigbuf = buf_new(200);
+	buf_putmpint(sigbuf, (mp_int*)r);
+	buf_putmpint(sigbuf, (mp_int*)s);
+	buf_putbufstring(buf, sigbuf);
+
+	err = DROPBEAR_SUCCESS;
+
+out:
+	if (r && s && p && e) {
+		ltc_deinit_multi(r, s, p, e, NULL);
+	}
+
+	if (sigbuf) {
+		buf_free(sigbuf);
+	}
+
+	if (err == DROPBEAR_FAILURE) {
+		dropbear_exit("ECC error");
+	}
+}
+
+// returns values in s and r
+// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
+static int buf_get_ecdsa_verify_params(buffer *buf, struct dropbear_ecc_curve *curve,
+	void *r, void* s) {
+	int ret = DROPBEAR_FAILURE;
+	unsigned int sig_len;
+	unsigned int sig_pos;
+
+	sig_len = buf_getint(buf);
+	sig_pos = buf->pos;
+	if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) {
+		goto out;
+	}
+	if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) {
+		goto out;
+	}
+	if (buf->pos - sig_pos != sig_len) {
+		goto out;
+	}
+	ret = DROPBEAR_SUCCESS;
+
+out:
+	return ret;
+}
+
+
+int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
+	/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
+	int ret = DROPBEAR_FAILURE;
+	hash_state hs;
+	struct dropbear_ecc_curve *curve = NULL;
+	unsigned char hash[64];
+	ecc_point *mG = NULL, *mQ = NULL;
+	void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL, 
+		*e = NULL, *p = NULL, *m = NULL;
+	void *mp = NULL;
+
+	/* verify 
+	 *
+	 * w  = s^-1 mod n
+	 * u1 = xw 
+	 * u2 = rw
+	 * X = u1*G + u2*Q
+	 * v = X_x1 mod n
+	 * accept if v == r
+	 */
+
+	TRACE(("buf_ecdsa_verify"))
+	curve = curve_for_dp(key->dp);
+
+	mG = ltc_ecc_new_point();
+	mQ = ltc_ecc_new_point();
+	if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK
+		|| !mG
+		|| !mQ) {
+		dropbear_exit("ECC error");
+	}
+
+	if (buf_get_ecdsa_verify_params(buf, curve, r, s) != DROPBEAR_SUCCESS) {
+		goto out;
+	}
+
+	curve->hash_desc->init(&hs);
+	curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
+	curve->hash_desc->done(&hs, hash);
+
+	if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
+		goto out;
+	}
+
+   /* get the order */
+	if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* get the modulus */
+	if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* check for zero */
+	if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ 
+		|| ltc_mp.compare_d(s, 0) == LTC_MP_EQ 
+		|| ltc_mp.compare(r, p) != LTC_MP_LT 
+		|| ltc_mp.compare(s, p) != LTC_MP_LT) {
+		goto out;
+	}
+
+   /*  w  = s^-1 mod n */
+	if (ltc_mp.invmod(s, p, w) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* u1 = ew */
+	if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* u2 = rw */
+	if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* find mG and mQ */
+	if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) { 
+		goto out; 
+	}
+	if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) { 
+		goto out; 
+	}
+	if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) { 
+		goto out; 
+	}
+
+	if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK
+		|| ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK
+		|| ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* compute u1*mG + u2*mQ = mG */
+	if (ltc_mp.ecc_mul2add == NULL) {
+		if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) { 
+			goto out; 
+		}
+		if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) {
+			goto out; 
+		}
+
+		/* find the montgomery mp */
+		if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) { 
+			goto out; 
+		}
+
+		/* add them */
+		if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) { 
+			goto out; 
+		}
+
+    	/* reduce */
+		if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) { 
+			goto out; 
+		}
+	} else {
+      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
+		if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) { 
+			goto out; 
+		}
+	}
+
+   /* v = X_x1 mod n */
+	if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) { 
+		goto out; 
+	}
+
+   /* does v == r */
+	if (ltc_mp.compare(v, r) == LTC_MP_EQ) {
+		ret = DROPBEAR_SUCCESS;
+	}
+
+out:
+	ltc_ecc_del_point(mG);
+	ltc_ecc_del_point(mQ);
+	mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
+	if (mp != NULL) { 
+		ltc_mp.montgomery_deinit(mp);
+	}
+	return ret;
+}
+
+
+
+#endif // DROPBEAR_ECDSA
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ecdsa.h	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,32 @@
+#ifndef _ECDSA_H_
+#define _ECDSA_H_
+
+#include "includes.h"
+#include "buffer.h"
+#include "signkey.h"
+
+#ifdef DROPBEAR_ECDSA
+
+#ifdef DROPBEAR_ECC_256
+#define ECDSA_DEFAULT_SIZE 256
+#elif DROPBEAR_ECC_384
+#define ECDSA_DEFAULT_SIZE 384
+#elif DROPBEAR_ECC_521
+#define ECDSA_DEFAULT_SIZE 521
+#else
+#define ECDSA_DEFAULT_SIZE 0
+#endif
+
+ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
+ecc_key *buf_get_ecdsa_pub_key(buffer* buf);
+ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
+void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
+void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
+enum signkey_type ecdsa_signkey_type(ecc_key * key);
+
+void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
+int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
+
+#endif
+
+#endif // _ECDSA_H_
--- a/gendss.c	Mon May 13 21:35:13 2013 +0800
+++ b/gendss.c	Tue May 21 12:09:35 2013 +0800
@@ -47,6 +47,10 @@
 
 	dropbear_dss_key *key;
 
+	if (size != 1024) {
+		dropbear_exit("DSS keys have a fixed size of 1024 bits");
+	}
+
 	key = m_malloc(sizeof(*key));
 
 	key->p = (mp_int*)m_malloc(sizeof(mp_int));
@@ -56,10 +60,8 @@
 	key->x = (mp_int*)m_malloc(sizeof(mp_int));
 	m_mp_init_multi(key->p, key->q, key->g, key->y, key->x, NULL);
 	
-	seedrandom();
-	
 	getq(key);
-	getp(key, size);
+	getp(key, size/8);
 	getg(key);
 	getx(key);
 	gety(key);
--- a/genrsa.c	Mon May 13 21:35:13 2013 +0800
+++ b/genrsa.c	Tue May 21 12:09:35 2013 +0800
@@ -34,7 +34,7 @@
 #ifdef DROPBEAR_RSA
 
 static void getrsaprime(mp_int* prime, mp_int *primeminus, 
-		mp_int* rsa_e, unsigned int size);
+		mp_int* rsa_e, unsigned int size_bytes);
 
 /* mostly taken from libtomcrypt's rsa key generation routine */
 dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
@@ -44,6 +44,11 @@
 	DEF_MP_INT(qminus);
 	DEF_MP_INT(lcm);
 
+	if (size < 512 || size > 4096 || (size % 8 != 0)) {
+		dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
+			" multiple of 8");
+	}
+
 	key = m_malloc(sizeof(*key));
 
 	key->e = (mp_int*)m_malloc(sizeof(mp_int));
@@ -55,15 +60,13 @@
 	m_mp_init_multi(key->e, key->n, key->d, key->p, key->q,
 			&pminus, &lcm, &qminus, NULL);
 
-	seedrandom();
-
 	if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
 		fprintf(stderr, "RSA generation failed\n");
 		exit(1);
 	}
 
-	getrsaprime(key->p, &pminus, key->e, size/2);
-	getrsaprime(key->q, &qminus, key->e, size/2);
+	getrsaprime(key->p, &pminus, key->e, size/16);
+	getrsaprime(key->q, &qminus, key->e, size/16);
 
 	if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
 		fprintf(stderr, "RSA generation failed\n");
@@ -90,21 +93,21 @@
 
 /* return a prime suitable for p or q */
 static void getrsaprime(mp_int* prime, mp_int *primeminus, 
-		mp_int* rsa_e, unsigned int size) {
+		mp_int* rsa_e, unsigned int size_bytes) {
 
 	unsigned char *buf;
 	DEF_MP_INT(temp_gcd);
 
-	buf = (unsigned char*)m_malloc(size+1);
+	buf = (unsigned char*)m_malloc(size_bytes+1);
 
 	m_mp_init(&temp_gcd);
 	do {
 		/* generate a random odd number with MSB set, then find the
 		   the next prime above it */
-		genrandom(buf, size+1);
+		genrandom(buf, size_bytes+1);
 		buf[0] |= 0x80; /* MSB set */
 
-		bytes_to_mp(prime, buf, size+1);
+		bytes_to_mp(prime, buf, size_bytes+1);
 
 		/* find the next integer which is prime, 8 round of miller-rabin */
 		if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
@@ -126,7 +129,7 @@
 
 	/* now we have a good value for result */
 	mp_clear(&temp_gcd);
-	m_burn(buf, size+1);
+	m_burn(buf, size_bytes+1);
 	m_free(buf);
 }
 
--- a/kex.h	Mon May 13 21:35:13 2013 +0800
+++ b/kex.h	Tue May 21 12:09:35 2013 +0800
@@ -27,16 +27,26 @@
 
 #include "includes.h"
 #include "algo.h"
+#include "signkey.h"
 
 void send_msg_kexinit();
 void recv_msg_kexinit();
 void send_msg_newkeys();
 void recv_msg_newkeys();
 void kexfirstinitialise();
-void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv);
-void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
+
+struct kex_dh_param *gen_kexdh_param();
+void free_kexdh_param(struct kex_dh_param *param);
+void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
 		sign_key *hostkey);
 
+#ifdef DROPBEAR_ECDH
+struct kex_ecdh_param *gen_kexecdh_param();
+void free_kexecdh_param(struct kex_ecdh_param *param);
+void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
+		sign_key *hostkey);
+#endif
+
 #ifndef DISABLE_ZLIB
 int is_compress_trans();
 int is_compress_recv();
@@ -66,6 +76,21 @@
 
 };
 
+#define DH_P_1_LEN 128
+extern const unsigned char dh_p_1[DH_P_1_LEN];
+#define DH_P_14_LEN 256
+extern const unsigned char dh_p_14[DH_P_14_LEN];
+
+struct kex_dh_param {
+	mp_int pub; /* e */
+	mp_int priv; /* x */
+};
+
+#ifdef DROPBEAR_ECDH
+struct kex_ecdh_param {
+	ecc_key key;
+};
+#endif
 
 #define MAX_KEXHASHBUF 2000
 
--- a/keyimport.c	Mon May 13 21:35:13 2013 +0800
+++ b/keyimport.c	Tue May 21 12:09:35 2013 +0800
@@ -349,7 +349,7 @@
  * Code to read and write OpenSSH private keys.
  */
 
-enum { OSSH_DSA, OSSH_RSA };
+enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
 struct openssh_key {
 	int type;
 	int encrypted;
@@ -392,6 +392,8 @@
 		ret->type = OSSH_RSA;
 	else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
 		ret->type = OSSH_DSA;
+	else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
+		ret->type = OSSH_EC;
 	else {
 		errmsg = "Unrecognised key type";
 		goto error;
--- a/libtomcrypt/Makefile.in	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/Makefile.in	Tue May 21 12:09:35 2013 +0800
@@ -19,7 +19,7 @@
 
 # Compilation flags. Note the += does not write over the user's CFLAGS!
 # The rest of the flags come from the parent Dropbear makefile
-CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../
+CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../ -DLTC_SOURCE -I$(srcdir)/../libtommath/
 
 # additional warnings (newer GCC 3.4 and higher)
 ifdef GCC_34
@@ -157,7 +157,53 @@
 src/modes/lrw/lrw_getiv.o src/modes/lrw/lrw_process.o src/modes/lrw/lrw_setiv.o \
 src/modes/lrw/lrw_start.o src/modes/lrw/lrw_test.o src/modes/ofb/ofb_decrypt.o src/modes/ofb/ofb_done.o \
 src/modes/ofb/ofb_encrypt.o src/modes/ofb/ofb_getiv.o src/modes/ofb/ofb_setiv.o \
-src/modes/ofb/ofb_start.o 
+src/modes/ofb/ofb_start.o src/pk/asn1/der/bit/der_decode_bit_string.o \
+src/pk/asn1/der/bit/der_encode_bit_string.o src/pk/asn1/der/bit/der_length_bit_string.o \
+src/pk/asn1/der/boolean/der_decode_boolean.o src/pk/asn1/der/boolean/der_encode_boolean.o \
+src/pk/asn1/der/boolean/der_length_boolean.o src/pk/asn1/der/choice/der_decode_choice.o \
+src/pk/asn1/der/ia5/der_decode_ia5_string.o src/pk/asn1/der/ia5/der_encode_ia5_string.o \
+src/pk/asn1/der/ia5/der_length_ia5_string.o src/pk/asn1/der/integer/der_decode_integer.o \
+src/pk/asn1/der/integer/der_encode_integer.o src/pk/asn1/der/integer/der_length_integer.o \
+src/pk/asn1/der/object_identifier/der_decode_object_identifier.o \
+src/pk/asn1/der/object_identifier/der_encode_object_identifier.o \
+src/pk/asn1/der/object_identifier/der_length_object_identifier.o \
+src/pk/asn1/der/octet/der_decode_octet_string.o src/pk/asn1/der/octet/der_encode_octet_string.o \
+src/pk/asn1/der/octet/der_length_octet_string.o \
+src/pk/asn1/der/printable_string/der_decode_printable_string.o \
+src/pk/asn1/der/printable_string/der_encode_printable_string.o \
+src/pk/asn1/der/printable_string/der_length_printable_string.o \
+src/pk/asn1/der/sequence/der_decode_sequence_ex.o \
+src/pk/asn1/der/sequence/der_decode_sequence_flexi.o \
+src/pk/asn1/der/sequence/der_decode_sequence_multi.o \
+src/pk/asn1/der/sequence/der_encode_sequence_ex.o \
+src/pk/asn1/der/sequence/der_encode_sequence_multi.o src/pk/asn1/der/sequence/der_length_sequence.o \
+src/pk/asn1/der/sequence/der_sequence_free.o src/pk/asn1/der/set/der_encode_set.o \
+src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_short_integer.o \
+src/pk/asn1/der/short_integer/der_encode_short_integer.o \
+src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \
+src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \
+src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \
+src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \
+src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \
+src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \
+src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \
+src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
+src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \
+src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \
+src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
+src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
+src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
+src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \
+src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \
+src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
+src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
+src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
+src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
+src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_import.o \
+src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_sign_hash.o src/pk/rsa/rsa_verify_hash.o src/prngs/fortuna.o \
+src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
+src/prngs/sprng.o src/prngs/yarrow.o 
 
 HEADERS=src/headers/tomcrypt_cfg.h src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h \
 src/headers/tomcrypt_custom.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cipher.h \
--- a/libtomcrypt/src/headers/tomcrypt.h	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/headers/tomcrypt.h	Tue May 21 12:09:35 2013 +0800
@@ -24,7 +24,7 @@
 
 /* descriptor table size */
 /* Dropbear change - this should be smaller, saves some size */
-#define TAB_SIZE    4
+#define TAB_SIZE    5
 
 /* error codes [will be expanded in future releases] */
 enum {
--- a/libtomcrypt/src/headers/tomcrypt_custom.h	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/headers/tomcrypt_custom.h	Tue May 21 12:09:35 2013 +0800
@@ -127,13 +127,32 @@
 #ifdef DROPBEAR_SHA256
 #define SHA256
 #endif
-
+#ifdef DROPBEAR_SHA384
+#define SHA384
+#endif
 #ifdef DROPBEAR_SHA512
 #define SHA512
 #endif
 
 #define LTC_HMAC
 
+#ifdef DROPBEAR_ECC
+#define MECC
+#define LTC_ECC_SHAMIR
+#define LTC_ECC_TIMING_RESISTANT
+#define MPI
+#define LTM_DESC
+#ifdef DROPBEAR_ECC_256
+#define ECC256
+#endif
+#ifdef DROPBEAR_ECC_384
+#define ECC384
+#endif
+#ifdef DROPBEAR_ECC_521
+#define ECC521
+#endif
+#endif
+
 /* Various tidbits of modern neatoness */
 #define BASE64
 
--- a/libtomcrypt/src/headers/tomcrypt_math.h	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/headers/tomcrypt_math.h	Tue May 21 12:09:35 2013 +0800
@@ -11,12 +11,9 @@
    typedef void ecc_point;
 #endif
 
-/* Dropbear has its own rsa_key. We just comment this out. */
-#if 0
 #ifndef MRSA
    typedef void rsa_key;
 #endif
-#endif
 
 /** math descriptor */
 typedef struct {
@@ -389,8 +386,6 @@
                       ecc_point *C,
                            void *modulus);
 
-/* Dropbear has its own rsa code */
-#if 0
 /* ---- (optional) rsa optimized math (for internal CRT) ---- */
 
    /** RSA Key Generation 
@@ -416,7 +411,6 @@
    int (*rsa_me)(const unsigned char *in,   unsigned long inlen,
                        unsigned char *out,  unsigned long *outlen, int which,
                        rsa_key *key);
-#endif
 } ltc_math_descriptor;
 
 extern ltc_math_descriptor ltc_mp;
--- a/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c	Tue May 21 12:09:35 2013 +0800
@@ -10,4 +10,4 @@
  */
 #include "tomcrypt.h"
 
-ltc_math_descriptor ltc_mp;
+ltc_math_descriptor ltc_mp = {0};
--- a/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c	Tue May 21 12:09:35 2013 +0800
@@ -21,7 +21,7 @@
   ECC Crypto, Tom St Denis
 */  
 
-#ifdef MECC
+#if defined(MECC) && defined(LTC_DER)
 
 /**
   Decrypt an ECC encrypted key
--- a/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c	Tue May 21 12:09:35 2013 +0800
@@ -21,7 +21,7 @@
   ECC Crypto, Tom St Denis
 */  
 
-#ifdef MECC
+#if defined(MECC) && defined(LTC_DER)
 
 /**
   Encrypt a symmetric key with ECC 
--- a/libtomcrypt/src/pk/ecc/ecc_export.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/pk/ecc/ecc_export.c	Tue May 21 12:09:35 2013 +0800
@@ -21,7 +21,7 @@
   ECC Crypto, Tom St Denis
 */  
 
-#ifdef MECC
+#if defined(MECC) && defined(LTC_DER)
 
 /**
   Export an ECC key as a binary packet
--- a/libtomcrypt/src/pk/ecc/ecc_import.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/pk/ecc/ecc_import.c	Tue May 21 12:09:35 2013 +0800
@@ -21,7 +21,7 @@
   ECC Crypto, Tom St Denis
 */  
 
-#ifdef MECC
+#if defined(MECC) && defined(LTC_DER)
 
 static int is_point(ecc_key *key)
 {
--- a/libtomcrypt/src/pk/ecc/ecc_sign_hash.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/pk/ecc/ecc_sign_hash.c	Tue May 21 12:09:35 2013 +0800
@@ -21,7 +21,7 @@
   ECC Crypto, Tom St Denis
 */  
 
-#ifdef MECC
+#if defined(MECC) && defined(LTC_DER)
 
 /**
   Sign a message digest
--- a/libtomcrypt/src/pk/ecc/ecc_verify_hash.c	Mon May 13 21:35:13 2013 +0800
+++ b/libtomcrypt/src/pk/ecc/ecc_verify_hash.c	Tue May 21 12:09:35 2013 +0800
@@ -21,7 +21,7 @@
   ECC Crypto, Tom St Denis
 */  
 
-#ifdef MECC
+#if defined(MECC) && defined(LTC_DER)
 
 /* verify 
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ltc_prng.c	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,137 @@
+/* Copied from libtomcrypt/src/prngs/sprng.c and modified to
+ * use Dropbear's genrandom(). */
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, [email protected], http://libtomcrypt.com
+ */
+#include "options.h"
+#include "includes.h"
+#include "random.h"
+#include "ltc_prng.h"
+
+/**
+   @file sprng.c
+   Secure PRNG, Tom St Denis
+*/
+   
+/* A secure PRNG using the RNG functions.  Basically this is a
+ * wrapper that allows you to use a secure RNG as a PRNG
+ * in the various other functions.
+ */
+
+#ifdef DROPBEAR_LTC_PRNG
+
+/**
+  Start the PRNG
+  @param prng     [out] The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_start(prng_state* UNUSED(prng))
+{
+   return CRYPT_OK;  
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
+{
+   return CRYPT_OK;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_ready(prng_state* UNUSED(prng))
+{
+   return CRYPT_OK;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/  
+unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng))
+{
+   LTC_ARGCHK(out != NULL);
+   genrandom(out, outlen);
+   return outlen;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_done(prng_state* UNUSED(prng))
+{
+   return CRYPT_OK;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng))
+{
+   LTC_ARGCHK(outlen != NULL);
+
+   *outlen = 0;
+   return CRYPT_OK;
+}
+ 
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
+{
+   return CRYPT_OK;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/  
+int dropbear_prng_test(void)
+{
+   return CRYPT_OK;
+}
+
+const struct ltc_prng_descriptor dropbear_prng_desc =
+{
+    "dropbear_prng", 0,
+    &dropbear_prng_start,
+    &dropbear_prng_add_entropy,
+    &dropbear_prng_ready,
+    &dropbear_prng_read,
+    &dropbear_prng_done,
+    &dropbear_prng_export,
+    &dropbear_prng_import,
+    &dropbear_prng_test
+};
+
+
+#endif // DROPBEAR_LTC_PRNG
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ltc_prng.h	Tue May 21 12:09:35 2013 +0800
@@ -0,0 +1,13 @@
+#ifndef _LTC_PRNG_H_DROPBEAR
+#define _LTC_PRNG_H_DROPBEAR
+
+#include "options.h"
+#include "includes.h"
+
+#ifdef DROPBEAR_LTC_PRNG
+
+extern const struct ltc_prng_descriptor dropbear_prng_desc;
+
+#endif // DROPBEAR_LTC_PRNG
+
+#endif // _LTC_PRNG_H_DROPBEAR
\ No newline at end of file
--- a/options.h	Mon May 13 21:35:13 2013 +0800
+++ b/options.h	Tue May 21 12:09:35 2013 +0800
@@ -5,10 +5,10 @@
 #ifndef _OPTIONS_H_
 #define _OPTIONS_H_
 
-/******************************************************************
- * Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
- * parts are to allow for commandline -DDROPBEAR_XXX options etc.
- ******************************************************************/
+/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
+ * parts are to allow for commandline -DDROPBEAR_XXX options etc. */
+
+/* Important: Many options will require "make clean" after changes */
 
 #ifndef DROPBEAR_DEFPORT
 #define DROPBEAR_DEFPORT "22"
@@ -26,6 +26,9 @@
 #ifndef RSA_PRIV_FILENAME
 #define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
 #endif
+#ifndef ECDSA_PRIV_FILENAME
+#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
+#endif
 
 /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
  * on chosen ports and keeps accepting connections. This is the default.
@@ -136,6 +139,9 @@
 #define DROPBEAR_RSA
 #define DROPBEAR_DSS
 
+#define DROPBEAR_ECDH
+#define DROPBEAR_ECDSA
+
 /* RSA can be vulnerable to timing attacks which use the time required for
  * signing to guess the private key. Blinding avoids this attack, though makes
  * signing operations slightly slower. */
--- a/random.c	Mon May 13 21:35:13 2013 +0800
+++ b/random.c	Tue May 21 12:09:35 2013 +0800
@@ -28,6 +28,7 @@
 #include "bignum.h"
 #include "random.h"
 
+
 /* this is used to generate unique output from the same hashpool */
 static uint32_t counter = 0;
 /* the max value for the counter, so it won't integer overflow */
--- a/rsa.c	Mon May 13 21:35:13 2013 +0800
+++ b/rsa.c	Tue May 21 12:09:35 2013 +0800
@@ -39,8 +39,7 @@
 #ifdef DROPBEAR_RSA 
 
 static void rsa_pad_em(dropbear_rsa_key * key,
-		const unsigned char * data, unsigned int len,
-		mp_int * rsa_em);
+	buffer *data_buf, 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.
@@ -213,9 +212,7 @@
 #ifdef DROPBEAR_SIGNKEY_VERIFY
 /* Verify a signature in buf, made on data by the key given.
  * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
-		unsigned int len) {
-
+int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf) {
 	unsigned int slen;
 	DEF_MP_INT(rsa_s);
 	DEF_MP_INT(rsa_mdash);
@@ -247,7 +244,7 @@
 	}
 
 	/* create the magic PKCS padded value */
-	rsa_pad_em(key, data, len, &rsa_em);
+	rsa_pad_em(key, data_buf, &rsa_em);
 
 	if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
 		TRACE(("failed exptmod rsa_s"))
@@ -270,9 +267,7 @@
 
 /* Sign the data presented with key, writing the signature contents
  * to the buffer */
-void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
-		unsigned int len) {
-
+void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf) {
 	unsigned int nsize, ssize;
 	unsigned int i;
 	DEF_MP_INT(rsa_s);
@@ -285,7 +280,7 @@
 
 	m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
 
-	rsa_pad_em(key, data, len, &rsa_tmp1);
+	rsa_pad_em(key, data_buf, &rsa_tmp1);
 
 	/* the actual signing of the padded data */
 
@@ -377,8 +372,7 @@
  * rsa_em must be a pointer to an initialised mp_int.
  */
 static void rsa_pad_em(dropbear_rsa_key * key,
-		const unsigned char * data, unsigned int len, 
-		mp_int * rsa_em) {
+	buffer *data_buf, mp_int * rsa_em) {
 
 	/* ASN1 designator (including the 0x00 preceding) */
 	const unsigned char rsa_asn1_magic[] = 
@@ -391,7 +385,6 @@
 	unsigned int nsize;
 	
 	dropbear_assert(key != NULL);
-	dropbear_assert(data != NULL);
 	nsize = mp_unsigned_bin_size(key->n);
 
 	rsa_EM = buf_new(nsize-1);
@@ -408,7 +401,7 @@
 
 	/* The hash of the data */
 	sha1_init(&hs);
-	sha1_process(&hs, data, len);
+	sha1_process(&hs, data_buf->data, data_buf->len);
 	sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
 	buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);
 
--- a/rsa.h	Mon May 13 21:35:13 2013 +0800
+++ b/rsa.h	Tue May 21 12:09:35 2013 +0800
@@ -43,11 +43,9 @@
 
 } dropbear_rsa_key;
 
-void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
-		unsigned int len);
+void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf);
 #ifdef DROPBEAR_SIGNKEY_VERIFY
-int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
-		unsigned int len);
+int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf);
 #endif
 int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
 int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
--- a/runopts.h	Mon May 13 21:35:13 2013 +0800
+++ b/runopts.h	Tue May 21 12:09:35 2013 +0800
@@ -57,11 +57,10 @@
 extern runopts opts;
 
 int readhostkey(const char * filename, sign_key * hostkey, int *type);
+void load_all_hostkeys();
 
 typedef struct svr_runopts {
 
-	char * rsakeyfile;
-	char * dsskeyfile;
 	char * bannerfile;
 
 	int forkbg;
@@ -99,6 +98,10 @@
 #endif
 
 	sign_key *hostkey;
+
+	char *hostkey_files[MAX_HOSTKEYS];
+	int num_hostkey_files;
+
 	buffer * banner;
 	char * pidfile;
 
--- a/session.h	Mon May 13 21:35:13 2013 +0800
+++ b/session.h	Tue May 21 12:09:35 2013 +0800
@@ -66,7 +66,7 @@
 	const struct dropbear_cipher_mode *crypt_mode;
 	const struct dropbear_hash *algo_mac;
 	int hash_index; /* lookup for libtomcrypt */
-	char algo_comp; /* compression */
+	int algo_comp; /* compression */
 #ifndef DISABLE_ZLIB
 	z_streamp zstream;
 #endif
@@ -86,8 +86,8 @@
 	struct key_context_directional recv;
 	struct key_context_directional trans;
 
-	char algo_kex;
-	char algo_hostkey;
+	const struct dropbear_kex *algo_kex;
+	int algo_hostkey;
 
 	int allow_compress; /* whether compression has started (useful in 
 							[email protected] delayed compression case) */
@@ -158,10 +158,10 @@
 	struct KEXState kexstate;
 	struct key_context *keys;
 	struct key_context *newkeys;
-	unsigned char *session_id; /* this is the hash from the first kex */
-	/* The below are used temorarily during kex, are freed after use */
+	buffer *session_id; /* this is the hash from the first kex */
+	/* The below are used temporarily during kex, are freed after use */
 	mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */
-	unsigned char hash[SHA1_HASH_SIZE]; /* the hash*/
+	buffer *hash; /* the session hash */
 	buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
 	buffer* transkexinit; /* the kexinit packet we send should be kept so we
 							 can add it to the hash when generating keys */
@@ -241,8 +241,11 @@
 
 struct clientsession {
 
-	mp_int *dh_e, *dh_x; /* Used during KEX */
-	int dh_val_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
+	// XXX - move these to kexstate?
+	struct kex_dh_param *dh_param;
+	struct kex_ecdh_param *ecdh_param;
+	const struct dropbear_kex *param_kex_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
+
 	cli_kex_state kex_state; /* Used for progressing KEX */
 	cli_state state; /* Used to progress auth/channelsession etc */
 	unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
--- a/signkey.c	Mon May 13 21:35:13 2013 +0800
+++ b/signkey.c	Tue May 21 12:09:35 2013 +0800
@@ -27,6 +27,22 @@
 #include "signkey.h"
 #include "buffer.h"
 #include "ssh.h"
+#include "ecdsa.h"
+
+static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
+#ifdef DROPBEAR_RSA
+	"ssh-rsa",
+#endif
+#ifdef DROPBEAR_DSS
+	"ssh-dss",
+#endif
+#ifdef DROPBEAR_ECDSA
+	"ecdsa-sha2-nistp256",
+	"ecdsa-sha2-nistp384",
+	"ecdsa-sha2-nistp521",
+	"ecdsa" // for keygen
+#endif // DROPBEAR_ECDSA
+};
 
 /* malloc a new sign_key and set the dss and rsa keys to NULL */
 sign_key * new_sign_key() {
@@ -34,54 +50,53 @@
 	sign_key * ret;
 
 	ret = (sign_key*)m_malloc(sizeof(sign_key));
-#ifdef DROPBEAR_DSS
-	ret->dsskey = NULL;
-#endif
-#ifdef DROPBEAR_RSA
-	ret->rsakey = NULL;
-#endif
-	ret->filename = NULL;
 	ret->type = DROPBEAR_SIGNKEY_NONE;
 	ret->source = SIGNKEY_SOURCE_INVALID;
 	return ret;
 }
 
-/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
+/* Returns key name corresponding to the type. Exits fatally
  * if the type is invalid */
-const char* signkey_name_from_type(int type, int *namelen) {
-
-#ifdef DROPBEAR_RSA
-	if (type == DROPBEAR_SIGNKEY_RSA) {
-		*namelen = SSH_SIGNKEY_RSA_LEN;
-		return SSH_SIGNKEY_RSA;
+const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) {
+	if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) {
+		dropbear_exit("Bad key type %d", type);
 	}
-#endif
-#ifdef DROPBEAR_DSS
-	if (type == DROPBEAR_SIGNKEY_DSS) {
-		*namelen = SSH_SIGNKEY_DSS_LEN;
-		return SSH_SIGNKEY_DSS;
+
+	if (namelen) {
+		*namelen = strlen(signkey_names[type]);
 	}
-#endif
-	dropbear_exit("Bad key type %d", type);
-	return NULL; /* notreached */
+	return signkey_names[type];
 }
 
-/* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS, 
- * or DROPBEAR_SIGNKEY_NONE */
-int signkey_type_from_name(const char* name, int namelen) {
+/* Returns DROPBEAR_SIGNKEY_NONE if none match */
+enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) {
+	int i;
+	for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) {
+		const char *fixed_name = signkey_names[i];
+		if (namelen == strlen(fixed_name)
+			&& memcmp(fixed_name, name, namelen) == 0) {
 
-#ifdef DROPBEAR_RSA
-	if (namelen == SSH_SIGNKEY_RSA_LEN
-			&& memcmp(name, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN) == 0) {
-		return DROPBEAR_SIGNKEY_RSA;
-	}
+#ifdef DROPBEAR_ECDSA
+			/* Some of the ECDSA key sizes are defined even if they're not compiled in */
+			if (0
+#ifndef DROPBEAR_ECC_256
+				|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
+#endif
+#ifndef DROPBEAR_ECC_384
+				|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
 #endif
-#ifdef DROPBEAR_DSS
-	if (namelen == SSH_SIGNKEY_DSS_LEN
-			&& memcmp(name, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN) == 0) {
-		return DROPBEAR_SIGNKEY_DSS;
+#ifndef DROPBEAR_ECC_521
+				|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
+#endif
+				) {
+				TRACE(("attempt to use ecdsa type %d not compiled in", i))
+				return DROPBEAR_SIGNKEY_NONE;
+			}
+#endif
+
+			return i;
+		}
 	}
-#endif
 
 	TRACE(("signkey_type_from_name unexpected key type."))
 
@@ -136,6 +151,17 @@
 		}
 	}
 #endif
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(keytype)) {
+		if (key->ecckey) {
+			ecc_free(key->ecckey);
+		}
+		key->ecckey = buf_get_ecdsa_pub_key(buf);
+		if (key->ecckey) {
+			ret = DROPBEAR_SUCCESS;
+		}
+	}
+#endif
 
 	TRACE2(("leave buf_get_pub_key"))
 
@@ -189,6 +215,17 @@
 		}
 	}
 #endif
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(keytype)) {
+		if (key->ecckey) {
+			ecc_free(key->ecckey);
+		}
+		key->ecckey = buf_get_ecdsa_priv_key(buf);
+		if (key->ecckey) {
+			ret = DROPBEAR_SUCCESS;
+		}
+	}
+#endif
 
 	TRACE2(("leave buf_get_priv_key"))
 
@@ -214,14 +251,16 @@
 		buf_put_rsa_pub_key(pubkeys, key->rsakey);
 	}
 #endif
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(type)) {
+		buf_put_ecdsa_pub_key(pubkeys, key->ecckey);
+	}
+#endif
 	if (pubkeys->len == 0) {
 		dropbear_exit("Bad key types in buf_put_pub_key");
 	}
 
-	buf_setpos(pubkeys, 0);
-	buf_putstring(buf, buf_getptr(pubkeys, pubkeys->len),
-			pubkeys->len);
-	
+	buf_putbufstring(buf, pubkeys);
 	buf_free(pubkeys);
 	TRACE2(("leave buf_put_pub_key"))
 }
@@ -246,6 +285,12 @@
 	return;
 	}
 #endif
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(type)) {
+		buf_put_ecdsa_priv_key(buf, key->ecckey);
+		return;
+	}
+#endif
 	dropbear_exit("Bad key types in put pub key");
 }
 
@@ -261,6 +306,12 @@
 	rsa_key_free(key->rsakey);
 	key->rsakey = NULL;
 #endif
+#ifdef DROPBEAR_ECDSA
+	if (key->ecckey) {
+		ecc_free(key->ecckey);
+		key->ecckey = NULL;
+	}
+#endif
 
 	m_free(key->filename);
 
@@ -269,7 +320,6 @@
 }
 
 static char hexdig(unsigned char x) {
-
 	if (x > 0xf)
 		return 'X';
 
@@ -333,14 +383,14 @@
 
 	sha1_done(&hs, hash);
 
-	/* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
-	buflen = 5 + 3*SHA1_HASH_SIZE;
+	/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
+	buflen = 7 + 3*SHA1_HASH_SIZE;
 	ret = (char*)m_malloc(buflen);
 
-	strcpy(ret, "sha1 ");
+	strcpy(ret, "sha1!! ");
 
 	for (i = 0; i < SHA1_HASH_SIZE; i++) {
-		unsigned int pos = 5 + 3*i;
+		unsigned int pos = 7 + 3*i;
 		ret[pos] = hexdig(hash[i] >> 4);
 		ret[pos+1] = hexdig(hash[i] & 0x0f);
 		ret[pos+2] = ':';
@@ -364,28 +414,29 @@
 }
 
 void buf_put_sign(buffer* buf, sign_key *key, int type, 
-		const unsigned char *data, unsigned int len) {
-
+	buffer *data_buf) {
 	buffer *sigblob;
 	sigblob = buf_new(MAX_PUBKEY_SIZE);
 
 #ifdef DROPBEAR_DSS
 	if (type == DROPBEAR_SIGNKEY_DSS) {
-		buf_put_dss_sign(sigblob, key->dsskey, data, len);
+		buf_put_dss_sign(sigblob, key->dsskey, data_buf);
 	}
 #endif
 #ifdef DROPBEAR_RSA
 	if (type == DROPBEAR_SIGNKEY_RSA) {
-		buf_put_rsa_sign(sigblob, key->rsakey, data, len);
+		buf_put_rsa_sign(sigblob, key->rsakey, data_buf);
+	}
+#endif
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(type)) {
+		buf_put_ecdsa_sign(sigblob, key->ecckey, data_buf);
 	}
 #endif
 	if (sigblob->len == 0) {
 		dropbear_exit("Non-matching signing type");
 	}
-	buf_setpos(sigblob, 0);
-	buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
-			sigblob->len);
-			
+	buf_putbufstring(buf, sigblob);
 	buf_free(sigblob);
 
 }
@@ -395,40 +446,42 @@
  * If FAILURE is returned, the position of
  * buf is undefined. If SUCCESS is returned, buf will be positioned after the
  * signature blob */
-int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
-		unsigned int len) {
+int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
 	
 	unsigned int bloblen;
-	unsigned char * ident = NULL;
-	unsigned int identlen = 0;
+	unsigned char * type_name = NULL;
+	unsigned int type_name_len = 0;
 
 	TRACE(("enter buf_verify"))
 
 	bloblen = buf_getint(buf);
-	ident = buf_getstring(buf, &identlen);
+	type_name = buf_getstring(buf, &type_name_len);
+	enum signkey_type type = signkey_type_from_name(type_name, type_name_len);
+	m_free(type_name);
 
 #ifdef DROPBEAR_DSS
-	if (bloblen == DSS_SIGNATURE_SIZE &&
-			memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
-		m_free(ident);
+	if (type == DROPBEAR_SIGNKEY_DSS) {
 		if (key->dsskey == NULL) {
 			dropbear_exit("No DSS key to verify signature");
 		}
-		return buf_dss_verify(buf, key->dsskey, data, len);
+		return buf_dss_verify(buf, key->dsskey, data_buf);
 	}
 #endif
 
 #ifdef DROPBEAR_RSA
-	if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
-		m_free(ident);
+	if (type == DROPBEAR_SIGNKEY_RSA) {
 		if (key->rsakey == NULL) {
 			dropbear_exit("No RSA key to verify signature");
 		}
-		return buf_rsa_verify(buf, key->rsakey, data, len);
+		return buf_rsa_verify(buf, key->rsakey, data_buf);
+	}
+#endif
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(type)) {
+		return buf_ecdsa_verify(buf, key->ecckey, data_buf);
 	}
 #endif
 
-	m_free(ident);
 	dropbear_exit("Non-matching signing type");
 	return DROPBEAR_FAILURE;
 }
--- a/signkey.h	Mon May 13 21:35:13 2013 +0800
+++ b/signkey.h	Tue May 21 12:09:35 2013 +0800
@@ -29,6 +29,24 @@
 #include "dss.h"
 #include "rsa.h"
 
+enum signkey_type {
+#ifdef DROPBEAR_RSA
+	DROPBEAR_SIGNKEY_RSA,
+#endif
+#ifdef DROPBEAR_DSS
+	DROPBEAR_SIGNKEY_DSS,
+#endif
+#ifdef DROPBEAR_ECDSA
+	DROPBEAR_SIGNKEY_ECDSA_NISTP256,
+	DROPBEAR_SIGNKEY_ECDSA_NISTP384,
+	DROPBEAR_SIGNKEY_ECDSA_NISTP521,
+	DROPBEAR_SIGNKEY_ECDSA_KEYGEN, // just "ecdsa" for keygen
+#endif // DROPBEAR_ECDSA
+	DROPBEAR_SIGNKEY_NUM_NAMED,
+	DROPBEAR_SIGNKEY_ANY = 80,
+	DROPBEAR_SIGNKEY_NONE = 90,
+};
+
 
 /* Sources for signing keys */
 typedef enum {
@@ -39,11 +57,9 @@
 
 struct SIGN_key {
 
-	int type; /* The type of key (dss or rsa) */
+	enum signkey_type type;
 	signkey_source source;
 	char *filename;
-	/* the buffer? for encrypted keys, so we can later get
-	 * the private key portion */
 
 #ifdef DROPBEAR_DSS
 	dropbear_dss_key * dsskey;
@@ -51,27 +67,36 @@
 #ifdef DROPBEAR_RSA
 	dropbear_rsa_key * rsakey;
 #endif
+#ifdef DROPBEAR_ECDSA
+	ecc_key * ecckey;
+#endif
 };
 
 typedef struct SIGN_key sign_key;
 
 sign_key * new_sign_key();
-const char* signkey_name_from_type(int type, int *namelen);
-int signkey_type_from_name(const char* name, int namelen);
+const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen);
+enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen);
 int buf_get_pub_key(buffer *buf, sign_key *key, int *type);
 int buf_get_priv_key(buffer* buf, sign_key *key, int *type);
 void buf_put_pub_key(buffer* buf, sign_key *key, int type);
 void buf_put_priv_key(buffer* buf, sign_key *key, int type);
 void sign_key_free(sign_key *key);
-void buf_put_sign(buffer* buf, sign_key *key, int type, 
-		const unsigned char *data, unsigned int len);
+void buf_put_sign(buffer* buf, sign_key *key, int type, buffer *data_buf);
 #ifdef DROPBEAR_SIGNKEY_VERIFY
-int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
-		unsigned int len);
+int buf_verify(buffer * buf, sign_key *key, buffer *data_buf);
 char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen);
 #endif
 int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, 
 					const unsigned char* algoname, unsigned int algolen, 
 					buffer * line, char ** fingerprint);
 
+#ifdef DROPBEAR_ECDSA
+#define IS_ECDSA_KEY(type) \
+	((type) == DROPBEAR_SIGNKEY_ECDSA_NISTP256 \
+		|| (type) == DROPBEAR_SIGNKEY_ECDSA_NISTP384 \
+		|| (type) == DROPBEAR_SIGNKEY_ECDSA_NISTP521 \
+		|| (type) == DROPBEAR_SIGNKEY_ECDSA_KEYGEN)
+#endif
+
 #endif /* _SIGNKEY_H_ */
--- a/svr-auth.c	Mon May 13 21:35:13 2013 +0800
+++ b/svr-auth.c	Tue May 21 12:09:35 2013 +0800
@@ -93,8 +93,7 @@
 	CHECKCLEARTOWRITE();
 
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
-	buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner,
-				svr_opts.banner->len), svr_opts.banner->len);
+	buf_putbufstring(ses.writepayload, svr_opts.banner);
 	buf_putstring(ses.writepayload, "en", 2);
 
 	encrypt_packet();
@@ -343,12 +342,10 @@
 		buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
 	}
 
-	buf_setpos(typebuf, 0);
-	buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len),
-			typebuf->len);
+	buf_putbufstring(ses.writepayload, typebuf);
 
-	TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes,
-				buf_getptr(typebuf, typebuf->len)));
+	TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes,
+				typebuf->len, typebuf->data))
 
 	buf_free(typebuf);
 
--- a/svr-authpubkey.c	Mon May 13 21:35:13 2013 +0800
+++ b/svr-authpubkey.c	Tue May 21 12:09:35 2013 +0800
@@ -125,15 +125,14 @@
 
 	/* create the data which has been signed - this a string containing
 	 * session_id, concatenated with the payload packet up to the signature */
-	signbuf = buf_new(ses.payload->pos + 4 + SHA1_HASH_SIZE);
-	buf_putstring(signbuf, ses.session_id, SHA1_HASH_SIZE);
+	signbuf = buf_new(ses.payload->pos + 4 + ses.session_id->len);
+	buf_putbufstring(signbuf, ses.session_id);
 	buf_putbytes(signbuf, ses.payload->data, ses.payload->pos);
 	buf_setpos(signbuf, 0);
 
 	/* ... and finally verify the signature */
 	fp = sign_key_fingerprint(keyblob, keybloblen);
-	if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len),
-				signbuf->len) == DROPBEAR_SUCCESS) {
+	if (buf_verify(ses.payload, key, signbuf) == DROPBEAR_SUCCESS) {
 		dropbear_log(LOG_NOTICE,
 				"Pubkey auth succeeded for '%s' with key %s from %s",
 				ses.authstate.pw_name, fp, svr_ses.addrstring);
--- a/svr-kex.c	Mon May 13 21:35:13 2013 +0800
+++ b/svr-kex.c	Tue May 21 12:09:35 2013 +0800
@@ -34,9 +34,9 @@
 #include "bignum.h"
 #include "random.h"
 #include "runopts.h"
-
+#include "ecc.h"
 
-static void send_msg_kexdh_reply(mp_int *dh_e);
+static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs);
 
 /* Handle a diffie-hellman key exchange initialisation. This involves
  * calculating a session key reply value, and corresponding hash. These
@@ -45,20 +45,30 @@
 void recv_msg_kexdh_init() {
 
 	DEF_MP_INT(dh_e);
+	buffer *ecdh_qs = NULL;
 
 	TRACE(("enter recv_msg_kexdh_init"))
 	if (!ses.kexstate.recvkexinit) {
 		dropbear_exit("Premature kexdh_init message received");
 	}
 
-	m_mp_init(&dh_e);
-	if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
-		dropbear_exit("Failed to get kex value");
+	if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
+		m_mp_init(&dh_e);
+		if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
+			dropbear_exit("Failed to get kex value");
+		}
+	} else {
+#ifdef DROPBEAR_ECDH
+		ecdh_qs = buf_getstringbuf(ses.payload);
+#endif
 	}
 
-	send_msg_kexdh_reply(&dh_e);
+	send_msg_kexdh_reply(&dh_e, ecdh_qs);
 
 	mp_clear(&dh_e);
+	if (ecdh_qs) {
+		buf_free(ecdh_qs);
+	}
 
 	send_msg_newkeys();
 	ses.requirenext[0] = SSH_MSG_NEWKEYS;
@@ -71,19 +81,10 @@
  * that, the session hash is calculated, and signed with RSA or DSS. The
  * result is sent to the client. 
  *
- * See the transport rfc 4253 section 8 for details */
-static void send_msg_kexdh_reply(mp_int *dh_e) {
-
-	DEF_MP_INT(dh_y);
-	DEF_MP_INT(dh_f);
-
+ * See the transport RFC4253 section 8 for details
+ * or RFC5656 section 4 for elliptic curve variant. */
+static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
 	TRACE(("enter send_msg_kexdh_reply"))
-	m_mp_init_multi(&dh_y, &dh_f, NULL);
-	
-	gen_kexdh_vals(&dh_f, &dh_y);
-
-	kexdh_comb_key(&dh_f, &dh_y, dh_e, svr_opts.hostkey);
-	mp_clear(&dh_y);
 
 	/* we can start creating the kexdh_reply packet */
 	CHECKCLEARTOWRITE();
@@ -91,13 +92,27 @@
 	buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
 			ses.newkeys->algo_hostkey);
 
-	/* put f */
-	buf_putmpint(ses.writepayload, &dh_f);
-	mp_clear(&dh_f);
+	if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
+		// Normal diffie-hellman
+		struct kex_dh_param * dh_param = gen_kexdh_param();
+		kexdh_comb_key(dh_param, dh_e, svr_opts.hostkey);
+
+		/* put f */
+		buf_putmpint(ses.writepayload, &dh_param->pub);
+		free_kexdh_param(dh_param);
+	} else {
+#ifdef DROPBEAR_ECDH
+		struct kex_ecdh_param *ecdh_param = gen_kexecdh_param();
+		kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
+
+		buf_put_ecc_raw_pubkey_string(ses.writepayload, &ecdh_param->key);
+		free_kexecdh_param(ecdh_param);
+#endif
+	}
 
 	/* calc the signature */
 	buf_put_sign(ses.writepayload, svr_opts.hostkey, 
-			ses.newkeys->algo_hostkey, ses.hash, SHA1_HASH_SIZE);
+			ses.newkeys->algo_hostkey, ses.hash);
 
 	/* the SSH_MSG_KEXDH_REPLY is done */
 	encrypt_packet();
--- a/svr-main.c	Mon May 13 21:35:13 2013 +0800
+++ b/svr-main.c	Tue May 21 12:09:35 2013 +0800
@@ -29,6 +29,7 @@
 #include "signkey.h"
 #include "runopts.h"
 #include "random.h"
+#include "crypto_desc.h"
 
 static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
 static void sigchld_handler(int dummy);
@@ -383,9 +384,11 @@
 		dropbear_exit("signal() error");
 	}
 
+	crypto_init();
+
 	/* Now we can setup the hostkeys - needs to be after logging is on,
 	 * otherwise we might end up blatting error messages to the socket */
-	loadhostkeys();
+	load_all_hostkeys();
 
     seedrandom();
 }
--- a/svr-runopts.c	Mon May 13 21:35:13 2013 +0800
+++ b/svr-runopts.c	Tue May 21 12:09:35 2013 +0800
@@ -28,11 +28,14 @@
 #include "buffer.h"
 #include "dbutil.h"
 #include "algo.h"
+#include "ecdsa.h"
 
 svr_runopts svr_opts; /* GLOBAL */
 
 static void printhelp(const char * progname);
 static void addportandaddress(char* spec);
+static void loadhostkey(const char *keyfile, int fatal_duplicate);
+static void addhostkey(const char *keyfile);
 
 static void printhelp(const char * progname) {
 
@@ -105,10 +108,10 @@
 	char* recv_window_arg = NULL;
 	char* keepalive_arg = NULL;
 	char* idle_timeout_arg = NULL;
+	char* keyfile = NULL;
+
 
 	/* see printhelp() for options */
-	svr_opts.rsakeyfile = NULL;
-	svr_opts.dsskeyfile = NULL;
 	svr_opts.bannerfile = NULL;
 	svr_opts.banner = NULL;
 	svr_opts.forkbg = 1;
@@ -160,6 +163,11 @@
 				dropbear_exit("Invalid null argument");
 			}
 			next = 0x00;
+
+			if (keyfile) {
+				addhostkey(keyfile);
+				keyfile = NULL;
+			}
 			continue;
 		}
 
@@ -168,16 +176,10 @@
 				case 'b':
 					next = &svr_opts.bannerfile;
 					break;
-#ifdef DROPBEAR_DSS
 				case 'd':
-					next = &svr_opts.dsskeyfile;
+				case 'r':
+					next = &keyfile;
 					break;
-#endif
-#ifdef DROPBEAR_RSA
-				case 'r':
-					next = &svr_opts.rsakeyfile;
-					break;
-#endif
 				case 'F':
 					svr_opts.forkbg = 0;
 					break;
@@ -267,13 +269,6 @@
 		svr_opts.portcount = 1;
 	}
 
-	if (svr_opts.dsskeyfile == NULL) {
-		svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
-	}
-	if (svr_opts.rsakeyfile == NULL) {
-		svr_opts.rsakeyfile = RSA_PRIV_FILENAME;
-	}
-
 	if (svr_opts.bannerfile) {
 		struct stat buf;
 		if (stat(svr_opts.bannerfile, &buf) != 0) {
@@ -292,7 +287,6 @@
 					svr_opts.bannerfile);
 		}
 		buf_setpos(svr_opts.banner, 0);
-
 	}
 	
 	if (recv_window_arg) {
@@ -370,55 +364,125 @@
 	}
 }
 
-static void disablekey(int type, const char* filename) {
-
+static void disablekey(int type) {
 	int i;
-
 	for (i = 0; sshhostkey[i].name != NULL; i++) {
 		if (sshhostkey[i].val == type) {
-			sshhostkey[i].usable = 0;
+			sshhostkey[i].usable = 1;
 			break;
 		}
 	}
-	dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename,
-			type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
 }
 
 /* Must be called after syslog/etc is working */
-void loadhostkeys() {
+static void loadhostkey(const char *keyfile, int fatal_duplicate) {
+	sign_key * read_key = new_sign_key();
+	int type = DROPBEAR_SIGNKEY_ANY;
+	if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
+		dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
+	}
+
+#ifdef DROPBEAR_RSA
+	if (type == DROPBEAR_SIGNKEY_RSA) {
+		if (svr_opts.hostkey->rsakey) {
+			if (fatal_duplicate) {
+				dropbear_exit("Only one RSA key can be specified");
+			}
+		} else {
+			svr_opts.hostkey->rsakey = read_key->rsakey;
+			read_key->rsakey = NULL;
+		}
+	}
+#endif
 
-	int ret;
-	int type;
+#ifdef DROPBEAR_DSS
+	if (type == DROPBEAR_SIGNKEY_DSS) {
+		if (svr_opts.hostkey->dsskey) {
+			if (fatal_duplicate) {
+				dropbear_exit("Only one DSS key can be specified");
+			}
+		} else {
+			svr_opts.hostkey->dsskey = read_key->dsskey;
+			read_key->dsskey = NULL;
+		}
+	}
+#endif
 
-	TRACE(("enter loadhostkeys"))
+#ifdef DROPBEAR_ECDSA
+	if (IS_ECDSA_KEY(type)) {
+		if (svr_opts.hostkey->ecckey) {
+			if (fatal_duplicate) {
+				dropbear_exit("Only one ECDSA key can be specified");
+			}
+		} else {
+			svr_opts.hostkey->ecckey = read_key->ecckey;
+			read_key->ecckey = NULL;
+		}
+	}
+#endif
+	sign_key_free(read_key);
+	TRACE(("leave loadhostkey"))
+}
+
+static void addhostkey(const char *keyfile) {
+	if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
+		dropbear_exit("Too many hostkeys");
+	}
+	svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
+	svr_opts.num_hostkey_files++;
+}
+
+void load_all_hostkeys() {
+	int i;
 
 	svr_opts.hostkey = new_sign_key();
 
+	for (i = 0; i < svr_opts.num_hostkey_files; i++) {
+		char *hostkey_file = svr_opts.hostkey_files[i];
+		loadhostkey(hostkey_file, 1);
+		m_free(hostkey_file);
+	}
+
 #ifdef DROPBEAR_RSA
-	type = DROPBEAR_SIGNKEY_RSA;
-	ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type);
-	if (ret == DROPBEAR_FAILURE) {
-		disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile);
+	loadhostkey(RSA_PRIV_FILENAME, 0);
+#endif
+
+#ifdef DROPBEAR_DSS
+	loadhostkey(DSS_PRIV_FILENAME, 0);
+#endif
+
+#ifdef DROPBEAR_ECDSA
+	loadhostkey(ECDSA_PRIV_FILENAME, 0);
+#endif
+
+#ifdef DROPBEAR_RSA
+	if (!svr_opts.hostkey->rsakey) {
+		disablekey(DROPBEAR_SIGNKEY_RSA);
 	}
 #endif
 #ifdef DROPBEAR_DSS
-	type = DROPBEAR_SIGNKEY_DSS;
-	ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type);
-	if (ret == DROPBEAR_FAILURE) {
-		disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile);
+	if (!svr_opts.hostkey->dsskey) {
+		disablekey(DROPBEAR_SIGNKEY_RSA);
+	}
+#endif
+#ifdef DROPBEAR_ECDSA
+#ifdef DROPBEAR_ECC_256
+	if (!svr_opts.hostkey->ecckey 
+		|| ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
+		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
 	}
 #endif
-
-	if ( 1
-#ifdef DROPBEAR_DSS
-		&& svr_opts.hostkey->dsskey == NULL
+#ifdef DROPBEAR_ECC_384
+	if (!svr_opts.hostkey->ecckey 
+		|| ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
+		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
+	}
 #endif
-#ifdef DROPBEAR_RSA
-		&& svr_opts.hostkey->rsakey == NULL
+#ifdef DROPBEAR_ECC_521
+	if (!svr_opts.hostkey->ecckey 
+		|| ecdsa_signkey_type(svr_opts.hostkey->ecckey) != DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+		disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
+	}
 #endif
-		) {
-		dropbear_exit("No hostkeys available");
-	}
-
-	TRACE(("leave loadhostkeys"))
+#endif
 }
--- a/svr-session.c	Mon May 13 21:35:13 2013 +0800
+++ b/svr-session.c	Tue May 21 12:09:35 2013 +0800
@@ -39,6 +39,7 @@
 #include "service.h"
 #include "auth.h"
 #include "runopts.h"
+#include "crypto_desc.h"
 
 static void svr_remoteclosed();
 
@@ -83,7 +84,6 @@
 	char *host, *port;
 	size_t len;
 
-	crypto_init();
 	common_session_init(sock, sock);
 
 	/* Initialise server specific parts of the session */
--- a/sysoptions.h	Mon May 13 21:35:13 2013 +0800
+++ b/sysoptions.h	Tue May 21 12:09:35 2013 +0800
@@ -69,20 +69,6 @@
 #define DROPBEAR_SUCCESS 0
 #define DROPBEAR_FAILURE -1
 
-/* various algorithm identifiers */
-#define DROPBEAR_KEX_NONE 0
-#define DROPBEAR_KEX_DH_GROUP1 1
-#define DROPBEAR_KEX_DH_GROUP14 2
-
-#define DROPBEAR_SIGNKEY_ANY 0
-#define DROPBEAR_SIGNKEY_RSA 1
-#define DROPBEAR_SIGNKEY_DSS 2
-#define DROPBEAR_SIGNKEY_NONE 3
-
-#define DROPBEAR_COMP_NONE 0
-#define DROPBEAR_COMP_ZLIB 1
-#define DROPBEAR_COMP_ZLIB_DELAY 2
-
 /* Required for pubkey auth */
 #if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT)
 #define DROPBEAR_SIGNKEY_VERIFY
@@ -92,8 +78,7 @@
 #define MD5_HASH_SIZE 16
 
 #define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */
-#define MAX_IV_LEN 20 /* must be same as max blocksize, 
-						 and >= SHA1_HASH_SIZE */
+#define MAX_IV_LEN 20 /* must be same as max blocksize,  */
 
 #if defined(DROPBEAR_SHA2_512_HMAC)
 #define MAX_MAC_LEN 64
@@ -103,6 +88,37 @@
 #define MAX_MAC_LEN 20
 #endif
 
+#if defined(DROPBEAR_ECDH) || defined (DROPBEAR_ECDSA)
+#define DROPBEAR_ECC
+#endif
+
+#ifdef DROPBEAR_ECC
+#define DROPBEAR_ECC_256
+#define DROPBEAR_ECC_384
+#define DROPBEAR_ECC_521
+#endif
+
+#ifdef DROPBEAR_ECC
+#define DROPBEAR_LTC_PRNG
+#endif
+
+// hashes which will be linked and registered
+#if defined(DROPBEAR_SHA2_256_HMAC) || defined(DROPBEAR_ECC_256)
+#define DROPBEAR_SHA256
+#endif
+#if defined(DROPBEAR_ECC_384)
+#define DROPBEAR_SHA384
+#endif
+#if defined(DROPBEAR_SHA2_512_HMAC) || defined(DROPBEAR_ECC_521)
+#define DROPBEAR_SHA512
+#endif
+#if defined(DROPBEAR_MD5_HMAC)
+#define DROPBEAR_MD5
+#endif
+
+// roughly 2x 521 bits
+#define MAX_ECC_SIZE 140
+
 #define MAX_NAME_LEN 64 /* maximum length of a protocol name, isn't
 						   explicitly specified for all protocols (just
 						   for algos) but seems valid */
@@ -134,6 +150,8 @@
 /* For a 4096 bit DSS key, empirically determined */
 #define MAX_PRIVKEY_SIZE 1700
 
+#define MAX_HOSTKEYS 3
+
 /* The maximum size of the bignum portion of the kexhash buffer */
 /* Sect. 8 of the transport rfc 4253, K_S + e + f + K */
 #define KEXHASHBUF_MAX_INTS (1700 + 130 + 130 + 130)
@@ -155,19 +173,6 @@
 #define DROPBEAR_TWOFISH
 #endif
 
-#ifdef DROPBEAR_MD5_HMAC
-#define DROPBEAR_MD5
-#endif
-
-#ifdef DROPBEAR_SHA2_256_HMAC
-#define DROPBEAR_SHA256
-#endif
-
-#if (defined(DROPBEAR_DSS) && defined(DSS_PROTOK)) \
-	|| defined(DROPBEAR_SHA2_512_HMAC)
-#define DROPBEAR_SHA512
-#endif
-
 #ifndef ENABLE_X11FWD
 #define DISABLE_X11FWD
 #endif