Support for selecting AES from the GUI. In the process, I've had to
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 2 Mar 2001 13:55:23 +0000 (13:55 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 2 Mar 2001 13:55:23 +0000 (13:55 +0000)
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
settings.c
ssh.c
ssh.h
sshaes.c
sshblowf.c
sshdes.c
windlg.c

diff --git a/putty.h b/putty.h
index 7bb97d9..cf917ab 100644 (file)
--- 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 */
index 01087ee..ad062dd 100644 (file)
@@ -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 c239eb2..5996fd3 100644 (file)
--- 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 555fe61..aafee4e 100644 (file)
--- 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);
index d6a2766..0e7ddc1 100644 (file)
--- 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 <stdio.h>
+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
+};
index 1d92d30..99d8373 100644 (file)
@@ -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
+};
index 0b47aab..491c906 100644 (file)
--- 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
 };
index 6d3b0f4..9b2e60f 100644 (file)
--- 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: