From 5e8358ad8127c0ffc2010ddfed3a5258ba24704d Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 20 Sep 2000 15:15:02 +0000 Subject: [PATCH] Fix Blowfish-with-SSH2 combination, and enable user cipher selection for SSH2 git-svn-id: svn://svn.tartarus.org/sgt/putty@606 cda61777-01e9-0310-a592-d414129be87e --- ssh.c | 33 +++++++++++++++--- sshblowf.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 126 insertions(+), 19 deletions(-) diff --git a/ssh.c b/ssh.c index 91b9fd39..ff6e8377 100644 --- a/ssh.c +++ b/ssh.c @@ -142,10 +142,20 @@ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM }; extern struct ssh_cipher ssh_3des; extern struct ssh_cipher ssh_3des_ssh2; extern struct ssh_cipher ssh_des; -extern struct ssh_cipher ssh_blowfish; +extern struct ssh_cipher ssh_blowfish_ssh1; +extern struct ssh_cipher ssh_blowfish_ssh2; -/* for ssh 2; we miss out single-DES because it isn't supported */ -struct ssh_cipher *ciphers[] = { &ssh_3des_ssh2, &ssh_blowfish }; +/* + * Ciphers for SSH2. We miss out single-DES because it isn't + * supported; also 3DES and Blowfish are both done differently from + * SSH1. (3DES uses outer chaining; Blowfish has the opposite + * endianness and different-sized keys.) + * + * The first entry in this array is set up to be whatever the user + * asks for as a cipher. Thereafter there is a fixed preference + * order of fallback ciphers. + */ +struct ssh_cipher *ciphers[] = { NULL, &ssh_blowfish_ssh2, &ssh_3des_ssh2 }; extern struct ssh_kex ssh_diffiehellman; struct ssh_kex *kex_algs[] = { &ssh_diffiehellman }; @@ -1163,7 +1173,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) free(rsabuf); - cipher = cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish : + cipher = cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 : cipher_type == SSH_CIPHER_DES ? &ssh_des : &ssh_3des; cipher->sesskey(session_key); @@ -1780,6 +1790,21 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) crBegin; random_init(); + /* + * Set up the preferred cipher. + */ + if (cfg.cipher == CIPHER_BLOWFISH) { + ciphers[0] = &ssh_blowfish_ssh2; + } else if (cfg.cipher == CIPHER_DES) { + logevent("Single DES not supported in SSH2; using 3DES"); + ciphers[0] = &ssh_3des_ssh2; + } else if (cfg.cipher == CIPHER_3DES) { + ciphers[0] = &ssh_3des_ssh2; + } else { + /* Shouldn't happen, but we do want to initialise to _something_. */ + ciphers[0] = &ssh_3des_ssh2; + } + begin_key_exchange: /* * Construct and send our key exchange packet. diff --git a/sshblowf.c b/sshblowf.c index d6e6731f..dc507ca5 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -25,6 +25,18 @@ typedef struct { (cp)[2] = (value) >> 16; \ (cp)[3] = (value) >> 24; } while (0) +#define GET_32BIT_MSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0] << 24) | \ + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ + ((unsigned long)(unsigned char)(cp)[3])) + +#define PUT_32BIT_MSB_FIRST(cp, value) do { \ + (cp)[0] = (value) >> 24; \ + (cp)[1] = (value) >> 16; \ + (cp)[2] = (value) >> 8; \ + (cp)[3] = (value); } while (0) + /* * The Blowfish init data: hex digits of the fractional part of pi. * (ie pi as a hex fraction is 3.243F6A8885A308D3...) @@ -287,8 +299,8 @@ static void blowfish_decrypt(word32 xL, word32 xR, word32 *output, output[1] = xL; } -static void blowfish_encrypt_cbc(unsigned char *blk, int len, - BlowfishContext *ctx) { +static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len, + BlowfishContext *ctx) { word32 xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); @@ -312,8 +324,8 @@ static void blowfish_encrypt_cbc(unsigned char *blk, int len, ctx->iv0 = iv0; ctx->iv1 = iv1; } -static void blowfish_decrypt_cbc(unsigned char *blk, int len, - BlowfishContext *ctx) { +static void blowfish_lsb_decrypt_cbc(unsigned char *blk, int len, + BlowfishContext *ctx) { word32 xL, xR, out[2], iv0, iv1; assert((len & 7) == 0); @@ -337,6 +349,56 @@ static void blowfish_decrypt_cbc(unsigned char *blk, int len, ctx->iv0 = iv0; ctx->iv1 = iv1; } +static void blowfish_msb_encrypt_cbc(unsigned char *blk, int len, + BlowfishContext *ctx) { + word32 xL, xR, out[2], iv0, iv1; + + assert((len & 7) == 0); + + iv0 = ctx->iv0; iv1 = ctx->iv1; + + while (len > 0) { + xL = GET_32BIT_MSB_FIRST(blk); + xR = GET_32BIT_MSB_FIRST(blk+4); + iv0 ^= xL; + iv1 ^= xR; + blowfish_encrypt(iv0, iv1, out, ctx); + iv0 = out[0]; + iv1 = out[1]; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk+4, iv1); + blk += 8; + len -= 8; + } + + ctx->iv0 = iv0; ctx->iv1 = iv1; +} + +static void blowfish_msb_decrypt_cbc(unsigned char *blk, int len, + BlowfishContext *ctx) { + word32 xL, xR, out[2], iv0, iv1; + + assert((len & 7) == 0); + + iv0 = ctx->iv0; iv1 = ctx->iv1; + + while (len > 0) { + xL = GET_32BIT_MSB_FIRST(blk); + xR = GET_32BIT_MSB_FIRST(blk+4); + blowfish_decrypt(xL, xR, out, ctx); + iv0 ^= out[0]; + iv1 ^= out[1]; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk+4, iv1); + iv0 = xL; + iv1 = xR; + blk += 8; + len -= 8; + } + + ctx->iv0 = iv0; ctx->iv1 = iv1; +} + static void blowfish_setkey(BlowfishContext *ctx, const unsigned char *key, short keybytes) { word32 *S0 = ctx->S0; @@ -406,14 +468,14 @@ static void blowfish_sckey(unsigned char *key) static void blowfish_csiv(unsigned char *key) { - ectx.iv0 = GET_32BIT_LSB_FIRST(key); - ectx.iv1 = GET_32BIT_LSB_FIRST(key+4); + ectx.iv0 = GET_32BIT_MSB_FIRST(key); + ectx.iv1 = GET_32BIT_MSB_FIRST(key+4); } static void blowfish_sciv(unsigned char *key) { - dctx.iv0 = GET_32BIT_LSB_FIRST(key); - dctx.iv1 = GET_32BIT_LSB_FIRST(key+4); + dctx.iv0 = GET_32BIT_MSB_FIRST(key); + dctx.iv1 = GET_32BIT_MSB_FIRST(key+4); } static void blowfish_sesskey(unsigned char *key) @@ -425,22 +487,42 @@ static void blowfish_sesskey(unsigned char *key) logevent("Initialised Blowfish encryption"); } -static void blowfish_encrypt_blk(unsigned char *blk, int len) +static void blowfish_ssh1_encrypt_blk(unsigned char *blk, int len) { - blowfish_encrypt_cbc(blk, len, &ectx); + blowfish_lsb_encrypt_cbc(blk, len, &ectx); } -static void blowfish_decrypt_blk(unsigned char *blk, int len) +static void blowfish_ssh1_decrypt_blk(unsigned char *blk, int len) { - blowfish_decrypt_cbc(blk, len, &dctx); + blowfish_lsb_decrypt_cbc(blk, len, &dctx); } -struct ssh_cipher ssh_blowfish = { +static void blowfish_ssh2_encrypt_blk(unsigned char *blk, int len) +{ + blowfish_msb_encrypt_cbc(blk, len, &ectx); +} + +static void blowfish_ssh2_decrypt_blk(unsigned char *blk, int len) +{ + blowfish_msb_decrypt_cbc(blk, len, &dctx); +} + +struct ssh_cipher ssh_blowfish_ssh1 = { + blowfish_sesskey, + blowfish_csiv, blowfish_cskey, + blowfish_sciv, blowfish_sckey, + blowfish_ssh1_encrypt_blk, + blowfish_ssh1_decrypt_blk, + "blowfish-cbc", + 8 +}; + +struct ssh_cipher ssh_blowfish_ssh2 = { blowfish_sesskey, blowfish_csiv, blowfish_cskey, blowfish_sciv, blowfish_sckey, - blowfish_encrypt_blk, - blowfish_decrypt_blk, + blowfish_ssh2_encrypt_blk, + blowfish_ssh2_decrypt_blk, "blowfish-cbc", 8 }; -- 2.11.0