diff --git a/CHANGES b/CHANGES
index ace4cecbb06ed83c086b3f9b637f874d70f56ae8..85e7bc5b333b9a7277174551e0868d1f76610ebc 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,24 @@
+0.46
+
+- Fix long-standing bug which caused connections to be closed if an ssh-agent
+  socket was no longer available
+
+- print a warning if we seem to be blocking on /dev/random 
+  (suggested by Paul Fox)
+
+- fixed a memory leak in DSS code (thanks to Boris Berezovsky for the patch)
+
+- dbclient -L no longer segfaults, allocate correct buffer size (thanks
+  to David Cook for reporting it)
+
+- added RSA blinding (recommended by Dan Kaminsky)
+
+- rearranged bignum reading/random generation code
+
+- Reset the non-blocking status on stderr and stdout as well as stdin,
+  fixes a problem where the shell running dbclient will exit (thanks to 
+  Brent Roman for reporting it)
+
 0.45 - Mon March 7 2005
 
 - Makefile no longer appends 'static' to statically linked binaries
diff --git a/Makefile.in b/Makefile.in
index 1fa0f99bc4f12ce22ff87a97254c697510bea794..fc820dda75d5c40075b201a4c4368e602cdd2e44 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -69,7 +69,7 @@ AR=@AR@
 RANLIB=@RANLIB@
 STRIP=@STRIP@
 INSTALL=@INSTALL@
-CFLAGS=-I. -I$(srcdir)/libtomcrypt @CFLAGS@
+CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ @CFLAGS@
 LIBS=$(LTC) $(LTM) @LIBS@
 LDFLAGS=@LDFLAGS@
 
diff --git a/TODO b/TODO
index 4b82efc96ef1f9914b976eb67359d1e0678f426c..9807f599b45903ebb37acbc4ab959e348a557781 100644
--- a/TODO
+++ b/TODO
@@ -2,12 +2,12 @@ Current:
 
 Things which might need doing:
 
+- default private dbclient keys
+
 - Make options.h generated from configure perhaps?
 
 - Improved queueing of unauthed connections
 
-- fix agent fwd problems
-
 - handle /etc/environment in AIX
 
 - check that there aren't timing issues with valid/invalid user authentication
@@ -15,9 +15,9 @@ Things which might need doing:
 
 - Binding to different interfaces
 
-- possible RSA blinding? need to check whether this is vuln to timing attacks
 - check PRNG
-- CTR mode, SSH_MSG_IGNORE sending to improve CBC security
+- CTR mode
+- SSH_MSG_IGNORE sending to improve CBC security
 - DH Group Exchange possibly, or just add group14 (whatever it's called today)
 
 - fix scp.c for IRIX
diff --git a/algo.h b/algo.h
index 3e8ebb553416310d69bfb0146764170526642a5b..5ed01cc7ea6a6576e9e52ed6106eb2193f89dbc1 100644
--- a/algo.h
+++ b/algo.h
@@ -51,13 +51,13 @@ extern const struct dropbear_cipher dropbear_nocipher;
 extern const struct dropbear_hash dropbear_nohash;
 
 struct dropbear_cipher {
-	const struct _cipher_descriptor *cipherdesc;
+	const struct ltc_cipher_descriptor *cipherdesc;
 	unsigned long keysize;
 	unsigned char blocksize;
 };
 
 struct dropbear_hash {
-	const struct _hash_descriptor *hashdesc;
+	const struct ltc_hash_descriptor *hashdesc;
 	unsigned long keysize;
 	unsigned char hashsize;
 };
diff --git a/auth.h b/auth.h
index 399db2d8f0bf98fd3e51921dc9fca5868b7370c1..548e0174a7ba07c13e33687f040b5f3f87511b1e 100644
--- a/auth.h
+++ b/auth.h
@@ -84,13 +84,13 @@ struct AuthState {
 
 };
 
-struct PubkeyList;
-/* A singly linked list of pubkeys */
-struct PubkeyList {
+struct SignKeyList;
+/* A singly linked list of signing keys */
+struct SignKeyList {
 
 	sign_key *key;
 	int type; /* The type of key */
-	struct PubkeyList *next;
+	struct SignKeyList *next;
 	/* filename? or the buffer? for encrypted keys, so we can later get
 	 * the private key portion */
 
diff --git a/bignum.c b/bignum.c
index 97901fbdd883852aa2449bf1af107665ad3efd86..60b52207b27a12f562ce569db7ee050cd2be7498 100644
--- a/bignum.c
+++ b/bignum.c
@@ -52,9 +52,9 @@ void m_mp_init_multi(mp_int *mp, ...)
     va_end(args);
 }
 
-void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len) {
+void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
 
-	if (mp_read_unsigned_bin(mp, bytes, len) != MP_OKAY) {
+	if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
 		dropbear_exit("mem alloc error");
 	}
 }
diff --git a/bignum.h b/bignum.h
index 2a807af98ad94396559c45c6d1066638150dcd8f..042f81151f9760b520d2fb8a24505d0df7e8cf6f 100644
--- a/bignum.h
+++ b/bignum.h
@@ -29,7 +29,7 @@
 
 void m_mp_init(mp_int *mp);
 void m_mp_init_multi(mp_int *mp, ...);
-void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len);
+void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
 void sha1_process_mp(hash_state *hs, mp_int *mp);
 
 #endif /* _BIGNUM_H_ */
diff --git a/buffer.c b/buffer.c
index dff861f15a5f1d775b224d5a4fd044ce9c2c9a20..97045ffcfc3acba3f05b86c9a7bd452e1197effb 100644
--- a/buffer.c
+++ b/buffer.c
@@ -160,6 +160,16 @@ unsigned char buf_getbyte(buffer* buf) {
 	return buf->data[buf->pos++];
 }
 
+/* Get a bool from the buffer and increment the pos */
+unsigned char buf_getbool(buffer* buf) {
+
+	unsigned char b;
+	b = buf_getbyte(buf);
+	if (b != 0)
+		b = 1;
+	return b;
+}
+
 /* put a byte, incrementing the length if required */
 void buf_putbyte(buffer* buf, unsigned char val) {
 
diff --git a/buffer.h b/buffer.h
index e1031a1b70aef9c67f66452f9f38defe75697429..f9aa6fa28dbeeb395c6cab7a790e8c31afacb001 100644
--- a/buffer.h
+++ b/buffer.h
@@ -50,6 +50,7 @@ void buf_setpos(buffer* buf, unsigned int pos);
 void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
 void buf_incrwritepos(buffer* buf, unsigned int incr);
 unsigned char buf_getbyte(buffer* buf);
+unsigned char buf_getbool(buffer* buf);
 void buf_putbyte(buffer* buf, unsigned char val);
 unsigned char* buf_getptr(buffer* buf, unsigned int len);
 unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
diff --git a/channel.h b/channel.h
index 225fafb69a0c0ac4fcb017d0bbf0cc54bddc5e5d..a2fe87adbfb3a17daee4c8909375d371023da1e8 100644
--- a/channel.h
+++ b/channel.h
@@ -100,7 +100,7 @@ void chaninitialise();
 void chancleanup();
 void setchannelfds(fd_set *readfd, fd_set *writefd);
 void channelio(fd_set *readfd, fd_set *writefd);
-struct Channel* getchannel(unsigned int chan);
+struct Channel* getchannel();
 struct Channel* newchannel(unsigned int remotechan, 
 		const struct ChanType *type, 
 		unsigned int transwindow, unsigned int transmaxpacket);
diff --git a/cli-auth.c b/cli-auth.c
index dfd9bbb008fbbcd543adda5efac12a74f0b668ad..fc51061a515a833cc79c88ebb9096dc0616b4ae1 100644
--- a/cli-auth.c
+++ b/cli-auth.c
@@ -127,7 +127,7 @@ void recv_msg_userauth_failure() {
 
 	methods = buf_getstring(ses.payload, &methlen);
 
-	partial = buf_getbyte(ses.payload);
+	partial = buf_getbool(ses.payload);
 
 	if (partial) {
 		dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required");
diff --git a/cli-authpubkey.c b/cli-authpubkey.c
index 61b17d9822b58b79277b6f7919f3d99b22a83f36..9d36bc38c475ef0b846b196362593305519e5da8 100644
--- a/cli-authpubkey.c
+++ b/cli-authpubkey.c
@@ -38,29 +38,29 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
  * We use it to remove the key we tried from the list */
 void cli_pubkeyfail() {
 
-	struct PubkeyList *keyitem;
-	struct PubkeyList **previtem;
+	struct SignKeyList *keyitem;
+	struct SignKeyList **previtem;
 
 	TRACE(("enter cli_pubkeyfail"))
-	previtem = &cli_opts.pubkeys;
+	previtem = &cli_opts.privkeys;
 
 	/* Find the key we failed with, and remove it */
-	for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
-		if (keyitem == cli_ses.lastpubkey) {
+	for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
+		if (keyitem == cli_ses.lastprivkey) {
 			*previtem = keyitem->next;
 		}
 		previtem = &keyitem;
 	}
 
-	sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */
-	m_free(cli_ses.lastpubkey);
+	sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
+	m_free(cli_ses.lastprivkey);
 
 	TRACE(("leave cli_pubkeyfail"))
 }
 
 void recv_msg_userauth_pk_ok() {
 
-	struct PubkeyList *keyitem;
+	struct SignKeyList *keyitem;
 	buffer* keybuf;
 	char* algotype = NULL;
 	unsigned int algolen;
@@ -80,7 +80,7 @@ void recv_msg_userauth_pk_ok() {
 
 	/* Iterate through our keys, find which one it was that matched, and
 	 * send a real request with that key */
-	for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
+	for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
 
 		if (keyitem->type != keytype) {
 			/* Types differed */
@@ -172,11 +172,11 @@ int cli_auth_pubkey() {
 
 	TRACE(("enter cli_auth_pubkey"))
 
-	if (cli_opts.pubkeys != NULL) {
+	if (cli_opts.privkeys != NULL) {
 		/* Send a trial request */
-		send_msg_userauth_pubkey(cli_opts.pubkeys->key,
-				cli_opts.pubkeys->type, 0);
-		cli_ses.lastpubkey = cli_opts.pubkeys;
+		send_msg_userauth_pubkey(cli_opts.privkeys->key,
+				cli_opts.privkeys->type, 0);
+		cli_ses.lastprivkey = cli_opts.privkeys;
 		TRACE(("leave cli_auth_pubkey-success"))
 		return 1;
 	} else {
diff --git a/cli-channel.c b/cli-channel.c
index 42e165b5e14896b30740a68bfa5714861822cb4a..1bd49abcf79bd9a67db158d7ebbdb42741e3f436 100644
--- a/cli-channel.c
+++ b/cli-channel.c
@@ -33,15 +33,12 @@
 /* We receive channel data - only used by the client chansession code*/
 void recv_msg_channel_extended_data() {
 
-	unsigned int chan;
 	struct Channel *channel;
 	unsigned int datatype;
 
 	TRACE(("enter recv_msg_channel_extended_data"))
 
-	chan = buf_getint(ses.payload);
-	channel = getchannel(chan);
-
+	channel = getchannel();
 	if (channel == NULL) {
 		dropbear_exit("Unknown channel");
 	}
diff --git a/cli-chansession.c b/cli-chansession.c
index 76e9dfae536c5b18c7d0686d27eaa7aab88be8f0..a8363ac8d5cc25a6512358ec165f8abc74337334 100644
--- a/cli-chansession.c
+++ b/cli-chansession.c
@@ -62,7 +62,7 @@ static void cli_chansessreq(struct Channel *channel) {
 	TRACE(("enter cli_chansessreq"))
 
 	type = buf_getstring(ses.payload, NULL);
-	wantreply = buf_getbyte(ses.payload);
+	wantreply = buf_getbool(ses.payload);
 
 	if (strcmp(type, "exit-status") != 0) {
 		TRACE(("unknown request '%s'", type))
diff --git a/cli-runopts.c b/cli-runopts.c
index 3ac5c2b24249cbcbd5f13c0e66a3aadb2382562b..285c51d60f33fc1742e51d563d0ede05573b4ad8 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -53,7 +53,7 @@ static void printhelp() {
 					"-i <identityfile>   (multiple allowed)\n"
 #endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
-					"-L <listenport:remotehsot:reportport> Local port forwarding\n"
+					"-L <listenport:remotehost:remoteport> Local port forwarding\n"
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 					"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
@@ -89,7 +89,7 @@ void cli_getopts(int argc, char ** argv) {
 	cli_opts.cmd = NULL;
 	cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	cli_opts.pubkeys = NULL;
+	cli_opts.privkeys = NULL;
 #endif
 #ifdef ENABLE_CLI_LOCALTCPFWD
 	cli_opts.localfwds = NULL;
@@ -271,7 +271,7 @@ void cli_getopts(int argc, char ** argv) {
 #ifdef ENABLE_CLI_PUBKEY_AUTH
 static void loadidentityfile(const char* filename) {
 
-	struct PubkeyList * nextkey;
+	struct SignKeyList * nextkey;
 	sign_key *key;
 	int keytype;
 
@@ -284,11 +284,11 @@ static void loadidentityfile(const char* filename) {
 
 	} else {
 
-		nextkey = (struct PubkeyList*)m_malloc(sizeof(struct PubkeyList));
+		nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
 		nextkey->key = key;
-		nextkey->next = cli_opts.pubkeys;
+		nextkey->next = cli_opts.privkeys;
 		nextkey->type = keytype;
-		cli_opts.pubkeys = nextkey;
+		cli_opts.privkeys = nextkey;
 	}
 }
 #endif
diff --git a/cli-session.c b/cli-session.c
index 4d6a6458c247e768cc46ee10cd1e7e0b7b72eba1..8b58526b4d4d14445c10bcaeb714cc13f1ee39f9 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -113,16 +113,20 @@ static void cli_session_init() {
 	cli_ses.tty_raw_mode = 0;
 	cli_ses.winchange = 0;
 
-	/* We store stdin's flags, so we can set them back on exit (otherwise
-	 * busybox's ash isn't happy */
+	/* We store std{in,out,err}'s flags, so we can set them back on exit
+	 * (otherwise busybox's ash isn't happy */
 	cli_ses.stdincopy = dup(STDIN_FILENO);
 	cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
+	cli_ses.stdoutcopy = dup(STDOUT_FILENO);
+	cli_ses.stdoutflags = fcntl(STDOUT_FILENO, F_GETFL, 0);
+	cli_ses.stderrcopy = dup(STDERR_FILENO);
+	cli_ses.stderrflags = fcntl(STDERR_FILENO, F_GETFL, 0);
 
 	cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
 									  specific exit status */
 
 	/* Auth */
-	cli_ses.lastpubkey = NULL;
+	cli_ses.lastprivkey = NULL;
 	cli_ses.lastauthtype = 0;
 
 	/* For printing "remote host closed" for the user */
@@ -250,9 +254,11 @@ void cli_session_cleanup() {
 		return;
 	}
 
-	/* Set stdin back to non-blocking - busybox ash dies nastily
-	 * if we don't revert the flags */
+	/* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if
+	 * we don't revert the flags */
 	fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
+	fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
+	fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
 
 	cli_tty_cleanup();
 
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c
index aa5b72019bd44abf32ffa5c1954c80c59f4fa54a..300a2fabeff1107fdcd4917bd04ee48cf1f52e0f 100644
--- a/cli-tcpfwd.c
+++ b/cli-tcpfwd.c
@@ -94,7 +94,7 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
 	TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
 				remoteport));
 
-	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
+	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
 	tcpinfo->sendaddr = m_strdup(remoteaddr);
 	tcpinfo->sendport = remoteport;
 	tcpinfo->listenport = listenport;
diff --git a/common-algo.c b/common-algo.c
index 1975864e744175b036fb7d734a181cf1cf7d0c41..ea9c31143667af4b6aa78c07fcf6125204609576 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -125,7 +125,7 @@ algo_type sshkex[] = {
  * This should be run before using any of the ciphers/hashes */
 void crypto_init() {
 
-	const struct _cipher_descriptor *regciphers[] = {
+	const struct ltc_cipher_descriptor *regciphers[] = {
 #ifdef DROPBEAR_AES128_CBC
 		&aes_desc,
 #endif
@@ -141,7 +141,7 @@ void crypto_init() {
 		NULL
 	};
 
-	const struct _hash_descriptor *reghashes[] = {
+	const struct ltc_hash_descriptor *reghashes[] = {
 		/* we need sha1 for hostkey stuff regardless */
 		&sha1_desc,
 #ifdef DROPBEAR_MD5_HMAC
diff --git a/common-channel.c b/common-channel.c
index 6f73fab8b0c8c2f7961ddf0adda9ef4cc82f8a76..f03039a174536c6f69339f5d8f01297c9c2f5868 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -162,8 +162,13 @@ struct Channel* newchannel(unsigned int remotechan,
 	return newchan;
 }
 
-/* Get the channel structure corresponding to a channel number */
-struct Channel* getchannel(unsigned int chan) {
+/* Returns the channel structure corresponding to the channel in the current
+ * data packet (ses.payload must be positioned appropriately) */
+struct Channel* getchannel() {
+
+	unsigned int chan;
+
+	chan = buf_getint(ses.payload);
 	if (chan >= ses.chansize || ses.channels[chan] == NULL) {
 		return NULL;
 	}
@@ -474,14 +479,11 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) {
  * etc) FD is also EOF */
 void recv_msg_channel_eof() {
 
-	unsigned int chan;
 	struct Channel * channel;
 
 	TRACE(("enter recv_msg_channel_eof"))
 
-	chan = buf_getint(ses.payload);
-	channel = getchannel(chan);
-
+	channel = getchannel();
 	if (channel == NULL) {
 		dropbear_exit("EOF for unknown channel");
 	}
@@ -500,15 +502,11 @@ void recv_msg_channel_eof() {
 /* Handle channel closure(), respond in kind and close the channels */
 void recv_msg_channel_close() {
 
-	unsigned int chan;
 	struct Channel * channel;
 
 	TRACE(("enter recv_msg_channel_close"))
 
-	chan = buf_getint(ses.payload);
-	TRACE(("close channel = %d", chan))
-	channel = getchannel(chan);
-
+	channel = getchannel();
 	if (channel == NULL) {
 		/* disconnect ? */
 		dropbear_exit("Close for unknown channel");
@@ -567,14 +565,11 @@ static void deletechannel(struct Channel *channel) {
  * such as chansession or x11fwd */
 void recv_msg_channel_request() {
 
-	unsigned int chan;
 	struct Channel *channel;
 
 	TRACE(("enter recv_msg_channel_request"))
 	
-	chan = buf_getint(ses.payload);
-	channel = getchannel(chan);
-
+	channel = getchannel();
 	if (channel == NULL) {
 		/* disconnect ? */
 		dropbear_exit("Unknown channel");
@@ -666,12 +661,9 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
 /* We receive channel data */
 void recv_msg_channel_data() {
 
-	unsigned int chan;
 	struct Channel *channel;
 
-	chan = buf_getint(ses.payload);
-	channel = getchannel(chan);
-
+	channel = getchannel();
 	if (channel == NULL) {
 		dropbear_exit("Unknown channel");
 	}
@@ -738,13 +730,10 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
  * as data is sent, and incremented upon receiving window-adjust messages */
 void recv_msg_channel_window_adjust() {
 
-	unsigned int chan;
 	struct Channel * channel;
 	unsigned int incr;
 	
-	chan = buf_getint(ses.payload);
-	channel = getchannel(chan);
-
+	channel = getchannel();
 	if (channel == NULL) {
 		dropbear_exit("Unknown channel");
 	}
@@ -961,14 +950,12 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
  * successful*/
 void recv_msg_channel_open_confirmation() {
 
-	unsigned int chan;
 	struct Channel * channel;
 	int ret;
 
 	TRACE(("enter recv_msg_channel_open_confirmation"))
-	chan = buf_getint(ses.payload);
 
-	channel = getchannel(chan);
+	channel = getchannel();
 	if (channel == NULL) {
 		dropbear_exit("Unknown channel");
 	}
@@ -977,7 +964,8 @@ void recv_msg_channel_open_confirmation() {
 	channel->transwindow = buf_getint(ses.payload);
 	channel->transmaxpacket = buf_getint(ses.payload);
 	
-	TRACE(("new chan remote %d localho %d", channel->remotechan, chan))
+	TRACE(("new chan remote %d local %d", 
+				channel->remotechan, channel->index))
 
 	/* Run the inithandler callback */
 	if (channel->type->inithandler) {
@@ -995,11 +983,9 @@ void recv_msg_channel_open_confirmation() {
 /* Notification that our channel open request failed */
 void recv_msg_channel_open_failure() {
 
-	unsigned int chan;
 	struct Channel * channel;
-	chan = buf_getbyte(ses.payload);
 
-	channel = getchannel(chan);
+	channel = getchannel();
 	if (channel == NULL) {
 		dropbear_exit("Unknown channel");
 	}
diff --git a/common-kex.c b/common-kex.c
index 97e341dfbf59251cb4bc1c2caf61d1437ba78575..8a8aa932eb35bb783860f4f6f7af2edde8283109 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -457,7 +457,6 @@ void recv_msg_kexinit() {
 	/* the rest of ses.kexhashbuf will be done after DH exchange */
 
 	ses.kexstate.recvkexinit = 1;
-//	ses.expecting = 0; // client matt
 
 	TRACE(("leave recv_msg_kexinit"))
 }
@@ -470,18 +469,13 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
 	DEF_MP_INT(dh_p);
 	DEF_MP_INT(dh_q);
 	DEF_MP_INT(dh_g);
-	unsigned char randbuf[DH_P_LEN];
-	int dh_q_len;
 
 	TRACE(("enter send_msg_kexdh_reply"))
 	
 	m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
 
 	/* read the prime and generator*/
-	if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
-			!= MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN);
 	
 	if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
 		dropbear_exit("Diffie-Hellman error");
@@ -496,16 +490,8 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
 		dropbear_exit("Diffie-Hellman error");
 	}
 
-	dh_q_len = mp_unsigned_bin_size(&dh_q);
-
-	/* calculate our random value dh_y */
-	do {
-		assert((unsigned int)dh_q_len <= sizeof(randbuf));
-		genrandom(randbuf, dh_q_len);
-		if (mp_read_unsigned_bin(dh_priv, randbuf, dh_q_len) != MP_OKAY) {
-			dropbear_exit("Diffie-Hellman error");
-		}
-	} while (mp_cmp(dh_priv, &dh_q) == MP_GT || mp_cmp_d(dh_priv, 0) != MP_GT);
+	/* Generate a private portion 0 < dh_priv < dh_q */
+	gen_random_mpint(&dh_q, dh_priv);
 
 	/* f = g^y mod p */
 	if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
@@ -527,10 +513,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
 
 	/* read the prime and generator*/
 	mp_init(&dh_p);
-	if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
-			!= MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);
 
 	/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
 	if (mp_cmp(dh_pub_them, &dh_p) != MP_LT 
@@ -683,7 +666,7 @@ static void read_kex_algos() {
 	buf_eatstring(ses.payload);
 
 	/* first_kex_packet_follows */
-	if (buf_getbyte(ses.payload)) {
+	if (buf_getbool(ses.payload)) {
 		ses.kexstate.firstfollows = 1;
 		/* if the guess wasn't good, we ignore the packet sent */
 		if (!allgood) {
diff --git a/dbclient.1 b/dbclient.1
new file mode 100644
index 0000000000000000000000000000000000000000..fc6f0d07f227f4a6978853bcc4e372843bb1a54b
--- /dev/null
+++ b/dbclient.1
@@ -0,0 +1,69 @@
+.TH dbclient 1
+.SH NAME
+dbclient \- lightweight SSH2 client
+.SH SYNOPSIS
+.B dbclient
+[\-Tt] [\-p
+.I port\fR] [\-i
+.I id\fR] [\-L
+.I l\fR:\fIh\fR:\fIr\fR] [\-R
+.I l\fR:\fIh\fR:\fIr\fR] [\-l
+.IR user ]
+.I host
+.SH DESCRIPTION
+.B dbclient
+is a SSH 2 client designed to be small enough to be used in small memory
+environments, while still being functional and secure enough for general use.
+.SH OPTIONS
+.TP
+.B \-p \fIport
+Remote port.
+Connect to port
+.I port
+on the remote host.
+Default is 22.
+.TP
+.B \-i \fIidfile
+Identity file.
+Read the identity from file
+.I idfile
+(multiple allowed).
+.TP
+.B \-L \fIlocalport\fR:\fIremotehost\fR:\fIremoteport\fR
+Local port forwarding.
+Forward the port
+.I localport
+on the local host to port
+.I remoteport
+on the remote host
+.IR remotehost .
+.TP
+.B \-R \fIlocalport\fR:\fIremotehost\fR:\fIremoteport\fR
+Remote port forwarding.
+Forward the port
+.I remoteport
+on the remote host
+.I remotehost
+to port
+.I localport
+on the local host.
+.TP
+.B \-l \fIuser
+Username.
+Login as
+.I user
+on the remote host.
+.TP
+.B \-t
+Allocate a pty.
+.TP
+.B \-T
+Don't allocate a pty.
+.SH AUTHOR
+Matt Johnston (matt@ucc.asn.au).
+.br
+Gerrit Pape (pape@smarden.org) wrote this manual page.
+.SH SEE ALSO
+dropbear(8), dropbearkey(8)
+.P
+http://matt.ucc.asn.au/dropbear/dropbear.html
diff --git a/dbutil.c b/dbutil.c
index 5f3a45dfb84192247f72c6b201cbe7c2a2b709ec..45c720e3308189ee1ee968e9dbc9fece6284e288 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -430,10 +430,11 @@ char* getaddrhostname(struct sockaddr_storage * addr) {
 }
 
 #ifdef DEBUG_TRACE
-void printhex(unsigned char* buf, int len) {
+void printhex(const char * label, const unsigned char * buf, int len) {
 
 	int i;
 
+	fprintf(stderr, "%s\n", label);
 	for (i = 0; i < len; i++) {
 		fprintf(stderr, "%02x", buf[i]);
 		if (i % 16 == 15) {
diff --git a/dbutil.h b/dbutil.h
index 6363f70d1107d135f638c4500c9fe30f89b50fe2..d90494944462e3ee89500f3e7b7a1bfae016c4d0 100644
--- a/dbutil.h
+++ b/dbutil.h
@@ -41,7 +41,7 @@ void dropbear_close(const char* format, ...);
 void dropbear_log(int priority, const char* format, ...);
 #ifdef DEBUG_TRACE
 void dropbear_trace(const char* format, ...);
-void printhex(unsigned char* buf, int len);
+void printhex(const char * label, const unsigned char * buf, int len);
 extern int debug_trace;
 #endif
 char * stripcontrol(const char * text);
diff --git a/debian/README.Debian.diet b/debian/README.Debian.diet
new file mode 100644
index 0000000000000000000000000000000000000000..bd0cb5cc8021acd8a40e8328f1f83e66c729fb58
--- /dev/null
+++ b/debian/README.Debian.diet
@@ -0,0 +1,15 @@
+Building with the diet libc
+---------------------------
+
+This package optionally can be built with the diet libc instead of the
+glibc to provide small statically linked programs.  The resulting package
+has no dependency on any other package.
+
+To use the diet libc, make sure the latest versions of the dietlibc-dev
+package is installed, and set DEB_BUILD_OPTIONS=diet in the environment
+when building the package, e.g.:
+
+ # apt-get install dietlibc-dev
+ $ DEB_BUILD_OPTIONS=diet fakeroot apt-get source -b dropbear
+
+ -- Gerrit Pape <pape@smarden.org>, Sat, 17 Jul 2004 19:09:34 +0000
diff --git a/debug.h b/debug.h
index 7b1e2b57de4aebc4337189c86e1b3b31c938c576..93cb89178b6be47fe612a1e32a7083215aaebfd3 100644
--- a/debug.h
+++ b/debug.h
@@ -39,7 +39,7 @@
  * Caution: Don't use this in an unfriendly environment (ie unfirewalled),
  * 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
diff --git a/dropbear.8 b/dropbear.8
index a574ff2d86c04aa9bf12b5d9cb675d4085be2d0d..1cf5c115e1b2c78f97aa30c977bc1230db91c81f 100644
--- a/dropbear.8
+++ b/dropbear.8
@@ -76,6 +76,6 @@ Matt Johnston (matt@ucc.asn.au).
 .br
 Gerrit Pape (pape@smarden.org) wrote this manual page.
 .SH SEE ALSO
-dropbearkey(8)
+dropbearkey(8), dbclient(1)
 .P
 http://matt.ucc.asn.au/dropbear/dropbear.html
diff --git a/dropbearkey.8 b/dropbearkey.8
index 3128007da84a109e178be10bda2d130aa7e37a77..a093d85ea7f6b317a294e1950d5839f1139f80a0 100644
--- a/dropbearkey.8
+++ b/dropbearkey.8
@@ -42,6 +42,6 @@ Matt Johnston (matt@ucc.asn.au).
 .br
 Gerrit Pape (pape@smarden.org) wrote this manual page.
 .SH SEE ALSO
-dropbear(8)
+dropbear(8), dbclient(1)
 .P
 http://matt.ucc.asn.au/dropbear/dropbear.html
diff --git a/dss.c b/dss.c
index 6429ede1e575a762704f56ac43dbde8f41cc40c8..cb877ca5e0abc78baa26100b5b43cd00dbd3bbc2 100644
--- a/dss.c
+++ b/dss.c
@@ -190,10 +190,8 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
 	/* create the signature - s' and r' are the received signatures in buf */
 	/* w = (s')-1 mod q */
 	/* let val1 = s' */
-	if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE)
-			!= MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
+
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, s' >= q"))
 		goto out;
@@ -205,9 +203,8 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
 
 	/* u1 = ((SHA(M')w) mod q */
 	/* let val1 = SHA(M') = msghash */
-	if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
+
 	/* let val3 = u1 = ((SHA(M')w) mod q */
 	if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
 		goto out;
@@ -215,10 +212,7 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
 
 	/* u2 = ((r')w) mod q */
 	/* let val1 = r' */
-	if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE)
-			!= MP_OKAY) {
-		goto out;
-	}
+	bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, r' >= q"))
 		goto out;
@@ -261,6 +255,7 @@ out:
 }
 #endif /* DROPBEAR_SIGNKEY_VERIFY */
 
+#ifdef DSS_PROTOK	
 /* convert an unsigned mp into an array of bytes, malloced.
  * This array must be freed after use, len contains the length of the array,
  * if len != NULL */
@@ -279,6 +274,7 @@ static unsigned char* mptobytes(mp_int *mp, int *len) {
 	}
 	return ret;
 }
+#endif
 
 /* Sign the data presented with key, writing the signature contents
  * to the buffer
@@ -304,8 +300,6 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
 	unsigned char *privkeytmp;
 	unsigned char proto_k[SHA512_HASH_SIZE];
 	DEF_MP_INT(dss_protok);
-#else
-	unsigned char kbuf[SHA1_HASH_SIZE];
 #endif
 	DEF_MP_INT(dss_k);
 	DEF_MP_INT(dss_m);
@@ -343,22 +337,16 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
 
 	/* generate k */
 	m_mp_init(&dss_protok);
-	bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE);
+	bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
 	mp_mod(&dss_protok, key->q, &dss_k);
 	mp_clear(&dss_protok);
 	m_burn(proto_k, SHA512_HASH_SIZE);
 #else /* DSS_PROTOK not defined*/
-	do {
-		genrandom(kbuf, SHA1_HASH_SIZE);
-		if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) {
-			dropbear_exit("dss error");
-		}
-	} while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT);
-	m_burn(kbuf, SHA1_HASH_SIZE);
+	gen_random_mpint(key->q, &dss_k);
 #endif
 
 	/* now generate the actual signature */
-	bytestomp(&dss_m, msghash, SHA1_HASH_SIZE);
+	bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
 
 	/* g^k mod p */
 	if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) !=  MP_OKAY) {
@@ -417,7 +405,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
 	mp_clear(&dss_s);
 	buf_incrwritepos(buf, writelen);
 
-	mp_clear_multi(&dss_k, &dss_temp1, &dss_temp1, &dss_r, &dss_s,
+	mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
 			&dss_m, NULL);
 	
 	/* create the signature to return */
diff --git a/gendss.c b/gendss.c
index d5897227d9780f3d8975bdfb0fc164daa2d44393..bf46d3d0095e6d3b8f3e6ccb8a0baad06052708f 100644
--- a/gendss.c
+++ b/gendss.c
@@ -77,10 +77,7 @@ static void getq(dss_key *key) {
 	buf[0] |= 0x80; /* top bit high */
 	buf[QSIZE-1] |= 0x01; /* bottom bit high */
 
-	if (mp_read_unsigned_bin(key->q, buf, QSIZE) != MP_OKAY) {
-		fprintf(stderr, "dss key generation failed\n");
-		exit(1);
-	}
+	bytes_to_mp(key->q, buf, QSIZE);
 
 	/* 18 rounds are required according to HAC */
 	if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
@@ -116,10 +113,7 @@ static void getp(dss_key *key, unsigned int size) {
 		buf[0] |= 0x80; /* set the top bit high */
 
 		/* X is a random mp_int */
-		if (mp_read_unsigned_bin(&tempX, buf, size) != MP_OKAY) {
-			fprintf(stderr, "dss key generation failed\n");
-			exit(1);
-		}
+		bytes_to_mp(&tempX, buf, size);
 
 		/* C = X mod 2q */
 		if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
@@ -147,6 +141,7 @@ static void getp(dss_key *key, unsigned int size) {
 	} while (!result);
 
 	mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
+	m_burn(buf, size);
 	m_free(buf);
 }
 
@@ -189,22 +184,7 @@ static void getg(dss_key * key) {
 
 static void getx(dss_key *key) {
 
-	DEF_MP_INT(val);
-	char buf[QSIZE];
-	
-	m_mp_init(&val);
-	
-	do {
-		genrandom(buf, QSIZE);
-
-		if (mp_read_unsigned_bin(&val, buf, QSIZE) != MP_OKAY) {
-			fprintf(stderr, "dss key generation failed\n");
-		}
-	} while ((mp_cmp_d(&val, 1) == MP_GT) && (mp_cmp(&val, key->q) == MP_LT));
-
-	mp_copy(&val, key->x);
-	mp_clear(&val);
-
+	gen_random_mpint(key->q, key->x);
 }
 
 static void gety(dss_key *key) {
diff --git a/genrsa.c b/genrsa.c
index 57115193ad6f5c083b633768d9437711faf50824..73a7984ec92869c505fad4b56142830c0e9b0606 100644
--- a/genrsa.c
+++ b/genrsa.c
@@ -108,10 +108,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
 		genrandom(buf, size+1);
 		buf[0] |= 0x80; /* MSB set */
 
-		if (mp_read_unsigned_bin(prime, buf, size+1) != MP_OKAY) {
-			fprintf(stderr, "rsa generation failed\n");
-			exit(1);
-		}
+		bytes_to_mp(prime, buf, size+1);
 
 		/* find the next integer which is prime, 8 round of miller-rabin */
 		if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
diff --git a/includes.h b/includes.h
index 50f2b7be1ad4952d70ecdad9ae54a69cb7f6a41a..6c9f0842161a762da5c2c849528a34e9b43a87f3 100644
--- a/includes.h
+++ b/includes.h
@@ -111,7 +111,7 @@
 #include <libgen.h>
 #endif
 
-#include "libtomcrypt/mycrypt.h"
+#include "libtomcrypt/src/headers/tomcrypt.h"
 #include "libtommath/tommath.h"
 
 #include "compat.h"
diff --git a/kex.h b/kex.h
index 01626ed1dc23fc88f0840bddf7f6be0c17ef0a4a..92b6c4282f005d7a3ced06cef312175b808343cb 100644
--- a/kex.h
+++ b/kex.h
@@ -37,10 +37,10 @@ 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,
 		sign_key *hostkey);
 
-void recv_msg_kexdh_init(); // server
+void recv_msg_kexdh_init(); /* server */
 
-void send_msg_kexdh_init(); // client
-void recv_msg_kexdh_reply(); // client
+void send_msg_kexdh_init(); /* client */
+void recv_msg_kexdh_reply(); /* client */
 
 extern const unsigned char dh_p_val[];
 #define DH_P_LEN 128 /* The length of the dh_p_val array */
diff --git a/options.h b/options.h
index 8fc1109fd8b8fc77dd2313946c526a128f1db0a8..7fa2ea0a52cbd235760eef1ae19e8c13d9652e99 100644
--- a/options.h
+++ b/options.h
@@ -90,6 +90,11 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
 #define DROPBEAR_RSA
 #define DROPBEAR_DSS
 
+/* 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. */
+#define RSA_BLINDING
+
 /* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
  * rather than just from the random byte source. Undefining this will save you
  * ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
@@ -313,14 +318,6 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
 #define DISABLE_AGENTFWD
 #endif
 
-#ifndef ENABLE_LOCALTCPFWD
-#define DISABLE_TCPDIRECT
-#endif
-
-#ifndef ENABLE_REMOTETCPFWD
-#define DISABLE_REMOTETCPFWD
-#endif
-
 #if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
 #define ENABLE_CLI_ANYTCPFWD 
 #endif
@@ -329,7 +326,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
 #define DROPBEAR_TCP_ACCEPT
 #endif
 
-#if defined(ENABLE_REMOTETCPFWD) || defined(ENABLE_LOCALTCPFWD) || \
+#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) || \
+	defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_SVR_LOCALTCPFWD) || \
 	defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD)
 #define USING_LISTENERS
 #endif
diff --git a/packet.c b/packet.c
index 56b31c216c344dceff9b1c4bb62787ed223f856b..ecda4102615a76dc77f68ce02c01ede019b7daa0 100644
--- a/packet.c
+++ b/packet.c
@@ -201,6 +201,7 @@ static void read_packet_init() {
 		/* decrypt it */
 		if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize), 
 					buf_getwriteptr(ses.decryptreadbuf,blocksize),
+					blocksize,
 					&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
 			dropbear_exit("error decrypting");
 		}
@@ -254,6 +255,7 @@ void decrypt_packet() {
 		while (ses.readbuf->pos < ses.readbuf->len - macsize) {
 			if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize), 
 						buf_getwriteptr(ses.decryptreadbuf, blocksize),
+						blocksize,
 						&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
 				dropbear_exit("error decrypting");
 			}
@@ -491,6 +493,7 @@ void encrypt_packet() {
 		while (clearwritebuf->pos < clearwritebuf->len) {
 			if (cbc_encrypt(buf_getptr(clearwritebuf, blocksize),
 						buf_getwriteptr(writebuf, blocksize),
+						blocksize,
 						&ses.keys->trans_symmetric_struct) != CRYPT_OK) {
 				dropbear_exit("error encrypting");
 			}
diff --git a/random.c b/random.c
index c69f6419c5dcd8412e1389ec25ec277a01968bd0..d58c8a834dd0ad7ad75c6975566763be832a91c0 100644
--- a/random.c
+++ b/random.c
@@ -25,14 +25,15 @@
 #include "includes.h"
 #include "buffer.h"
 #include "dbutil.h"
+#include "bignum.h"
 
-int donerandinit = 0;
+static int donerandinit = 0;
 
 /* this is used to generate unique output from the same hashpool */
-unsigned int counter = 0;
+static unsigned int counter = 0;
 #define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */
 
-unsigned char hashpool[SHA1_HASH_SIZE];
+static unsigned char hashpool[SHA1_HASH_SIZE];
 
 #define INIT_SEED_SIZE 32 /* 256 bits */
 
@@ -50,6 +51,7 @@ static void readrand(unsigned char* buf, unsigned int buflen);
 
 static void readrand(unsigned char* buf, unsigned int buflen) {
 
+	static int already_blocked = 0;
 	int readfd;
 	unsigned int readpos;
 	int readlen;
@@ -92,6 +94,24 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
 	/* read the actual random data */
 	readpos = 0;
 	do {
+		if (!already_blocked)
+		{
+			int ret;
+			struct timeval timeout;
+			fd_set read_fds;
+
+			timeout.tv_sec = 2; /* two seconds should be enough */
+			timeout.tv_usec = 0;
+
+			FD_ZERO(&read_fds);
+			FD_SET(readfd, &read_fds);
+			ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
+			if (ret == 0)
+			{
+				dropbear_log(LOG_INFO, "Warning: Reading the random source seems to have blocked.\nIf you experience problems, you probably need to find a better entropy source.");
+				already_blocked = 1;
+			}
+		}
 		readlen = read(readfd, &buf[readpos], buflen - readpos);
 		if (readlen <= 0) {
 			if (readlen < 0 && errno == EINTR) {
@@ -159,3 +179,38 @@ void genrandom(unsigned char* buf, unsigned int len) {
 	}
 	m_burn(hash, sizeof(hash));
 }
+
+/* Generates a random mp_int. 
+ * max is a *mp_int specifying an upper bound.
+ * rand must be an initialised *mp_int for the result.
+ * the result rand satisfies:  0 < rand < max 
+ * */
+void gen_random_mpint(mp_int *max, mp_int *rand) {
+
+	unsigned char *randbuf = NULL;
+	unsigned int len = 0;
+	const char masks[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
+
+	const int size_bits = mp_count_bits(max);
+
+	len = size_bits / 8;
+	if ((size_bits % 8) != 0) {
+		len += 1;
+	}
+
+	randbuf = (unsigned char*)m_malloc(len);
+	do {
+		genrandom(randbuf, len);
+		/* Mask out the unrequired bits - mp_read_unsigned_bin expects
+		 * MSB first.*/
+		randbuf[0] &= masks[size_bits % 8];
+
+		bytes_to_mp(rand, randbuf, len);
+
+		/* keep regenerating until we get one satisfying
+		 * 0 < rand < max    */
+	} while ( ( (max != NULL) && (mp_cmp(rand, max) != MP_LT) )
+			|| (mp_cmp_d(rand, 0) != MP_GT) );
+	m_burn(randbuf, len);
+	m_free(randbuf);
+}
diff --git a/random.h b/random.h
index 91aa342b70a5cf840dce94eac7957e87fe53522a..5ec1f24ecd0deed73d8edb51c48f13c20590ea9e 100644
--- a/random.h
+++ b/random.h
@@ -25,8 +25,11 @@
 #ifndef _RANDOM_H_
 #define _RANDOM_H_
 
+struct mp_int;
+
 void seedrandom();
 void genrandom(unsigned char* buf, int len);
 void addrandom(unsigned char* buf, int len);
+void gen_random_mpint(mp_int *max, mp_int *rand);
 
 #endif /* _RANDOM_H_ */
diff --git a/rsa.c b/rsa.c
index 1ac03578621df5344528dccc1c241c21ec823c5c..7248bed4b96a5262057d6f29cf4ce122469830e5 100644
--- a/rsa.c
+++ b/rsa.c
@@ -38,8 +38,9 @@
 
 #ifdef DROPBEAR_RSA 
 
-static mp_int * rsa_pad_em(rsa_key * key,
-		const unsigned char * data, unsigned int len);
+static void rsa_pad_em(rsa_key * key,
+		const unsigned char * data, unsigned int len,
+		mp_int * rsa_em);
 
 /* Load a public rsa key from a buffer, initialising the values.
  * The key will have the same format as buf_put_rsa_key.
@@ -203,14 +204,14 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
 	unsigned int slen;
 	DEF_MP_INT(rsa_s);
 	DEF_MP_INT(rsa_mdash);
-	mp_int *rsa_em = NULL;
+	DEF_MP_INT(rsa_em);
 	int ret = DROPBEAR_FAILURE;
 
 	TRACE(("enter buf_rsa_verify"))
 
 	assert(key != NULL);
 
-	m_mp_init_multi(&rsa_mdash, &rsa_s, NULL);
+	m_mp_init_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);
 
 	slen = buf_getint(buf);
 	if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) {
@@ -231,29 +232,25 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
 	}
 
 	/* create the magic PKCS padded value */
-	rsa_em = rsa_pad_em(key, data, len);
+	rsa_pad_em(key, data, len, &rsa_em);
 
 	if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
 		TRACE(("failed exptmod rsa_s"))
 		goto out;
 	}
 
-	if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) {
+	if (mp_cmp(&rsa_em, &rsa_mdash) == MP_EQ) {
 		/* signature is valid */
 		TRACE(("success!"))
 		ret = DROPBEAR_SUCCESS;
 	}
 
 out:
-	if (rsa_em) {
-		mp_clear(rsa_em);
-		m_free(rsa_em);
-	}
-	mp_clear_multi(&rsa_mdash, &rsa_s, NULL);
+	mp_clear_multi(&rsa_mdash, &rsa_s, &rsa_em, NULL);
 	TRACE(("leave buf_rsa_verify: ret %d", ret))
 	return ret;
-
 }
+
 #endif /* DROPBEAR_SIGNKEY_VERIFY */
 
 /* Sign the data presented with key, writing the signature contents
@@ -264,22 +261,55 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
 	unsigned int nsize, ssize;
 	unsigned int i;
 	DEF_MP_INT(rsa_s);
-	mp_int *rsa_em = NULL;
+	DEF_MP_INT(rsa_tmp1);
+	DEF_MP_INT(rsa_tmp2);
+	DEF_MP_INT(rsa_tmp3);
+	unsigned char *tmpbuf;
 	
 	TRACE(("enter buf_put_rsa_sign"))
 	assert(key != NULL);
 
-	rsa_em = rsa_pad_em(key, data, len);
+	m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
 
-	m_mp_init(&rsa_s);
+	rsa_pad_em(key, data, len, &rsa_tmp1);
 
 	/* the actual signing of the padded data */
+
+#ifdef RSA_BLINDING
+
+	/* With blinding, s = (r^(-1))((em)*r^e)^d mod n */
+
+	/* generate the r blinding value */
+	/* rsa_tmp2 is r */
+	gen_random_mpint(key->n, &rsa_tmp2);
+
+	/* rsa_tmp1 is em */
+	/* em' = em * r^e mod n */
+
+	mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s); /* rsa_s used as a temp var*/
+	mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3);
+	mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2);
+
+	/* rsa_tmp2 is em' */
+	/* s' = (em')^d mod n */
+	mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1);
+
+	/* rsa_tmp1 is s' */
+	/* rsa_tmp3 is r^(-1) mod n */
+	/* s = (s')r^(-1) mod n */
+	mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s);
+
+#else
+
 	/* s = em^d mod n */
-	if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) {
+	/* rsa_tmp1 is em */
+	if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) {
 		dropbear_exit("rsa error");
 	}
-	mp_clear(rsa_em);
-	m_free(rsa_em);
+
+#endif /* RSA_BLINDING */
+
+	mp_clear_multi(&rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
 	
 	/* create the signature to return */
 	buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
@@ -302,7 +332,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
 	mp_clear(&rsa_s);
 
 #if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
-	printhex(buf->data, buf->len);
+	printhex("RSA sig", buf->data, buf->len);
 #endif
 	
 
@@ -318,19 +348,22 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
  *
  * prefix is the ASN1 designator prefix,
  * hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14
+ *
+ * rsa_em must be a pointer to an initialised mp_int.
  */
-static mp_int * rsa_pad_em(rsa_key * key,
-		const unsigned char * data, unsigned int len) {
+static void rsa_pad_em(rsa_key * key,
+		const unsigned char * data, unsigned int len, 
+		mp_int * rsa_em) {
 
 	/* ASN1 designator (including the 0x00 preceding) */
-	const char rsa_asn1_magic[] = 
+	const unsigned char rsa_asn1_magic[] = 
 		{0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 
 		 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
-#define RSA_ASN1_MAGIC_LEN 16
+	const unsigned int RSA_ASN1_MAGIC_LEN = 16;
+
 	buffer * rsa_EM = NULL;
 	hash_state hs;
 	unsigned int nsize;
-	mp_int * rsa_em = NULL;
 	
 	assert(key != NULL);
 	assert(data != NULL);
@@ -358,16 +391,9 @@ static mp_int * rsa_pad_em(rsa_key * key,
 
 	/* Create the mp_int from the encoded bytes */
 	buf_setpos(rsa_EM, 0);
-	rsa_em = (mp_int*)m_malloc(sizeof(mp_int));
-	m_mp_init(rsa_em);
-	if (mp_read_unsigned_bin(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
-				rsa_EM->size) != MP_OKAY) {
-		dropbear_exit("rsa error");
-	}
+	bytes_to_mp(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
+			rsa_EM->size);
 	buf_free(rsa_EM);
-
-	return rsa_em;
-
 }
 
 #endif /* DROPBEAR_RSA */
diff --git a/runopts.h b/runopts.h
index 9597ac07c49d956054faa92f56a38ab830341831..3d589e7bd8f246173590a287a93a2ca6281ff171 100644
--- a/runopts.h
+++ b/runopts.h
@@ -95,7 +95,7 @@ typedef struct cli_runopts {
 	char *cmd;
 	int wantpty;
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
+	struct SignKeyList *privkeys; /* Keys to use for public-key auth */
 #endif
 #ifdef ENABLE_CLI_REMOTETCPFWD
 	struct TCPFwdList * remotefwds;
diff --git a/scp.c b/scp.c
index e356b8b040440f6c154bd71f1c92fc4b4eae841e..ccb6c2a36e23e0822df6bf188092ad3b8958c178 100644
--- a/scp.c
+++ b/scp.c
@@ -244,9 +244,6 @@ main(int argc, char **argv)
 	extern char *optarg;
 	extern int optind;
 
-	/* hack, seems to work */
-//	__progname = argv[0];
-
 	args.list = NULL;
 	addargs(&args, "ssh");		/* overwritten with ssh_program */
 	addargs(&args, "-x");
diff --git a/session.h b/session.h
index 1d5ebb4aa68016d4d4572f6a707c1d1cb63fbf82..2dbc7f8c86680db18ff16b94c0a5e874ace07a91 100644
--- a/session.h
+++ b/session.h
@@ -211,19 +211,22 @@ struct clientsession {
 	mp_int *dh_e, *dh_x; /* Used during KEX */
 	cli_kex_state kex_state; /* Used for progressing KEX */
 	cli_state state; /* Used to progress auth/channelsession etc */
-	int something; /* XXX */
 	unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
 
 	int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */
 	struct termios saved_tio;
 	int stdincopy;
 	int stdinflags;
+	int stdoutcopy;
+	int stdoutflags;
+	int stderrcopy;
+	int stderrflags;
 
 	int winchange; /* Set to 1 when a windowchange signal happens */
 
 	int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
 						 for the last type of auth we tried */
-	struct PubkeyList *lastpubkey;
+	struct SignKeyList *lastprivkey;
 
 	int retval; /* What the command exit status was - we emulate it */
 #if 0
diff --git a/signkey.c b/signkey.c
index b6b8bdcf798ceb7010f3add86962982c62ff60cb..8dee10bed12da94d6498426800a52e635debe40b 100644
--- a/signkey.c
+++ b/signkey.c
@@ -279,7 +279,7 @@ static char * sign_key_md5_fingerprint(unsigned char* keyblob,
 	char * ret;
 	hash_state hs;
 	unsigned char hash[MD5_HASH_SIZE];
-	unsigned int h, i;
+	unsigned int i;
 	unsigned int buflen;
 
 	md5_init(&hs);
@@ -296,10 +296,11 @@ static char * sign_key_md5_fingerprint(unsigned char* keyblob,
 	memset(ret, 'Z', buflen);
 	strcpy(ret, "md5 ");
 
-	for (i = 4, h = 0; i < buflen; i+=3, h++) {
-		ret[i] = hexdig(hash[h] >> 4);
-		ret[i+1] = hexdig(hash[h] & 0x0f);
-		ret[i+2] = ':';
+	for (i = 0; i < MD5_HASH_SIZE; i++) {
+		unsigned int pos = 4 + i*3;
+		ret[pos] = hexdig(hash[i] >> 4);
+		ret[pos+1] = hexdig(hash[i] & 0x0f);
+		ret[pos+2] = ':';
 	}
 	ret[buflen-1] = 0x0;
 
@@ -313,7 +314,7 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob,
 	char * ret;
 	hash_state hs;
 	unsigned char hash[SHA1_HASH_SIZE];
-	unsigned int h, i;
+	unsigned int i;
 	unsigned int buflen;
 
 	sha1_init(&hs);
@@ -329,10 +330,11 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob,
 
 	strcpy(ret, "sha1 ");
 
-	for (i = 5, h = 0; i < buflen; i+=3, h++) {
-		ret[i] = hexdig(hash[h] >> 4);
-		ret[i+1] = hexdig(hash[h] & 0x0f);
-		ret[i+2] = ':';
+	for (i = 0; i < SHA1_HASH_SIZE; i++) {
+		unsigned int pos = 5 + 3*i;
+		ret[pos] = hexdig(hash[i] >> 4);
+		ret[pos+1] = hexdig(hash[i] & 0x0f);
+		ret[pos+2] = ':';
 	}
 	ret[buflen-1] = 0x0;
 
diff --git a/svr-authpam.c b/svr-authpam.c
index e045b74eb2b45b0ce7c6ea7deb7f49278ecb02d7..fe1f123c8ed179f8fc592dba92abeeaef773bc4c 100644
--- a/svr-authpam.c
+++ b/svr-authpam.c
@@ -155,7 +155,7 @@ void svr_auth_pam() {
 	unsigned char changepw;
 
 	/* check if client wants to change password */
-	changepw = buf_getbyte(ses.payload);
+	changepw = buf_getbool(ses.payload);
 	if (changepw) {
 		/* not implemented by this server */
 		send_msg_userauth_failure(0, 1);
diff --git a/svr-authpasswd.c b/svr-authpasswd.c
index 43488173aad57f3229bb56e0f23449b0773d16f6..5be1e2ad584e975d61a84ea9a4095d0029a3e22d 100644
--- a/svr-authpasswd.c
+++ b/svr-authpasswd.c
@@ -71,7 +71,7 @@ void svr_auth_password() {
 	}
 
 	/* check if client wants to change password */
-	changepw = buf_getbyte(ses.payload);
+	changepw = buf_getbool(ses.payload);
 	if (changepw) {
 		/* not implemented by this server */
 		send_msg_userauth_failure(0, 1);
diff --git a/svr-authpubkey.c b/svr-authpubkey.c
index 5daba0f0e65e6a4168d9a04b86e0ad03e3436852..dcd59f0b1345c917f07526149a1949d247076e60 100644
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -64,7 +64,7 @@ void svr_auth_pubkey() {
 
 	/* 0 indicates user just wants to check if key can be used, 1 is an
 	 * actual attempt*/
-	testkey = (buf_getbyte(ses.payload) == 0);
+	testkey = (buf_getbool(ses.payload) == 0);
 
 	algo = buf_getstring(ses.payload, &algolen);
 	keybloblen = buf_getint(ses.payload);
diff --git a/svr-chansession.c b/svr-chansession.c
index c04d592d80694de34e757bba91a30ea935525766..1704c6efca9dc5290e73c161991866277f6e5062 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -305,7 +305,7 @@ static void chansessionrequest(struct Channel *channel) {
 	TRACE(("enter chansessionrequest"))
 
 	type = buf_getstring(ses.payload, &typelen);
-	wantreply = buf_getbyte(ses.payload);
+	wantreply = buf_getbool(ses.payload);
 
 	if (typelen > MAX_NAME_LEN) {
 		TRACE(("leave chansessionrequest: type too long")) /* XXX send error?*/
@@ -837,7 +837,7 @@ static void execchild(struct ChanSess *chansess) {
 
 	/* close file descriptors except stdin/stdout/stderr
 	 * Need to be sure FDs are closed here to avoid reading files as root */
-	for (i = 3; i < (unsigned int)ses.maxfd; i++) {
+	for (i = 3; i <= (unsigned int)ses.maxfd; i++) {
 		if (m_close(i) == DROPBEAR_FAILURE) {
 			dropbear_exit("Error closing file desc");
 		}
@@ -862,8 +862,10 @@ static void execchild(struct ChanSess *chansess) {
 
 		if ((setgid(ses.authstate.pw->pw_gid) < 0) ||
 			(initgroups(ses.authstate.pw->pw_name, 
-						ses.authstate.pw->pw_gid) < 0) ||
-			(setuid(ses.authstate.pw->pw_uid) < 0)) {
+						ses.authstate.pw->pw_gid) < 0)) {
+			dropbear_exit("error changing user group");
+		}
+		if (setuid(ses.authstate.pw->pw_uid) < 0) {
 			dropbear_exit("error changing user");
 		}
 	} else {
diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c
index 7fbc609bb51e2494f9947c30e5dc2690fc2fb7a2..3acc4ffb7a621b48431d96579c86c9002576bed4 100644
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -78,7 +78,7 @@ void recv_msg_global_request_remotetcp() {
 	}
 
 	reqname = buf_getstring(ses.payload, &namelen);
-	wantreply = buf_getbyte(ses.payload);
+	wantreply = buf_getbool(ses.payload);
 
 	if (namelen > MAXNAMLEN) {
 		TRACE(("name len is wrong: %d", namelen))
diff --git a/svr-x11fwd.c b/svr-x11fwd.c
index e15fb82758a1c157562be7ae9f50dbb89716337f..cbc8a799be061b50b04ce471e3e8fea7f225160d 100644
--- a/svr-x11fwd.c
+++ b/svr-x11fwd.c
@@ -52,7 +52,7 @@ int x11req(struct ChanSess * chansess) {
 		return DROPBEAR_FAILURE;
 	}
 
-	chansess->x11singleconn = buf_getbyte(ses.payload);
+	chansess->x11singleconn = buf_getbool(ses.payload);
 	chansess->x11authprot = buf_getstring(ses.payload, NULL);
 	chansess->x11authcookie = buf_getstring(ses.payload, NULL);
 	chansess->x11screennum = buf_getint(ses.payload);