From 0a3f1d48f7f8779690073685f057bc5705d61006 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 2 Mar 2001 13:55:23 +0000 Subject: [PATCH] Support for selecting AES from the GUI. In the process, I've had to introduce another layer of abstraction in SSH2 ciphers, such that a single `logical cipher' (as desired by a user) can equate to more than one `physical cipher'. This is because AES comes in several key lengths (PuTTY will pick the highest supported by the remote end) and several different SSH2-protocol-level names (aes*-cbc, rijndael*-cbc, and an unofficial one rijndael-cbc@lysator.liu.se). git-svn-id: svn://svn.tartarus.org/sgt/putty@967 cda61777-01e9-0310-a592-d414129be87e --- putty.h | 2 +- settings.c | 9 ++++-- ssh.c | 96 ++++++++++++++++++++++++++++++++++++-------------------------- ssh.h | 11 +++++++ sshaes.c | 77 ++++++++++++++++++++++++++++++------------------- sshblowf.c | 17 +++++++---- sshdes.c | 20 +++++++------ windlg.c | 13 +++++++-- 8 files changed, 156 insertions(+), 89 deletions(-) diff --git a/putty.h b/putty.h index 7bb97d96..cf917ab5 100644 --- a/putty.h +++ b/putty.h @@ -171,7 +171,7 @@ typedef struct { int nopty; int compression; int agentfwd; - enum { CIPHER_3DES, CIPHER_BLOWFISH, CIPHER_DES } cipher; + enum { CIPHER_3DES, CIPHER_BLOWFISH, CIPHER_DES, CIPHER_AES } cipher; char keyfile[FILENAME_MAX]; int sshprot; /* use v1 or v2 when both available */ int buggymac; /* MAC bug commmercial <=v2.3.x SSH2 */ diff --git a/settings.c b/settings.c index 01087eeb..ad062dd5 100644 --- a/settings.c +++ b/settings.c @@ -73,8 +73,11 @@ void save_settings (char *section, int do_host, Config *cfg) { write_setting_i (sesskey, "Compression", cfg->compression); write_setting_i (sesskey, "AgentFwd", cfg->agentfwd); write_setting_s (sesskey, "RemoteCmd", cfg->remote_cmd); - write_setting_s (sesskey, "Cipher", cfg->cipher == CIPHER_BLOWFISH ? "blowfish" : - cfg->cipher == CIPHER_DES ? "des" : "3des"); + write_setting_s (sesskey, "Cipher", + cfg->cipher == CIPHER_BLOWFISH ? "blowfish" : + cfg->cipher == CIPHER_DES ? "des" : + cfg->cipher == CIPHER_AES ? "aes" : + "3des"); write_setting_i (sesskey, "AuthTIS", cfg->try_tis_auth); write_setting_i (sesskey, "SshProt", cfg->sshprot); write_setting_i (sesskey, "BuggyMAC", cfg->buggymac); @@ -218,6 +221,8 @@ void load_settings (char *section, int do_host, Config *cfg) { cfg->cipher = CIPHER_BLOWFISH; else if (!strcmp(cipher, "des")) cfg->cipher = CIPHER_DES; + else if (!strcmp(cipher, "aes")) + cfg->cipher = CIPHER_AES; else cfg->cipher = CIPHER_3DES; } diff --git a/ssh.c b/ssh.c index c239eb22..5996fd39 100644 --- a/ssh.c +++ b/ssh.c @@ -165,13 +165,11 @@ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM }; #define crWaitUntilV(c) do { crReturnV; } while (!(c)) extern const struct ssh_cipher ssh_3des; -extern const struct ssh_cipher ssh_3des_ssh2; +extern const struct ssh2_ciphers ssh2_3des; extern const struct ssh_cipher ssh_des; -extern const struct ssh_cipher ssh_aes128_ssh2; -extern const struct ssh_cipher ssh_aes192_ssh2; -extern const struct ssh_cipher ssh_aes256_ssh2; +extern const struct ssh2_ciphers ssh2_aes; extern const struct ssh_cipher ssh_blowfish_ssh1; -extern const struct ssh_cipher ssh_blowfish_ssh2; +extern const struct ssh2_ciphers ssh2_blowfish; extern char *x11_init (Socket *, char *, void *); extern void x11_close (Socket); @@ -184,12 +182,10 @@ extern void x11_invent_auth(char *, int, char *, int); * SSH1. (3DES uses outer chaining; Blowfish has the opposite * endianness and different-sized keys.) */ -const static struct ssh_cipher *ciphers[] = { - &ssh_aes256_ssh2, - &ssh_aes192_ssh2, - &ssh_aes128_ssh2, - &ssh_blowfish_ssh2, - &ssh_3des_ssh2 +const static struct ssh2_ciphers *ciphers[] = { + &ssh2_aes, + &ssh2_blowfish, + &ssh2_3des, }; extern const struct ssh_kex ssh_diffiehellman; @@ -278,8 +274,8 @@ static int ssh1_compressing; static int ssh_agentfwd_enabled; static int ssh_X11_fwd_enabled; static const struct ssh_cipher *cipher = NULL; -static const struct ssh_cipher *cscipher = NULL; -static const struct ssh_cipher *sccipher = NULL; +static const struct ssh2_cipher *cscipher = NULL; +static const struct ssh2_cipher *sccipher = NULL; static const struct ssh_mac *csmac = NULL; static const struct ssh_mac *scmac = NULL; static const struct ssh_compress *cscomp = NULL; @@ -1396,9 +1392,15 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) logevent("Encrypted session key"); - cipher_type = cfg.cipher == CIPHER_BLOWFISH ? SSH_CIPHER_BLOWFISH : - cfg.cipher == CIPHER_DES ? SSH_CIPHER_DES : - SSH_CIPHER_3DES; + switch (cfg.cipher) { + case CIPHER_BLOWFISH: cipher_type = SSH_CIPHER_BLOWFISH; break; + case CIPHER_DES: cipher_type = SSH_CIPHER_DES; break; + case CIPHER_3DES: cipher_type = SSH_CIPHER_3DES; break; + case CIPHER_AES: + c_write("AES not supported in SSH1, falling back to 3DES\r\n", 49); + cipher_type = SSH_CIPHER_3DES; + break; + } if ((supported_ciphers_mask & (1 << cipher_type)) == 0) { c_write("Selected cipher not supported, falling back to 3DES\r\n", 53); cipher_type = SSH_CIPHER_3DES; @@ -2181,14 +2183,14 @@ static void ssh2_mkkey(Bignum K, char *H, char *sessid, char chr, char *keyspace */ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) { - static int i, len, nbits; + static int i, j, len, nbits; static char *str; static Bignum p, g, e, f, K; static int kex_init_value, kex_reply_value; static const struct ssh_mac **maclist; static int nmacs; - static const struct ssh_cipher *cscipher_tobe = NULL; - static const struct ssh_cipher *sccipher_tobe = NULL; + static const struct ssh2_cipher *cscipher_tobe = NULL; + static const struct ssh2_cipher *sccipher_tobe = NULL; static const struct ssh_mac *csmac_tobe = NULL; static const struct ssh_mac *scmac_tobe = NULL; static const struct ssh_compress *cscomp_tobe = NULL; @@ -2199,7 +2201,7 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) static unsigned char exchange_hash[20]; static unsigned char first_exchange_hash[20]; static unsigned char keyspace[40]; - static const struct ssh_cipher *preferred_cipher; + static const struct ssh2_ciphers *preferred_cipher; static const struct ssh_compress *preferred_comp; static int first_kex; @@ -2211,15 +2213,17 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) * Set up the preferred cipher and compression. */ if (cfg.cipher == CIPHER_BLOWFISH) { - preferred_cipher = &ssh_blowfish_ssh2; + preferred_cipher = &ssh2_blowfish; } else if (cfg.cipher == CIPHER_DES) { logevent("Single DES not supported in SSH2; using 3DES"); - preferred_cipher = &ssh_3des_ssh2; + preferred_cipher = &ssh2_3des; } else if (cfg.cipher == CIPHER_3DES) { - preferred_cipher = &ssh_3des_ssh2; + preferred_cipher = &ssh2_3des; + } else if (cfg.cipher == CIPHER_AES) { + preferred_cipher = &ssh2_aes; } else { /* Shouldn't happen, but we do want to initialise to _something_. */ - preferred_cipher = &ssh_3des_ssh2; + preferred_cipher = &ssh2_3des; } if (cfg.compression) preferred_comp = &ssh_zlib; @@ -2258,18 +2262,22 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) /* List client->server encryption algorithms. */ ssh2_pkt_addstring_start(); for (i = 0; i < lenof(ciphers)+1; i++) { - const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1]; - ssh2_pkt_addstring_str(c->name); - if (i < lenof(ciphers)) - ssh2_pkt_addstring_str(","); + const struct ssh2_ciphers *c = i==0 ? preferred_cipher : ciphers[i-1]; + for (j = 0; j < c->nciphers; j++) { + ssh2_pkt_addstring_str(c->list[j]->name); + if (i < lenof(ciphers) || j < c->nciphers-1) + ssh2_pkt_addstring_str(","); + } } /* List server->client encryption algorithms. */ ssh2_pkt_addstring_start(); for (i = 0; i < lenof(ciphers)+1; i++) { - const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1]; - ssh2_pkt_addstring_str(c->name); - if (i < lenof(ciphers)) - ssh2_pkt_addstring_str(","); + const struct ssh2_ciphers *c = i==0 ? preferred_cipher : ciphers[i-1]; + for (j = 0; j < c->nciphers; j++) { + ssh2_pkt_addstring_str(c->list[j]->name); + if (i < lenof(ciphers) || j < c->nciphers-1) + ssh2_pkt_addstring_str(","); + } } /* List client->server MAC algorithms. */ ssh2_pkt_addstring_start(); @@ -2345,19 +2353,27 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) } ssh2_pkt_getstring(&str, &len); /* client->server cipher */ for (i = 0; i < lenof(ciphers)+1; i++) { - const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1]; - if (in_commasep_string(c->name, str, len)) { - cscipher_tobe = c; - break; + const struct ssh2_ciphers *c = i==0 ? preferred_cipher : ciphers[i-1]; + for (j = 0; j < c->nciphers; j++) { + if (in_commasep_string(c->list[j]->name, str, len)) { + cscipher_tobe = c->list[j]; + break; + } } + if (cscipher_tobe) + break; } ssh2_pkt_getstring(&str, &len); /* server->client cipher */ for (i = 0; i < lenof(ciphers)+1; i++) { - const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1]; - if (in_commasep_string(c->name, str, len)) { - sccipher_tobe = c; - break; + const struct ssh2_ciphers *c = i==0 ? preferred_cipher : ciphers[i-1]; + for (j = 0; j < c->nciphers; j++) { + if (in_commasep_string(c->list[j]->name, str, len)) { + sccipher_tobe = c->list[j]; + break; + } } + if (sccipher_tobe) + break; } ssh2_pkt_getstring(&str, &len); /* client->server mac */ for (i = 0; i < nmacs; i++) { diff --git a/ssh.h b/ssh.h index 555fe61c..aafee4e3 100644 --- a/ssh.h +++ b/ssh.h @@ -95,6 +95,12 @@ void SHA_Simple(void *p, int len, unsigned char *output); struct ssh_cipher { void (*sesskey)(unsigned char *key); /* for ssh 1 */ + void (*encrypt)(unsigned char *blk, int len); + void (*decrypt)(unsigned char *blk, int len); + int blksize; +}; + +struct ssh2_cipher { void (*setcsiv)(unsigned char *key); /* for ssh 2 */ void (*setcskey)(unsigned char *key); /* for ssh 2 */ void (*setsciv)(unsigned char *key); /* for ssh 2 */ @@ -106,6 +112,11 @@ struct ssh_cipher { int keylen; }; +struct ssh2_ciphers { + int nciphers; + struct ssh2_cipher **list; +}; + struct ssh_mac { void (*setcskey)(unsigned char *key); void (*setsckey)(unsigned char *key); diff --git a/sshaes.c b/sshaes.c index d6a27663..0e7ddc1c 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1023,8 +1023,7 @@ static void aes_ssh2_decrypt_blk(unsigned char *blk, int len) { aes_decrypt_cbc(blk, len, &scctx); } -struct ssh_cipher ssh_aes128_ssh2 = { - NULL, +static struct ssh2_cipher ssh_aes128 = { aes_csiv, aes128_cskey, aes_sciv, aes128_sckey, aes_ssh2_encrypt_blk, @@ -1033,8 +1032,7 @@ struct ssh_cipher ssh_aes128_ssh2 = { 16, 128 }; -struct ssh_cipher ssh_aes192_ssh2 = { - NULL, +static struct ssh2_cipher ssh_aes192 = { aes_csiv, aes192_cskey, aes_sciv, aes192_sckey, aes_ssh2_encrypt_blk, @@ -1043,8 +1041,7 @@ struct ssh_cipher ssh_aes192_ssh2 = { 16, 192 }; -struct ssh_cipher ssh_aes256_ssh2 = { - NULL, +static struct ssh2_cipher ssh_aes256 = { aes_csiv, aes256_cskey, aes_sciv, aes256_sckey, aes_ssh2_encrypt_blk, @@ -1053,31 +1050,53 @@ struct ssh_cipher ssh_aes256_ssh2 = { 16, 256 }; -#ifdef TESTMODE +static struct ssh2_cipher ssh_rijndael128 = { + aes_csiv, aes128_cskey, + aes_sciv, aes128_sckey, + aes_ssh2_encrypt_blk, + aes_ssh2_decrypt_blk, + "rijndael128-cbc", + 16, 128 +}; -#include +static struct ssh2_cipher ssh_rijndael192 = { + aes_csiv, aes192_cskey, + aes_sciv, aes192_sckey, + aes_ssh2_encrypt_blk, + aes_ssh2_decrypt_blk, + "rijndael192-cbc", + 16, 192 +}; -int main(void) { - AESContext c; - static unsigned char key[32] = {}; - word32 block[32]; - int i, j, k; +static struct ssh2_cipher ssh_rijndael256 = { + aes_csiv, aes256_cskey, + aes_sciv, aes256_sckey, + aes_ssh2_encrypt_blk, + aes_ssh2_decrypt_blk, + "rijndael256-cbc", + 16, 256 +}; - for (i = 16; i <= 32; i += 8) { - for (j = 16; j <= 32; j += 8) { - printf("b%d, k%d: ", i, j); - fflush(stdout); - aes_setup(&c, i, key, j); - memset(block, 0, sizeof(block)); - aes_encrypt(&c, block); - aes_decrypt(&c, block); - for (k = 0; k < i/4; k++) - printf("%08x ", block[k]); - printf("\n"); - } - } +static struct ssh2_cipher ssh_rijndael_lysator = { + aes_csiv, aes256_cskey, + aes_sciv, aes256_sckey, + aes_ssh2_encrypt_blk, + aes_ssh2_decrypt_blk, + "rijndael-cbc@lysator.liu.se", + 16, 256 +}; - return 0; -} +static struct ssh2_cipher *aes_list[] = { + &ssh_aes256, + &ssh_rijndael256, + &ssh_rijndael_lysator, + &ssh_aes192, + &ssh_rijndael192, + &ssh_aes128, + &ssh_rijndael128, +}; -#endif +struct ssh2_ciphers ssh2_aes = { + sizeof(aes_list) / sizeof(*aes_list), + aes_list +}; diff --git a/sshblowf.c b/sshblowf.c index 1d92d30c..99d83737 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -509,16 +509,12 @@ static void blowfish_ssh2_decrypt_blk(unsigned char *blk, int len) 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, 256 + 8 }; -struct ssh_cipher ssh_blowfish_ssh2 = { - blowfish_sesskey, +static struct ssh2_cipher ssh_blowfish_ssh2 = { blowfish_csiv, blowfish_cskey, blowfish_sciv, blowfish_sckey, blowfish_ssh2_encrypt_blk, @@ -526,3 +522,12 @@ struct ssh_cipher ssh_blowfish_ssh2 = { "blowfish-cbc", 8, 128 }; + +static struct ssh2_cipher *blowfish_list[] = { + &ssh_blowfish_ssh2 +}; + +struct ssh2_ciphers ssh2_blowfish = { + sizeof(blowfish_list) / sizeof(*blowfish_list), + blowfish_list +}; diff --git a/sshdes.c b/sshdes.c index 0b47aab6..491c9067 100644 --- a/sshdes.c +++ b/sshdes.c @@ -790,8 +790,7 @@ void des3_encrypt_pubkey(unsigned char *key, des_3cbc_encrypt(blk, blk, len, ourkeys); } -struct ssh_cipher ssh_3des_ssh2 = { - NULL, +static struct ssh2_cipher ssh_3des_ssh2 = { des3_csiv, des3_cskey, des3_sciv, des3_sckey, des3_ssh2_encrypt_blk, @@ -800,13 +799,20 @@ struct ssh_cipher ssh_3des_ssh2 = { 8, 168 }; +static struct ssh2_cipher *des3_list[] = { + &ssh_3des_ssh2 +}; + +struct ssh2_ciphers ssh2_3des = { + sizeof(des3_list) / sizeof(*des3_list), + des3_list +}; + struct ssh_cipher ssh_3des = { des3_sesskey, - NULL, NULL, NULL, NULL, des3_encrypt_blk, des3_decrypt_blk, - "3des-cbc", - 8, 168 + 8 }; static void des_sesskey(unsigned char *key) { @@ -825,9 +831,7 @@ static void des_decrypt_blk(unsigned char *blk, int len) { struct ssh_cipher ssh_des = { des_sesskey, - NULL, NULL, NULL, NULL, /* SSH 2 bits - unused */ des_encrypt_blk, des_decrypt_blk, - "des-cbc", /* should never be used - not a valid cipher in ssh2 */ - 8, 56 + 8 }; diff --git a/windlg.c b/windlg.c index 6d3b0f48..9b2e60fb 100644 --- a/windlg.c +++ b/windlg.c @@ -366,6 +366,7 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue, IDC_CIPHER3DES, IDC_CIPHERBLOWF, IDC_CIPHERDES, + IDC_CIPHERAES, IDC_BUGGYMAC, IDC_AUTHTIS, IDC_PKSTATIC, @@ -578,9 +579,10 @@ static void init_dlg_ctrls(HWND hwnd) { CheckDlgButton (hwnd, IDC_COMPRESS, cfg.compression); CheckDlgButton (hwnd, IDC_BUGGYMAC, cfg.buggymac); CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd); - CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES, + CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERAES, cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF : cfg.cipher == CIPHER_DES ? IDC_CIPHERDES : + cfg.cipher == CIPHER_AES ? IDC_CIPHERAES : IDC_CIPHER3DES); CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2, cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2); @@ -1031,10 +1033,12 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) { radioline(&cp, "Preferred SSH protocol version:", IDC_SSHPROTSTATIC, 2, "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL); - radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3, + radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 4, "&3DES", IDC_CIPHER3DES, "&Blowfish", IDC_CIPHERBLOWF, - "&DES", IDC_CIPHERDES, NULL); + "&DES", IDC_CIPHERDES, + "&AES", IDC_CIPHERAES, + NULL); checkbox(&cp, "&Imitate SSH 2 MAC bug in commercial <= v2.3.x", IDC_BUGGYMAC); endbox(&cp); @@ -1779,6 +1783,7 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg, case IDC_CIPHER3DES: case IDC_CIPHERBLOWF: case IDC_CIPHERDES: + case IDC_CIPHERAES: if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES)) @@ -1787,6 +1792,8 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg, cfg.cipher = CIPHER_BLOWFISH; else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES)) cfg.cipher = CIPHER_DES; + else if (IsDlgButtonChecked (hwnd, IDC_CIPHERAES)) + cfg.cipher = CIPHER_AES; } break; case IDC_SSHPROT1: -- 2.11.0