1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

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).

[originally from svn r967]
This commit is contained in:
Simon Tatham 2001-03-02 13:55:23 +00:00
parent bf25fd405c
commit b182356f99
8 changed files with 156 additions and 89 deletions

View File

@ -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 */

View 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;
}

96
ssh.c
View File

@ -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++) {

11
ssh.h
View File

@ -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);

View File

@ -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
};

View 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
};

View File

@ -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
};

View File

@ -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: