- markus@cvs.openbsd.org 2002/02/14 23:41:01
     [authfile.c cipher.c cipher.h kex.c kex.h packet.c]
     hide some more implementation details of cipher.[ch] and prepares for move
     to EVP, ok deraadt@
diff --git a/ChangeLog b/ChangeLog
index 4ca8825..2716f78 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -13,6 +13,10 @@
      [channels.h session.c ssh.c]
      increase the SSH v2 window size to 4 packets. comsumes a little
      bit more memory for slow receivers but increases througput.
+   - markus@cvs.openbsd.org 2002/02/14 23:41:01
+     [authfile.c cipher.c cipher.h kex.c kex.h packet.c]
+     hide some more implementation details of cipher.[ch] and prepares for move
+     to EVP, ok deraadt@
 
 20020218
  - (tim) newer config.guess from ftp://ftp.gnu.org/gnu/config/config.guess
@@ -7610,4 +7614,4 @@
  - Wrote replacements for strlcpy and mkdtemp
  - Released 1.0pre1
 
-$Id: ChangeLog,v 1.1857 2002/02/19 04:20:57 djm Exp $
+$Id: ChangeLog,v 1.1858 2002/02/19 04:21:23 djm Exp $
diff --git a/authfile.c b/authfile.c
index 69e0da0..e35714e 100644
--- a/authfile.c
+++ b/authfile.c
@@ -36,7 +36,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: authfile.c,v 1.45 2001/12/29 21:56:01 stevesk Exp $");
+RCSID("$OpenBSD: authfile.c,v 1.46 2002/02/14 23:41:01 markus Exp $");
 
 #include <openssl/err.h>
 #include <openssl/evp.h>
@@ -69,7 +69,7 @@
 {
 	Buffer buffer, encrypted;
 	u_char buf[100], *cp;
-	int fd, i;
+	int fd, i, cipher_num;
 	CipherContext ciphercontext;
 	Cipher *cipher;
 	u_int32_t rand;
@@ -78,11 +78,9 @@
 	 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
 	 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
 	 */
-	if (strcmp(passphrase, "") == 0)
-		cipher = cipher_by_number(SSH_CIPHER_NONE);
-	else
-		cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
-	if (cipher == NULL)
+	cipher_num = (strcmp(passphrase, "") == 0) ?
+	    SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
+	if ((cipher = cipher_by_number(cipher_num)) == NULL)
 		fatal("save_private_key_rsa: bad cipher");
 
 	/* This buffer is used to built the secret part of the private key. */
@@ -119,7 +117,7 @@
 	buffer_put_char(&encrypted, 0);
 
 	/* Store cipher type. */
-	buffer_put_char(&encrypted, cipher->number);
+	buffer_put_char(&encrypted, cipher_num);
 	buffer_put_int(&encrypted, 0);	/* For future extension */
 
 	/* Store public key.  This will be in plain text. */
@@ -131,9 +129,11 @@
 	/* Allocate space for the private part of the key in the buffer. */
 	cp = buffer_append_space(&encrypted, buffer_len(&buffer));
 
-	cipher_set_key_string(&ciphercontext, cipher, passphrase);
-	cipher_encrypt(&ciphercontext, cp,
+	cipher_set_key_string(&ciphercontext, cipher, passphrase,
+	    CIPHER_ENCRYPT);
+	cipher_crypt(&ciphercontext, cp,
 	    buffer_ptr(&buffer), buffer_len(&buffer));
+	cipher_cleanup(&ciphercontext);
 	memset(&ciphercontext, 0, sizeof(ciphercontext));
 
 	/* Destroy temporary data. */
@@ -380,9 +380,11 @@
 	cp = buffer_append_space(&decrypted, buffer_len(&buffer));
 
 	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
-	cipher_set_key_string(&ciphercontext, cipher, passphrase);
-	cipher_decrypt(&ciphercontext, cp,
+	cipher_set_key_string(&ciphercontext, cipher, passphrase,
+	    CIPHER_DECRYPT);
+	cipher_crypt(&ciphercontext, cp,
 	    buffer_ptr(&buffer), buffer_len(&buffer));
+	cipher_cleanup(&ciphercontext);
 	memset(&ciphercontext, 0, sizeof(ciphercontext));
 	buffer_free(&buffer);
 
diff --git a/cipher.c b/cipher.c
index 58b0e8a..c31696c 100644
--- a/cipher.c
+++ b/cipher.c
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: cipher.c,v 1.50 2002/01/21 22:30:12 markus Exp $");
+RCSID("$OpenBSD: cipher.c,v 1.51 2002/02/14 23:41:01 markus Exp $");
 
 #include "xmalloc.h"
 #include "log.h"
@@ -43,6 +43,17 @@
 
 #include <openssl/md5.h>
 
+struct Cipher {
+	char	*name;
+	int	number;		/* for ssh1 only */
+	u_int	block_size;
+	u_int	key_len;
+	void	(*setkey)(CipherContext *, const u_char *, u_int);
+	void	(*setiv)(CipherContext *, const u_char *, u_int);
+	void	(*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
+	void	(*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
+};
+
 /* no encryption */
 static void
 none_setkey(CipherContext *cc, const u_char *key, u_int keylen)
@@ -397,6 +408,18 @@
 
 /*--*/
 
+u_int   
+cipher_blocksize(Cipher *c)
+{
+	return (c->block_size);
+}
+
+u_int   
+cipher_keylen(Cipher *c)
+{
+	return (c->key_len);
+}
+
 u_int
 cipher_mask_ssh1(int client)
 {
@@ -479,8 +502,8 @@
 }
 
 void
-cipher_init(CipherContext *cc, Cipher *cipher,
-    const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)
+cipher_init(CipherContext *cc, Cipher *cipher, const u_char *key,
+     u_int keylen, const u_char *iv, u_int ivlen, int encrypt)
 {
 	if (keylen < cipher->key_len)
 		fatal("cipher_init: key length %d is insufficient for %s.",
@@ -489,24 +512,26 @@
 		fatal("cipher_init: iv length %d is insufficient for %s.",
 		    ivlen, cipher->name);
 	cc->cipher = cipher;
+	cc->encrypt = (encrypt == CIPHER_ENCRYPT);
 	cipher->setkey(cc, key, keylen);
 	cipher->setiv(cc, iv, ivlen);
 }
 
 void
-cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
 {
 	if (len % cc->cipher->block_size)
 		fatal("cipher_encrypt: bad plaintext length %d", len);
-	cc->cipher->encrypt(cc, dest, src, len);
+	if (cc->encrypt)
+		cc->cipher->encrypt(cc, dest, src, len);
+	else
+		cc->cipher->decrypt(cc, dest, src, len);
 }
 
 void
-cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
+cipher_cleanup(CipherContext *cc)
 {
-	if (len % cc->cipher->block_size)
-		fatal("cipher_decrypt: bad ciphertext length %d", len);
-	cc->cipher->decrypt(cc, dest, src, len);
+	memset(cc, 0, sizeof(*cc));
 }
 
 /*
@@ -516,7 +541,7 @@
 
 void
 cipher_set_key_string(CipherContext *cc, Cipher *cipher,
-    const char *passphrase)
+    const char *passphrase, int encrypt)
 {
 	MD5_CTX md;
 	u_char digest[16];
@@ -525,7 +550,7 @@
 	MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
 	MD5_Final(digest, &md);
 
-	cipher_init(cc, cipher, digest, 16, NULL, 0);
+	cipher_init(cc, cipher, digest, 16, NULL, 0, encrypt);
 
 	memset(digest, 0, sizeof(digest));
 	memset(&md, 0, sizeof(md));
diff --git a/cipher.h b/cipher.h
index 4533f5e..0c412b4 100644
--- a/cipher.h
+++ b/cipher.h
@@ -32,7 +32,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* RCSID("$OpenBSD: cipher.h,v 1.29 2001/08/23 11:31:59 markus Exp $"); */
+/* RCSID("$OpenBSD: cipher.h,v 1.30 2002/02/14 23:41:01 markus Exp $"); */
 
 #ifndef CIPHER_H
 #define CIPHER_H
@@ -59,9 +59,13 @@
 #define SSH_CIPHER_RESERVED	7
 #define SSH_CIPHER_MAX		31
 
+#define CIPHER_ENCRYPT		1
+#define CIPHER_DECRYPT		0
+
 typedef struct Cipher Cipher;
 typedef struct CipherContext CipherContext;
 
+struct Cipher;
 struct CipherContext {
 	union {
 		struct {
@@ -91,18 +95,10 @@
 		} rijndael;
 		RC4_KEY rc4;
 	}       u;
+	int	plaintext;
+	int	encrypt;
 	Cipher *cipher;
 };
-struct Cipher {
-	char	*name;
-	int	number;		/* for ssh1 only */
-	u_int	block_size;
-	u_int	key_len;
-	void	(*setkey)(CipherContext *, const u_char *, u_int);
-	void	(*setiv)(CipherContext *, const u_char *, u_int);
-	void	(*encrypt)(CipherContext *, u_char *, const u_char *, u_int);
-	void	(*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
-};
 
 u_int	 cipher_mask_ssh1(int);
 Cipher	*cipher_by_name(const char *);
@@ -111,9 +107,10 @@
 char	*cipher_name(int);
 int	 ciphers_valid(const char *);
 void	 cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
-    const u_char *, u_int);
-void	 cipher_encrypt(CipherContext *, u_char *, const u_char *, u_int);
-void	 cipher_decrypt(CipherContext *, u_char *, const u_char *, u_int);
-void	 cipher_set_key_string(CipherContext *, Cipher *, const char *);
-
+    const u_char *, u_int, int);
+void	 cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
+void	 cipher_cleanup(CipherContext *);
+void	 cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
+u_int	 cipher_blocksize(Cipher *);
+u_int	 cipher_keylen(Cipher *);
 #endif				/* CIPHER_H */
diff --git a/kex.c b/kex.c
index 02c9780..e9f944b 100644
--- a/kex.c
+++ b/kex.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: kex.c,v 1.44 2002/02/11 16:10:15 markus Exp $");
+RCSID("$OpenBSD: kex.c,v 1.45 2002/02/14 23:41:01 markus Exp $");
 
 #include <openssl/crypto.h>
 
@@ -232,13 +232,14 @@
 	char *name = match_list(client, server, NULL);
 	if (name == NULL)
 		fatal("no matching cipher found: client %s server %s", client, server);
-	enc->cipher = cipher_by_name(name);
-	if (enc->cipher == NULL)
+	if ((enc->cipher = cipher_by_name(name)) == NULL)
 		fatal("matching cipher is not supported: %s", name);
 	enc->name = name;
 	enc->enabled = 0;
 	enc->iv = NULL;
 	enc->key = NULL;
+	enc->key_len = cipher_keylen(enc->cipher);
+	enc->block_size = cipher_blocksize(enc->cipher);
 }
 static void
 choose_mac(Mac *mac, char *client, char *server)
@@ -341,10 +342,10 @@
 	need = 0;
 	for (mode = 0; mode < MODE_MAX; mode++) {
 		newkeys = kex->newkeys[mode];
-		if (need < newkeys->enc.cipher->key_len)
-			need = newkeys->enc.cipher->key_len;
-		if (need < newkeys->enc.cipher->block_size)
-			need = newkeys->enc.cipher->block_size;
+		if (need < newkeys->enc.key_len)
+			need = newkeys->enc.key_len;
+		if (need < newkeys->enc.block_size)
+			need = newkeys->enc.block_size;
 		if (need < newkeys->mac.key_len)
 			need = newkeys->mac.key_len;
 	}
diff --git a/kex.h b/kex.h
index 7bd6bc2..755bf33 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: kex.h,v 1.28 2001/12/28 15:06:00 markus Exp $	*/
+/*	$OpenBSD: kex.h,v 1.29 2002/02/14 23:41:01 markus Exp $	*/
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -71,6 +71,8 @@
 	char	*name;
 	Cipher	*cipher;
 	int	enabled;
+	u_int	key_len;
+	u_int	block_size;
 	u_char	*key;
 	u_char	*iv;
 };
diff --git a/packet.c b/packet.c
index e334c4b..794659b 100644
--- a/packet.c
+++ b/packet.c
@@ -37,7 +37,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: packet.c,v 1.87 2002/01/24 21:13:23 stevesk Exp $");
+RCSID("$OpenBSD: packet.c,v 1.88 2002/02/14 23:41:01 markus Exp $");
 
 #include "xmalloc.h"
 #include "buffer.h"
@@ -131,8 +131,8 @@
 		fatal("packet_set_connection: cannot load cipher 'none'");
 	connection_in = fd_in;
 	connection_out = fd_out;
-	cipher_init(&send_context, none, "", 0, NULL, 0);
-	cipher_init(&receive_context, none, "", 0, NULL, 0);
+	cipher_init(&send_context, none, "", 0, NULL, 0, CIPHER_ENCRYPT);
+	cipher_init(&receive_context, none, "", 0, NULL, 0, CIPHER_DECRYPT);
 	newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
 	if (!initialized) {
 		initialized = 1;
@@ -241,6 +241,8 @@
 		buffer_free(&compression_buffer);
 		buffer_compress_uninit();
 	}
+	cipher_cleanup(&send_context);
+	cipher_cleanup(&receive_context);
 }
 
 /* Sets remote side protocol flags. */
@@ -298,8 +300,8 @@
 		fatal("packet_set_encryption_key: unknown cipher number %d", number);
 	if (keylen < 20)
 		fatal("packet_set_encryption_key: keylen too small: %d", keylen);
-	cipher_init(&receive_context, cipher, key, keylen, NULL, 0);
-	cipher_init(&send_context, cipher, key, keylen, NULL, 0);
+	cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT);
+	cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT);
 }
 
 /* Start constructing a packet to send. */
@@ -388,7 +390,7 @@
 
 	/* Insert padding. Initialized to zero in packet_start1() */
 	padding = 8 - len % 8;
-	if (send_context.cipher->number != SSH_CIPHER_NONE) {
+	if (!send_context.plaintext) {
 		cp = buffer_ptr(&outgoing_packet);
 		for (i = 0; i < padding; i++) {
 			if (i % 4 == 0)
@@ -414,7 +416,7 @@
 	PUT_32BIT(buf, len);
 	buffer_append(&output, buf, 4);
 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
-	cipher_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
+	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
 	    buffer_len(&outgoing_packet));
 
 #ifdef PACKET_DEBUG
@@ -438,14 +440,20 @@
 	Mac *mac;
 	Comp *comp;
 	CipherContext *cc;
+	int encrypt;
 
 	debug("newkeys: mode %d", mode);
 
-	cc = (mode == MODE_OUT) ? &send_context : &receive_context;
+	if (mode == MODE_OUT) {
+		cc = &send_context;
+		encrypt = CIPHER_ENCRYPT;
+	} else {
+		cc = &receive_context;
+		encrypt = CIPHER_DECRYPT;
+	}
 	if (newkeys[mode] != NULL) {
 		debug("newkeys: rekeying");
-		/* todo: free old keys, reset compression/cipher-ctxt; */
-		memset(cc, 0, sizeof(*cc));
+		cipher_cleanup(cc);
 		enc  = &newkeys[mode]->enc;
 		mac  = &newkeys[mode]->mac;
 		comp = &newkeys[mode]->comp;
@@ -467,10 +475,10 @@
 	if (mac->md != NULL)
 		mac->enabled = 1;
 	DBG(debug("cipher_init_context: %d", mode));
-	cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len,
-	    enc->iv, enc->cipher->block_size);
-	memset(enc->iv,  0, enc->cipher->block_size);
-	memset(enc->key, 0, enc->cipher->key_len);
+	cipher_init(cc, enc->cipher, enc->key, enc->key_len,
+	    enc->iv, enc->block_size, encrypt);
+	memset(enc->iv,  0, enc->block_size);
+	memset(enc->key, 0, enc->key_len);
 	if (comp->type != 0 && comp->enabled == 0) {
 		packet_init_compression();
 		if (mode == MODE_OUT)
@@ -504,7 +512,7 @@
 		mac  = &newkeys[MODE_OUT]->mac;
 		comp = &newkeys[MODE_OUT]->comp;
 	}
-	block_size = enc ? enc->cipher->block_size : 8;
+	block_size = enc ? enc->block_size : 8;
 
 	ucp = buffer_ptr(&outgoing_packet);
 	type = ucp[5];
@@ -548,7 +556,7 @@
 		extra_pad = 0;
 	}
 	cp = buffer_append_space(&outgoing_packet, padlen);
-	if (enc && enc->cipher->number != SSH_CIPHER_NONE) {
+	if (enc && !send_context.plaintext) {
 		/* random padding */
 		for (i = 0; i < padlen; i++) {
 			if (i % 4 == 0)
@@ -576,7 +584,7 @@
 	}
 	/* encrypt packet and append to output buffer. */
 	cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
-	cipher_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
+	cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet),
 	    buffer_len(&outgoing_packet));
 	/* append unencrypted MAC */
 	if (mac && mac->enabled)
@@ -729,14 +737,14 @@
 	 * (C)1998 CORE-SDI, Buenos Aires Argentina
 	 * Ariel Futoransky(futo@core-sdi.com)
 	 */
-	if (receive_context.cipher->number != SSH_CIPHER_NONE &&
+	if (!receive_context.plaintext &&
 	    detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED)
 		packet_disconnect("crc32 compensation attack: network attack detected");
 
 	/* Decrypt data to incoming_packet. */
 	buffer_clear(&incoming_packet);
 	cp = buffer_append_space(&incoming_packet, padded_len);
-	cipher_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len);
+	cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len);
 
 	buffer_consume(&input, padded_len);
 
@@ -793,7 +801,7 @@
 		comp = &newkeys[MODE_IN]->comp;
 	}
 	maclen = mac && mac->enabled ? mac->mac_len : 0;
-	block_size = enc ? enc->cipher->block_size : 8;
+	block_size = enc ? enc->block_size : 8;
 
 	if (packet_length == 0) {
 		/*
@@ -804,7 +812,7 @@
 			return SSH_MSG_NONE;
 		buffer_clear(&incoming_packet);
 		cp = buffer_append_space(&incoming_packet, block_size);
-		cipher_decrypt(&receive_context, cp, buffer_ptr(&input),
+		cipher_crypt(&receive_context, cp, buffer_ptr(&input),
 		    block_size);
 		ucp = buffer_ptr(&incoming_packet);
 		packet_length = GET_32BIT(ucp);
@@ -833,7 +841,7 @@
 	buffer_dump(&input);
 #endif
 	cp = buffer_append_space(&incoming_packet, need);
-	cipher_decrypt(&receive_context, cp, buffer_ptr(&input), need);
+	cipher_crypt(&receive_context, cp, buffer_ptr(&input), need);
 	buffer_consume(&input, need);
 	/*
 	 * compute MAC over seqnr and packet,