changeset 534:0431915df79f

- Get rid of decryptreadbuf, just decrypt in-place with readbuf - Share make_mac function for both packet creation and validation - Split recv/trans parts of key_context into their own structures
author Matt Johnston <matt@ucc.asn.au>
date Sun, 01 Mar 2009 16:15:57 +0000
parents 805ae74ec024
children 21490eea261d 7de2f22ea759
files common-kex.c common-session.c packet.c packet.h session.h
diffstat 5 files changed, 175 insertions(+), 211 deletions(-) [+]
line wrap: on
line diff
--- a/common-kex.c	Sun Mar 01 14:38:25 2009 +0000
+++ b/common-kex.c	Sun Mar 01 16:15:57 2009 +0000
@@ -272,8 +272,8 @@
 	    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;
+	    C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
+	    S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
 		mactransletter = 'E';
 		macrecvletter = 'F';
 	} else {
@@ -281,8 +281,8 @@
 	    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;
+	    C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
+	    S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
 		mactransletter = 'F';
 		macrecvletter = 'E';
 	}
@@ -292,31 +292,33 @@
 	hashkeys(C2S_key, C2S_keysize, &hs, 'C');
 	hashkeys(S2C_key, S2C_keysize, &hs, 'D');
 
-	recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name);
+	recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
 	if (recv_cipher < 0)
 	    dropbear_exit("crypto error");
-	if (ses.newkeys->recv_crypt_mode->start(recv_cipher, 
+	if (ses.newkeys->recv.crypt_mode->start(recv_cipher, 
 			recv_IV, recv_key, 
-			ses.newkeys->recv_algo_crypt->keysize, 0, 
-			&ses.newkeys->recv_cipher_state) != CRYPT_OK) {
+			ses.newkeys->recv.algo_crypt->keysize, 0, 
+			&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
 		dropbear_exit("crypto error");
 	}
 
-	trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name);
+	trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
 	if (trans_cipher < 0)
 	    dropbear_exit("crypto error");
-	if (ses.newkeys->trans_crypt_mode->start(trans_cipher, 
+	if (ses.newkeys->trans.crypt_mode->start(trans_cipher, 
 			trans_IV, trans_key, 
-			ses.newkeys->trans_algo_crypt->keysize, 0, 
-			&ses.newkeys->trans_cipher_state) != CRYPT_OK) {
+			ses.newkeys->trans.algo_crypt->keysize, 0, 
+			&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
 		dropbear_exit("crypto error");
 	}
 	
 	/* MAC keys */
-	hashkeys(ses.newkeys->transmackey, 
-			ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
-	hashkeys(ses.newkeys->recvmackey, 
-			ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
+	hashkeys(ses.newkeys->trans.mackey, 
+			ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
+	hashkeys(ses.newkeys->recv.mackey, 
+			ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
+	ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name),
+	ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name),
 
 #ifndef DISABLE_ZLIB
 	gen_new_zstreams();
@@ -334,15 +336,15 @@
 #ifndef DISABLE_ZLIB
 
 int is_compress_trans() {
-	return ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB
+	return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
 		|| (ses.authstate.authdone
-			&& ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
+			&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
 }
 
 int is_compress_recv() {
-	return ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB
+	return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
 		|| (ses.authstate.authdone
-			&& ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
+			&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
 }
 
 /* Set up new zlib compression streams, close the old ones. Only
@@ -350,47 +352,47 @@
 static void gen_new_zstreams() {
 
 	/* create new zstreams */
-	if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB
-			|| ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
-		ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
-		ses.newkeys->recv_zstream->zalloc = Z_NULL;
-		ses.newkeys->recv_zstream->zfree = Z_NULL;
+	if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
+			|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
+		ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
+		ses.newkeys->recv.zstream->zalloc = Z_NULL;
+		ses.newkeys->recv.zstream->zfree = Z_NULL;
 		
-		if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
+		if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
 			dropbear_exit("zlib error");
 		}
 	} else {
-		ses.newkeys->recv_zstream = NULL;
+		ses.newkeys->recv.zstream = NULL;
 	}
 
-	if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB
-			|| ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
-		ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
-		ses.newkeys->trans_zstream->zalloc = Z_NULL;
-		ses.newkeys->trans_zstream->zfree = Z_NULL;
+	if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
+			|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
+		ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
+		ses.newkeys->trans.zstream->zalloc = Z_NULL;
+		ses.newkeys->trans.zstream->zfree = Z_NULL;
 	
-		if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION) 
+		if (deflateInit(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION) 
 				!= Z_OK) {
 			dropbear_exit("zlib error");
 		}
 	} else {
-		ses.newkeys->trans_zstream = NULL;
+		ses.newkeys->trans.zstream = NULL;
 	}
 
 	/* clean up old keys */
-	if (ses.keys->recv_zstream != NULL) {
-		if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) {
+	if (ses.keys->recv.zstream != NULL) {
+		if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
 			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
 			dropbear_exit("crypto error");
 		}
-		m_free(ses.keys->recv_zstream);
+		m_free(ses.keys->recv.zstream);
 	}
-	if (ses.keys->trans_zstream != NULL) {
-		if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) {
+	if (ses.keys->trans.zstream != NULL) {
+		if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
 			/* Z_DATA_ERROR is ok, just means that stream isn't ended */
 			dropbear_exit("crypto error");
 		}
-		m_free(ses.keys->trans_zstream);
+		m_free(ses.keys->trans.zstream);
 	}
 }
 #endif /* DISABLE_ZLIB */
@@ -698,36 +700,36 @@
 
 	/* Handle the asymmetry */
 	if (IS_DROPBEAR_CLIENT) {
-		ses.newkeys->recv_algo_crypt = 
+		ses.newkeys->recv.algo_crypt = 
 			(struct dropbear_cipher*)s2c_cipher_algo->data;
-		ses.newkeys->trans_algo_crypt = 
+		ses.newkeys->trans.algo_crypt = 
 			(struct dropbear_cipher*)c2s_cipher_algo->data;
-		ses.newkeys->recv_crypt_mode = 
+		ses.newkeys->recv.crypt_mode = 
 			(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
-		ses.newkeys->trans_crypt_mode =
+		ses.newkeys->trans.crypt_mode =
 			(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
-		ses.newkeys->recv_algo_mac = 
+		ses.newkeys->recv.algo_mac = 
 			(struct dropbear_hash*)s2c_hash_algo->data;
-		ses.newkeys->trans_algo_mac = 
+		ses.newkeys->trans.algo_mac = 
 			(struct dropbear_hash*)c2s_hash_algo->data;
-		ses.newkeys->recv_algo_comp = s2c_comp_algo->val;
-		ses.newkeys->trans_algo_comp = c2s_comp_algo->val;
+		ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
+		ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
 	} else {
 		/* SERVER */
-		ses.newkeys->recv_algo_crypt = 
+		ses.newkeys->recv.algo_crypt = 
 			(struct dropbear_cipher*)c2s_cipher_algo->data;
-		ses.newkeys->trans_algo_crypt = 
+		ses.newkeys->trans.algo_crypt = 
 			(struct dropbear_cipher*)s2c_cipher_algo->data;
-		ses.newkeys->recv_crypt_mode =
+		ses.newkeys->recv.crypt_mode =
 			(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
-		ses.newkeys->trans_crypt_mode =
+		ses.newkeys->trans.crypt_mode =
 			(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
-		ses.newkeys->recv_algo_mac = 
+		ses.newkeys->recv.algo_mac = 
 			(struct dropbear_hash*)c2s_hash_algo->data;
-		ses.newkeys->trans_algo_mac = 
+		ses.newkeys->trans.algo_mac = 
 			(struct dropbear_hash*)s2c_hash_algo->data;
-		ses.newkeys->recv_algo_comp = c2s_comp_algo->val;
-		ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
+		ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
+		ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
 	}
 
 	/* reserved for future extensions */
--- a/common-session.c	Sun Mar 01 14:38:25 2009 +0000
+++ b/common-session.c	Sun Mar 01 16:15:57 2009 +0000
@@ -78,7 +78,6 @@
 	ses.transseq = 0;
 
 	ses.readbuf = NULL;
-	ses.decryptreadbuf = NULL;
 	ses.payload = NULL;
 	ses.recvseq = 0;
 
@@ -95,22 +94,22 @@
 	/* set all the algos to none */
 	ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
 	ses.newkeys = NULL;
-	ses.keys->recv_algo_crypt = &dropbear_nocipher;
-	ses.keys->trans_algo_crypt = &dropbear_nocipher;
-	ses.keys->recv_crypt_mode = &dropbear_mode_none;
-	ses.keys->trans_crypt_mode = &dropbear_mode_none;
+	ses.keys->recv.algo_crypt = &dropbear_nocipher;
+	ses.keys->trans.algo_crypt = &dropbear_nocipher;
+	ses.keys->recv.crypt_mode = &dropbear_mode_none;
+	ses.keys->trans.crypt_mode = &dropbear_mode_none;
 	
-	ses.keys->recv_algo_mac = &dropbear_nohash;
-	ses.keys->trans_algo_mac = &dropbear_nohash;
+	ses.keys->recv.algo_mac = &dropbear_nohash;
+	ses.keys->trans.algo_mac = &dropbear_nohash;
 
 	ses.keys->algo_kex = -1;
 	ses.keys->algo_hostkey = -1;
-	ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
-	ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
+	ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
+	ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
 
 #ifndef DISABLE_ZLIB
-	ses.keys->recv_zstream = NULL;
-	ses.keys->trans_zstream = NULL;
+	ses.keys->recv.zstream = NULL;
+	ses.keys->trans.zstream = NULL;
 #endif
 
 	/* key exchange buffers */
--- a/packet.c	Sun Mar 01 14:38:25 2009 +0000
+++ b/packet.c	Sun Mar 01 16:15:57 2009 +0000
@@ -35,9 +35,11 @@
 #include "auth.h"
 #include "channel.h"
 
-static void read_packet_init();
-static void make_mac(buffer * clearwritebuf, unsigned char *output_mac);
-static int checkmac(buffer* hashbuf, buffer* readbuf);
+static int read_packet_init();
+static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
+		buffer * clear_buf, unsigned int clear_len, 
+		unsigned char *output_mac);
+static int checkmac();
 
 #define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
 #define ZLIB_DECOMPRESS_INCR 100
@@ -102,18 +104,18 @@
 	unsigned char blocksize;
 
 	TRACE(("enter read_packet"))
-	blocksize = ses.keys->recv_algo_crypt->blocksize;
+	blocksize = ses.keys->recv.algo_crypt->blocksize;
 	
 	if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
+		int ret;
 		/* In the first blocksize of a packet */
 
 		/* Read the first blocksize of the packet, so we can decrypt it and
 		 * find the length of the whole packet */
-		read_packet_init();
+		ret = read_packet_init();
 
-		/* If we don't have the length of decryptreadbuf, we didn't read
-		 * a whole blocksize and should exit */
-		if (ses.decryptreadbuf->len == 0) {
+		if (ret == DROPBEAR_FAILURE) {
+			/* didn't read enough to determine the length */
 			TRACE(("leave read_packet: packetinit done"))
 			return;
 		}
@@ -121,7 +123,6 @@
 
 	/* Attempt to read the remainder of the packet, note that there
 	 * mightn't be any available (EAGAIN) */
-	dropbear_assert(ses.readbuf != NULL);
 	maxlen = ses.readbuf->len - ses.readbuf->pos;
 	len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
 
@@ -151,7 +152,9 @@
 
 /* Function used to read the initial portion of a packet, and determine the
  * length. Only called during the first BLOCKSIZE of a packet. */
-static void read_packet_init() {
+/* Returns DROPBEAR_SUCCESS if the length is determined, 
+ * DROPBEAR_FAILURE otherwise */
+static int read_packet_init() {
 
 	unsigned int maxlen;
 	int len;
@@ -159,14 +162,12 @@
 	unsigned char macsize;
 
 
-	blocksize = ses.keys->recv_algo_crypt->blocksize;
-	macsize = ses.keys->recv_algo_mac->hashsize;
+	blocksize = ses.keys->recv.algo_crypt->blocksize;
+	macsize = ses.keys->recv.algo_mac->hashsize;
 
 	if (ses.readbuf == NULL) {
 		/* start of a new packet */
 		ses.readbuf = buf_new(INIT_READBUF);
-		dropbear_assert(ses.decryptreadbuf == NULL);
-		ses.decryptreadbuf = buf_new(blocksize);
 	}
 
 	maxlen = blocksize - ses.readbuf->pos;
@@ -180,7 +181,7 @@
 	if (len < 0) {
 		if (errno == EINTR) {
 			TRACE(("leave read_packet_init: EINTR"))
-			return;
+			return DROPBEAR_FAILURE;
 		}
 		dropbear_exit("error reading: %s", strerror(errno));
 	}
@@ -189,22 +190,22 @@
 
 	if ((unsigned int)len != maxlen) {
 		/* don't have enough bytes to determine length, get next time */
-		return;
+		return DROPBEAR_FAILURE;
 	}
 
 	/* now we have the first block, need to get packet length, so we decrypt
 	 * the first block (only need first 4 bytes) */
 	buf_setpos(ses.readbuf, 0);
-	if (ses.keys->recv_crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), 
-				buf_getwriteptr(ses.decryptreadbuf,blocksize),
+	if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), 
+				buf_getwriteptr(ses.readbuf, blocksize),
 				blocksize,
-				&ses.keys->recv_cipher_state) != CRYPT_OK) {
+				&ses.keys->recv.cipher_state) != CRYPT_OK) {
 		dropbear_exit("error decrypting");
 	}
-	buf_setlen(ses.decryptreadbuf, blocksize);
-	len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
+	len = buf_getint(ses.readbuf) + 4 + macsize;
 
-	buf_setpos(ses.readbuf, blocksize);
+	TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
+
 
 	/* check packet length */
 	if ((len > RECV_MAX_PACKET_LEN) ||
@@ -213,9 +214,12 @@
 		dropbear_exit("bad packet size %d", len);
 	}
 
-	buf_resize(ses.readbuf, len);
+	if (len > ses.readbuf->size) {
+		buf_resize(ses.readbuf, len);		
+	}
 	buf_setlen(ses.readbuf, len);
-
+	buf_setpos(ses.readbuf, blocksize);
+	return DROPBEAR_SUCCESS;
 }
 
 /* handle the received packet */
@@ -227,68 +231,60 @@
 	unsigned int len;
 
 	TRACE(("enter decrypt_packet"))
-	blocksize = ses.keys->recv_algo_crypt->blocksize;
-	macsize = ses.keys->recv_algo_mac->hashsize;
+	blocksize = ses.keys->recv.algo_crypt->blocksize;
+	macsize = ses.keys->recv.algo_mac->hashsize;
 
 	ses.kexstate.datarecv += ses.readbuf->len;
 
 	/* we've already decrypted the first blocksize in read_packet_init */
 	buf_setpos(ses.readbuf, blocksize);
 
-	buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize);
-	buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
-	buf_setpos(ses.decryptreadbuf, blocksize);
-
-	/* decrypt it */
+	/* decrypt it in-place */
 	len = ses.readbuf->len - macsize - ses.readbuf->pos;
-	if (ses.keys->recv_crypt_mode->decrypt(
+	if (ses.keys->recv.crypt_mode->decrypt(
 				buf_getptr(ses.readbuf, len), 
-				buf_getwriteptr(ses.decryptreadbuf, len),
+				buf_getwriteptr(ses.readbuf, len),
 				len,
-				&ses.keys->recv_cipher_state) != CRYPT_OK) {
+				&ses.keys->recv.cipher_state) != CRYPT_OK) {
 		dropbear_exit("error decrypting");
 	}
 	buf_incrpos(ses.readbuf, len);
-	buf_incrwritepos(ses.decryptreadbuf, len);
+
+	printhex("readbuf decrypted", ses.readbuf->data, ses.readbuf->len);
 
 	/* check the hmac */
-	buf_setpos(ses.readbuf, ses.readbuf->len - macsize);
-	if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
+	if (checkmac() != DROPBEAR_SUCCESS) {
 		dropbear_exit("Integrity error");
 	}
 
-	/* readbuf no longer required */
-	buf_free(ses.readbuf);
-	ses.readbuf = NULL;
-
 	/* get padding length */
-	buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF);
-	padlen = buf_getbyte(ses.decryptreadbuf);
+	buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
+	padlen = buf_getbyte(ses.readbuf);
 		
 	/* payload length */
 	/* - 4 - 1 is for LEN and PADLEN values */
-	len = ses.decryptreadbuf->len - padlen - 4 - 1;
+	len = ses.readbuf->len - padlen - 4 - 1;
 	if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
 		dropbear_exit("bad packet size");
 	}
 
-	buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF);
+	buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
 
 #ifndef DISABLE_ZLIB
 	if (is_compress_recv()) {
 		/* decompress */
-		ses.payload = buf_decompress(ses.decryptreadbuf, len);
+		ses.payload = buf_decompress(ses.readbuf, len);
 	} else 
 #endif
 	{
 		/* copy payload */
 		ses.payload = buf_new(len);
-		memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len);
+		memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
 		buf_incrlen(ses.payload, len);
 	}
 
-	buf_free(ses.decryptreadbuf);
-	ses.decryptreadbuf = NULL;
+	buf_free(ses.readbuf);
+	ses.readbuf = NULL;
 	buf_setpos(ses.payload, 0);
 
 	ses.recvseq++;
@@ -296,49 +292,22 @@
 	TRACE(("leave decrypt_packet"))
 }
 
-/* Checks the mac in hashbuf, for the data in readbuf.
+/* Checks the mac at the end of a decrypted readbuf.
  * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-static int checkmac(buffer* macbuf, buffer* sourcebuf) {
-
-	unsigned int macsize;
-	hmac_state hmac;
-	unsigned char tempbuf[MAX_MAC_LEN];
-	unsigned long bufsize;
-	unsigned int len;
-
-	macsize = ses.keys->recv_algo_mac->hashsize;
-	if (macsize == 0) {
-		return DROPBEAR_SUCCESS;
-	}
+static int checkmac() {
 
-	/* calculate the mac */
-	if (hmac_init(&hmac, 
-				find_hash(ses.keys->recv_algo_mac->hashdesc->name), 
-				ses.keys->recvmackey, 
-				ses.keys->recv_algo_mac->keysize) 
-				!= CRYPT_OK) {
-		dropbear_exit("HMAC error");
-	}
+	unsigned char mac_bytes[MAX_MAC_LEN];
+	unsigned int mac_size, contents_len;
 	
-	/* sequence number */
-	STORE32H(ses.recvseq, tempbuf);
-	if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
-		dropbear_exit("HMAC error");
-	}
+	mac_size = ses.keys->trans.algo_mac->hashsize;
+	contents_len = ses.readbuf->len - mac_size;
 
-	buf_setpos(sourcebuf, 0);
-	len = sourcebuf->len;
-	if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
-		dropbear_exit("HMAC error");
-	}
-
-	bufsize = sizeof(tempbuf);
-	if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
-		dropbear_exit("HMAC error");
-	}
+	buf_setpos(ses.readbuf, 0);
+	make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
 
 	/* compare the hash */
-	if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) {
+	buf_setpos(ses.readbuf, contents_len);
+	if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
 		return DROPBEAR_FAILURE;
 	} else {
 		return DROPBEAR_SUCCESS;
@@ -353,7 +322,7 @@
 	buffer * ret;
 	z_streamp zstream;
 
-	zstream = ses.keys->recv_zstream;
+	zstream = ses.keys->recv.zstream;
 	ret = buf_new(len);
 
 	zstream->avail_in = len;
@@ -468,8 +437,8 @@
 		return;
 	}
 		
-	blocksize = ses.keys->trans_algo_crypt->blocksize;
-	mac_size = ses.keys->trans_algo_mac->hashsize;
+	blocksize = ses.keys->trans.algo_crypt->blocksize;
+	mac_size = ses.keys->trans.algo_mac->hashsize;
 
 	/* Encrypted packet len is payload+5, then worst case is if we are 3 away
 	 * from a blocksize multiple. In which case we need to pad to the
@@ -526,17 +495,17 @@
 	buf_incrlen(writebuf, padlen);
 	genrandom(buf_getptr(writebuf, padlen), padlen);
 
-	make_mac(writebuf, mac_bytes);
+	make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
 
 	/* do the actual encryption, in-place */
 	buf_setpos(writebuf, 0);
 	/* encrypt it in-place*/
 	len = writebuf->len;
-	if (ses.keys->trans_crypt_mode->encrypt(
+	if (ses.keys->trans.crypt_mode->encrypt(
 				buf_getptr(writebuf, len),
 				buf_getwriteptr(writebuf, len),
 				len,
-				&ses.keys->trans_cipher_state) != CRYPT_OK) {
+				&ses.keys->trans.cipher_state) != CRYPT_OK) {
 		dropbear_exit("error encrypting");
 	}
 	buf_incrpos(writebuf, len);
@@ -557,35 +526,36 @@
 
 
 /* Create the packet mac, and append H(seqno|clearbuf) to the output */
-/* output_mac must have ses.keys->trans_algo_mac->hashsize bytes. */
-static void make_mac(buffer * clearwritebuf, unsigned char *output_mac) {
+/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
+static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
+		buffer * clear_buf, unsigned int clear_len, 
+		unsigned char *output_mac) {
 	unsigned char seqbuf[4];
 	unsigned long bufsize;
 	hmac_state hmac;
 
 	TRACE(("enter writemac"))
 
-	if (ses.keys->trans_algo_mac->hashsize > 0) {
+	if (key_state->algo_mac->hashsize > 0) {
 		/* calculate the mac */
 		if (hmac_init(&hmac, 
-					find_hash(ses.keys->trans_algo_mac->hashdesc->name), 
-					ses.keys->transmackey, 
-					ses.keys->trans_algo_mac->keysize) != CRYPT_OK) {
+					key_state->hash_index,
+					key_state->mackey,
+					key_state->algo_mac->keysize) != CRYPT_OK) {
 			dropbear_exit("HMAC error");
 		}
 	
 		/* sequence number */
-		STORE32H(ses.transseq, seqbuf);
+		STORE32H(seqno, seqbuf);
 		if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
 			dropbear_exit("HMAC error");
 		}
 	
 		/* the actual contents */
-		buf_setpos(clearwritebuf, 0);
+		buf_setpos(clear_buf, 0);
 		if (hmac_process(&hmac, 
-					buf_getptr(clearwritebuf, 
-						clearwritebuf->len),
-					clearwritebuf->len) != CRYPT_OK) {
+					buf_getptr(clear_buf, clear_len),
+					clear_len) != CRYPT_OK) {
 			dropbear_exit("HMAC error");
 		}
 	
@@ -609,29 +579,29 @@
 
 	while (1) {
 
-		ses.keys->trans_zstream->avail_in = endpos - src->pos;
-		ses.keys->trans_zstream->next_in = 
-			buf_getptr(src, ses.keys->trans_zstream->avail_in);
+		ses.keys->trans.zstream->avail_in = endpos - src->pos;
+		ses.keys->trans.zstream->next_in = 
+			buf_getptr(src, ses.keys->trans.zstream->avail_in);
 
-		ses.keys->trans_zstream->avail_out = dest->size - dest->pos;
-		ses.keys->trans_zstream->next_out =
-			buf_getwriteptr(dest, ses.keys->trans_zstream->avail_out);
+		ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
+		ses.keys->trans.zstream->next_out =
+			buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
 
-		result = deflate(ses.keys->trans_zstream, Z_SYNC_FLUSH);
+		result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
 
-		buf_setpos(src, endpos - ses.keys->trans_zstream->avail_in);
-		buf_setlen(dest, dest->size - ses.keys->trans_zstream->avail_out);
+		buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
+		buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
 		buf_setpos(dest, dest->len);
 
 		if (result != Z_OK) {
 			dropbear_exit("zlib error");
 		}
 
-		if (ses.keys->trans_zstream->avail_in == 0) {
+		if (ses.keys->trans.zstream->avail_in == 0) {
 			break;
 		}
 
-		dropbear_assert(ses.keys->trans_zstream->avail_out == 0);
+		dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
 
 		/* the buffer has been filled, we must extend. This only happens in
 		 * unusual circumstances where the data grows in size after deflate(),
--- a/packet.h	Sun Mar 01 14:38:25 2009 +0000
+++ b/packet.h	Sun Mar 01 16:15:57 2009 +0000
@@ -44,6 +44,6 @@
 #define PACKET_PADDING_OFF 4
 #define PACKET_PAYLOAD_OFF 5
 
-#define INIT_READBUF 200
+#define INIT_READBUF 128
 
 #endif /* _PACKET_H_ */
--- a/session.h	Sun Mar 01 14:38:25 2009 +0000
+++ b/session.h	Sun Mar 01 16:15:57 2009 +0000
@@ -60,42 +60,36 @@
 void cli_session_cleanup();
 void cleantext(unsigned char* dirtytext);
 
-struct key_context {
-
-	const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */
-	const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */
-	const struct dropbear_cipher_mode *recv_crypt_mode;
-	const struct dropbear_cipher_mode *trans_crypt_mode;
-	const struct dropbear_hash *recv_algo_mac; /* NULL for none */
-	const struct dropbear_hash *trans_algo_mac; /* NULL for none */
-	char algo_kex;
-	char algo_hostkey;
-
-	char recv_algo_comp; /* compression */
-	char trans_algo_comp;
-	int allow_compress; /* whether compression has started (useful in 
-							[email protected] delayed compression case) */
+/* crypto parameters that are stored individually for transmit and receive */
+struct key_context_directional {
+	const struct dropbear_cipher *algo_crypt; /* NULL for none */
+	const struct dropbear_cipher_mode *crypt_mode;
+	const struct dropbear_hash *algo_mac; /* NULL for none */
+	int hash_index; /* lookup for libtomcrypt */
+	char algo_comp; /* compression */
 #ifndef DISABLE_ZLIB
-	z_streamp recv_zstream;
-	z_streamp trans_zstream;
+	z_streamp zstream;
 #endif
-
 	/* actual keys */
 	union {
 		symmetric_CBC cbc;
 #ifdef DROPBEAR_ENABLE_CTR_MODE
 		symmetric_CTR ctr;
 #endif
-	} recv_cipher_state;
-	union {
-		symmetric_CBC cbc;
-#ifdef DROPBEAR_ENABLE_CTR_MODE
-		symmetric_CTR ctr;
-#endif
-	} trans_cipher_state;
-	unsigned char recvmackey[MAX_MAC_KEY];
-	unsigned char transmackey[MAX_MAC_KEY];
+	} cipher_state;
+	unsigned char mackey[MAX_MAC_KEY];
+};
+
+struct key_context {
 
+	struct key_context_directional recv;
+	struct key_context_directional trans;
+
+	char algo_kex;
+	char algo_hostkey;
+
+	int allow_compress; /* whether compression has started (useful in 
+							[email protected] delayed compression case) */
 };
 
 struct packetlist;
@@ -128,8 +122,7 @@
 							 throughout the code, as handlers fill out this
 							 buffer with the packet to send. */
 	struct Queue writequeue; /* A queue of encrypted packets to send */
-	buffer *readbuf; /* Encrypted */
-	buffer *decryptreadbuf; /* Post-decryption */
+	buffer *readbuf; /* From the wire, decrypted in-place */
 	buffer *payload; /* Post-decompression, the actual SSH packet */
 	unsigned int transseq, recvseq; /* Sequence IDs */