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 };
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);
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.
(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...)
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);
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);
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;
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)
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
};