changeset 755:b07eb3dc23ec ecc

refactor kexdh code a bit, start working on ecdh etc
author Matt Johnston <matt@ucc.asn.au>
date Tue, 26 Mar 2013 01:35:22 +0800
parents 49f68a7b7a55
children bf9dc2d9c2b1
files Makefile.in algo.h cli-kex.c common-algo.c common-kex.c configure.ac ecc.c kex.h libtomcrypt/src/headers/tomcrypt_custom.h ltc_prng.c options.h random.c random.h session.h svr-kex.c sysoptions.h
diffstat 16 files changed, 320 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Sun Mar 24 00:02:20 2013 +0800
+++ b/Makefile.in	Tue Mar 26 01:35:22 2013 +0800
@@ -26,7 +26,7 @@
 		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
 
 SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
 		svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
--- a/algo.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/algo.h	Tue Mar 26 01:35:22 2013 +0800
@@ -94,5 +94,23 @@
 char * algolist_string(algo_type algos[]);
 #endif
 
+enum {
+	DROPBEAR_KEX_DH_GROUP1,
+	DROPBEAR_KEX_DH_GROUP14,
+	DROPBEAR_KEX_ECDH_SECP256R1,
+};
+
+#ifdef DROPBEAR_ECDH
+#define IS_NORMAL_DH(algo) ((algo) == DROPBEAR_KEX_DH_GROUP1 || (algo) == DROPBEAR_KEX_DH_GROUP14)
+#else
+#define IS_NORMAL_DH(algo) 1
+#endif
+
+enum {
+	DROPBEAR_COMP_NONE,
+	DROPBEAR_COMP_ZLIB,
+	DROPBEAR_COMP_ZLIB_DELAY,
+};
+
 
 #endif /* _ALGO_H_ */
--- a/cli-kex.c	Sun Mar 24 00:02:20 2013 +0800
+++ b/cli-kex.c	Tue Mar 26 01:35:22 2013 +0800
@@ -42,16 +42,16 @@
 #define MAX_KNOWNHOSTS_LINE 4500
 
 void send_msg_kexdh_init() {
-
-	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);
-
 	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)) {
+		cli_ses.dh_param = gen_kexdh_param();
+		buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
+	} else {
+#ifdef DROPBEAR_ECDH
+		cli_ses.ecdh_param = 
+#endif
+	}
 	encrypt_packet();
 	ses.requirenext = SSH_MSG_KEXDH_REPLY;
 }
@@ -59,18 +59,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))
 
@@ -88,16 +85,23 @@
 		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_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);
+		kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
+		mp_clear(&dh_f);
+		free_kexdh_param(cli_ses.dh_param);
+		cli_ses.dh_param = NULL;
+	} else {
+#ifdef DROPBEAR_ECDH
+#endif
+	}
 
 	if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) 
 			!= DROPBEAR_SUCCESS) {
--- a/common-algo.c	Sun Mar 24 00:02:20 2013 +0800
+++ b/common-algo.c	Tue Mar 26 01:35:22 2013 +0800
@@ -213,6 +213,7 @@
 };
 
 algo_type sshkex[] = {
+//	{"ecdh-sha2-secp256r1", DROPBEAR_KEX_ECDH_SECP256R1, NULL, 1, NULL},
 	{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
 	{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
 	{NULL, 0, NULL, 0, NULL}
--- a/common-kex.c	Sun Mar 24 00:02:20 2013 +0800
+++ b/common-kex.c	Tue Mar 26 01:35:22 2013 +0800
@@ -549,15 +549,16 @@
 /* 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 send_msg_kexdh_reply"))
-	
-	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);
@@ -568,32 +569,40 @@
 
 	/* 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*/
@@ -609,7 +618,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");
 	}
 
@@ -619,11 +628,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 */
@@ -655,6 +664,16 @@
 	}
 }
 
+#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
+}
+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
+
 /* read the other side's algo list. buf_match_algo is a callback to match
  * algos for the client or server. */
 static void read_kex_algos() {
--- a/configure.ac	Sun Mar 24 00:02:20 2013 +0800
+++ b/configure.ac	Tue Mar 26 01:35:22 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/ecc.c	Tue Mar 26 01:35:22 2013 +0800
@@ -0,0 +1,17 @@
+#ifdef DROPBEAR_ECC
+
+void buf_put_ecc_key_string(buffer *buf, ecc_key *key) {
+	int len = key->dp->size*2 + 1;
+	buf_putint(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);
+}
+
+int buf_get_ecc_key_string(buffer *buf, ecc_key *key) {
+}
+
+
+#endif
--- a/kex.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/kex.h	Tue Mar 26 01:35:22 2013 +0800
@@ -33,10 +33,19 @@
 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();
@@ -64,6 +73,17 @@
 
 };
 
+struct kex_dh_param {
+	mp_int pub;
+	mp_int priv;
+};
+
+#ifdef DROPBEAR_ECDH
+struct kex_ecdh_param {
+	ecc_key key;
+};
+#endif
+
 #define MAX_KEXHASHBUF 2000
 
 #endif /* _KEX_H_ */
--- a/libtomcrypt/src/headers/tomcrypt_custom.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/libtomcrypt/src/headers/tomcrypt_custom.h	Tue Mar 26 01:35:22 2013 +0800
@@ -134,6 +134,13 @@
 
 #define LTC_HMAC
 
+#ifdef DROPBEAR_ECDH
+#define MECC
+#define ECC256
+#define ECC384
+#define ECC521
+#endif
+
 /* Various tidbits of modern neatoness */
 #define BASE64
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ltc_prng.c	Tue Mar 26 01:35:22 2013 +0800
@@ -0,0 +1,136 @@
+/* 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"
+
+/**
+   @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 *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 *in, unsigned long inlen, prng_state *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 *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 *prng)
+{
+   LTC_ARGCHK(out != NULL);
+   genrandom(out, outlen);
+   return CRYPT_OK;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/  
+int dropbear_prng_done(prng_state *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 *out, unsigned long *outlen, prng_state *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 *in, unsigned long inlen, prng_state *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
--- a/options.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/options.h	Tue Mar 26 01:35:22 2013 +0800
@@ -136,6 +136,8 @@
 #define DROPBEAR_RSA
 #define DROPBEAR_DSS
 
+#define DROPBEAR_ECDH
+
 /* 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	Sun Mar 24 00:02:20 2013 +0800
+++ b/random.c	Tue Mar 26 01:35:22 2013 +0800
@@ -36,6 +36,8 @@
 static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
 static int donerandinit = 0;
 
+int dropbear_ltc_prng = -1;
+
 #define INIT_SEED_SIZE 32 /* 256 bits */
 
 /* The basic setup is we read some data from /dev/(u)random or prngd and hash it
@@ -231,6 +233,13 @@
 
 	sha1_done(&hs, hashpool);
 
+#ifdef DROPBEAR_LTC_PRNG
+	if (dropbear_ltc_prng == -1) {
+		dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
+		dropbear_assert(dropbear_ltc_prng != -1);
+	}
+#endif
+
 	counter = 0;
 	donerandinit = 1;
 
--- a/random.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/random.h	Tue Mar 26 01:35:22 2013 +0800
@@ -32,4 +32,6 @@
 void addrandom(char * buf, unsigned int len);
 void gen_random_mpint(mp_int *max, mp_int *rand);
 
+extern int dropbear_ltc_prng;
+
 #endif /* _RANDOM_H_ */
--- a/session.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/session.h	Tue Mar 26 01:35:22 2013 +0800
@@ -67,7 +67,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;
+	int algo_kex;
+	int algo_hostkey;
 
 	int allow_compress; /* whether compression has started (useful in 
 							[email protected] delayed compression case) */
@@ -244,8 +244,8 @@
 } cli_state;
 
 struct clientsession {
-
-	mp_int *dh_e, *dh_x; /* Used during KEX */
+	struct kex_dh_param *dh_param;
+	struct kex_ecdh_param *ecdh_param;
 	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/svr-kex.c	Sun Mar 24 00:02:20 2013 +0800
+++ b/svr-kex.c	Tue Mar 26 01:35:22 2013 +0800
@@ -36,7 +36,7 @@
 #include "runopts.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,29 @@
 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
+#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 = SSH_MSG_NEWKEYS;
@@ -70,19 +79,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();
@@ -90,9 +90,23 @@
 	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_pub(ses.writepayload, &ecdh_param->key);
+		free_kexecdh_param(ecdh_param);
+#endif
+	}
 
 	/* calc the signature */
 	buf_put_sign(ses.writepayload, svr_opts.hostkey, 
--- a/sysoptions.h	Sun Mar 24 00:02:20 2013 +0800
+++ b/sysoptions.h	Tue Mar 26 01:35:22 2013 +0800
@@ -60,24 +60,20 @@
 #define DROPBEAR_SUCCESS 0
 #define DROPBEAR_FAILURE -1
 
-/* various algorithm identifiers */
-#define DROPBEAR_KEX_DH_GROUP1 0
-#define DROPBEAR_KEX_DH_GROUP14 1
-
 #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
 #endif
 
+#ifdef DROPBEAR_ECDH
+#define DROPBEAR_LTC_PRNG
+#endif
+
 #define SHA1_HASH_SIZE 20
 #define MD5_HASH_SIZE 16
 
@@ -93,6 +89,13 @@
 #define MAX_MAC_LEN 20
 #endif
 
+#if defined(DROPBEAR_ECDH) || defined (DROPBEAR_ECDSA)
+#define DROPBEAR_ECC
+#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 */