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

Implement Zlib compression, in both SSH1 and SSH2.

[originally from svn r792]
This commit is contained in:
Simon Tatham 2000-11-01 21:34:21 +00:00
parent 84077ea5ee
commit 462063cdc5
8 changed files with 1212 additions and 31 deletions

View File

@ -69,7 +69,7 @@ MOBJ2 = tree234.$(OBJ)
##-- objects putty pscp plink
OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ)
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ)
OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ)
OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) sshzlib.$(OBJ)
##-- objects pageant
PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ)
PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ)
@ -229,6 +229,7 @@ sshdh.$(OBJ): sshdh.c ssh.h
sshdss.$(OBJ): sshdss.c ssh.h
sshbn.$(OBJ): sshbn.c ssh.h
sshpubk.$(OBJ): sshpubk.c ssh.h
sshzlib.$(OBJ): sshzlib.c ssh.h
scp.$(OBJ): scp.c putty.h network.h winstuff.h
version.$(OBJ): version.c
be_all.$(OBJ): be_all.c

View File

@ -140,6 +140,7 @@ typedef struct {
/* SSH options */
char remote_cmd[512];
int nopty;
int compression;
int agentfwd;
enum { CIPHER_3DES, CIPHER_BLOWFISH, CIPHER_DES } cipher;
char keyfile[FILENAME_MAX];

View File

@ -66,6 +66,7 @@ void save_settings (char *section, int do_host, Config *cfg) {
}
write_setting_s (sesskey, "UserName", cfg->username);
write_setting_i (sesskey, "NoPTY", cfg->nopty);
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" :
@ -186,6 +187,7 @@ void load_settings (char *section, int do_host, Config *cfg) {
}
gpps (sesskey, "UserName", "", cfg->username, sizeof(cfg->username));
gppi (sesskey, "NoPTY", 0, &cfg->nopty);
gppi (sesskey, "Compression", 0, &cfg->compression);
gppi (sesskey, "AgentFwd", 0, &cfg->agentfwd);
gpps (sesskey, "RemoteCmd", "", cfg->remote_cmd, sizeof(cfg->remote_cmd));
{

187
ssh.c
View File

@ -51,6 +51,7 @@
#define SSH1_CMSG_EXIT_CONFIRMATION 33 /* 0x21 */
#define SSH1_MSG_IGNORE 32 /* 0x20 */
#define SSH1_MSG_DEBUG 36 /* 0x24 */
#define SSH1_CMSG_REQUEST_COMPRESSION 37 /* 0x25 */
#define SSH1_CMSG_AUTH_TIS 39 /* 0x27 */
#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 /* 0x28 */
#define SSH1_CMSG_AUTH_TIS_RESPONSE 41 /* 0x29 */
@ -186,10 +187,19 @@ const static struct ssh_mac *macs[] = {
const static struct ssh_mac *buggymacs[] = {
&ssh_sha1_buggy, &ssh_md5, &ssh_mac_none };
static void ssh_comp_none_init(void) { }
static int ssh_comp_none_block(unsigned char *block, int len,
unsigned char **outblock, int *outlen) {
return 0;
}
const static struct ssh_compress ssh_comp_none = {
"none"
"none",
ssh_comp_none_init, ssh_comp_none_block,
ssh_comp_none_init, ssh_comp_none_block
};
const static struct ssh_compress *compressions[] = { &ssh_comp_none };
extern const struct ssh_compress ssh_zlib;
const static struct ssh_compress *compressions[] = {
&ssh_zlib, &ssh_comp_none };
/*
* 2-3-4 tree storing channels.
@ -226,6 +236,7 @@ static SHA_State exhash;
static Socket s = NULL;
static unsigned char session_key[32];
static int ssh1_compressing;
static const struct ssh_cipher *cipher = NULL;
static const struct ssh_cipher *cscipher = NULL;
static const struct ssh_cipher *sccipher = NULL;
@ -373,9 +384,6 @@ next_packet:
debug(("\r\n"));
#endif
pktin.type = pktin.data[st->pad];
pktin.body = pktin.data + st->pad + 1;
st->realcrc = crc32(pktin.data, st->biglen-4);
st->gotcrc = GET_32BIT(pktin.data+st->biglen-4);
if (st->gotcrc != st->realcrc) {
@ -383,6 +391,39 @@ next_packet:
crReturn(0);
}
pktin.body = pktin.data + st->pad + 1;
if (ssh1_compressing) {
unsigned char *decompblk;
int decomplen;
#if 0
int i;
debug(("Packet payload pre-decompression:\n"));
for (i = -1; i < pktin.length; i++)
debug((" %02x", (unsigned char)pktin.body[i]));
debug(("\r\n"));
#endif
zlib_decompress_block(pktin.body-1, pktin.length+1,
&decompblk, &decomplen);
if (pktin.maxlen < st->pad + decomplen) {
pktin.maxlen = st->pad + decomplen;
pktin.data = realloc(pktin.data, pktin.maxlen+APIEXTRA);
if (!pktin.data)
fatalbox("Out of memory");
}
memcpy(pktin.body-1, decompblk, decomplen);
free(decompblk);
pktin.length = decomplen-1;
#if 0
debug(("Packet payload post-decompression:\n"));
for (i = -1; i < pktin.length; i++)
debug((" %02x", (unsigned char)pktin.body[i]));
debug(("\r\n"));
#endif
}
if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
pktin.type == SSH1_SMSG_STDERR_DATA ||
pktin.type == SSH1_MSG_DEBUG ||
@ -395,6 +436,8 @@ next_packet:
}
}
pktin.type = pktin.body[-1];
if (pktin.type == SSH1_MSG_DEBUG) {
/* log debug message */
char buf[80];
@ -515,6 +558,34 @@ next_packet:
}
st->incoming_sequence++; /* whether or not we MACed */
/*
* Decompress packet payload.
*/
{
unsigned char *newpayload;
int newlen;
if (sccomp && sccomp->decompress(pktin.data+5, pktin.length-5,
&newpayload, &newlen)) {
if (pktin.maxlen < newlen+5) {
pktin.maxlen = newlen+5;
pktin.data = (pktin.data == NULL ? malloc(pktin.maxlen+APIEXTRA) :
realloc(pktin.data, pktin.maxlen+APIEXTRA));
if (!pktin.data)
fatalbox("Out of memory");
}
pktin.length = 5 + newlen;
memcpy(pktin.data+5, newpayload, newlen);
#if 0
debug(("Post-decompression payload:\r\n"));
for (st->i = 0; st->i < newlen; st->i++)
debug((" %02x", (unsigned char)pktin.data[5+st->i]));
debug(("\r\n"));
#endif
free(newpayload);
}
}
pktin.savedpos = 6;
pktin.type = pktin.data[5];
@ -524,7 +595,7 @@ next_packet:
crFinish(0);
}
static void s_wrpkt_start(int type, int len) {
static void ssh1_pktout_size(int len) {
int pad, biglen;
len += 5; /* type and CRC */
@ -546,20 +617,46 @@ static void s_wrpkt_start(int type, int len) {
if (!pktout.data)
fatalbox("Out of memory");
}
pktout.type = type;
pktout.body = pktout.data+4+pad+1;
}
static void s_wrpkt_start(int type, int len) {
ssh1_pktout_size(len);
pktout.type = type;
}
static void s_wrpkt(void) {
int pad, len, biglen, i;
unsigned long crc;
pktout.body[-1] = pktout.type;
if (ssh1_compressing) {
unsigned char *compblk;
int complen;
#if 0
debug(("Packet payload pre-compression:\n"));
for (i = -1; i < pktout.length; i++)
debug((" %02x", (unsigned char)pktout.body[i]));
debug(("\r\n"));
#endif
zlib_compress_block(pktout.body-1, pktout.length+1,
&compblk, &complen);
ssh1_pktout_size(complen-1);
memcpy(pktout.body-1, compblk, complen);
free(compblk);
#if 0
debug(("Packet payload post-compression:\n"));
for (i = -1; i < pktout.length; i++)
debug((" %02x", (unsigned char)pktout.body[i]));
debug(("\r\n"));
#endif
}
len = pktout.length + 5; /* type and CRC */
pad = 8 - (len%8);
biglen = len + pad;
pktout.body[-1] = pktout.type;
for (i=0; i<pad; i++)
pktout.data[i+4] = random_byte();
crc = crc32(pktout.data+4, biglen-4);
@ -767,6 +864,26 @@ static void ssh2_pkt_send(void) {
int cipherblk, maclen, padding, i;
static unsigned long outgoing_sequence = 0;
/*
* Compress packet payload.
*/
#if 0
debug(("Pre-compression payload:\r\n"));
for (i = 5; i < pktout.length; i++)
debug((" %02x", (unsigned char)pktout.data[i]));
debug(("\r\n"));
#endif
{
unsigned char *newpayload;
int newlen;
if (cscomp && cscomp->compress(pktout.data+5, pktout.length-5,
&newpayload, &newlen)) {
pktout.length = 5;
ssh2_pkt_adddata(newpayload, newlen);
free(newpayload);
}
}
/*
* Add padding. At least four bytes, and must also bring total
* length (minus MAC) up to a multiple of the block size.
@ -1637,6 +1754,21 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
logevent("Allocated pty");
}
if (cfg.compression) {
send_packet(SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END);
do { crReturnV; } while (!ispkt);
if (pktin.type != SSH1_SMSG_SUCCESS && pktin.type != SSH1_SMSG_FAILURE) {
bombout(("Protocol confusion"));
crReturnV;
} else if (pktin.type == SSH1_SMSG_FAILURE) {
c_write("Server refused to compress\r\n", 32);
}
logevent("Started compression");
ssh1_compressing = TRUE;
zlib_compress_init();
zlib_decompress_init();
}
if (*cfg.remote_cmd)
send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cfg.remote_cmd, PKT_END);
else
@ -1845,12 +1977,13 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
static unsigned char exchange_hash[20];
static unsigned char keyspace[40];
static const struct ssh_cipher *preferred_cipher;
static const struct ssh_compress *preferred_comp;
crBegin;
random_init();
/*
* Set up the preferred cipher.
* Set up the preferred cipher and compression.
*/
if (cfg.cipher == CIPHER_BLOWFISH) {
preferred_cipher = &ssh_blowfish_ssh2;
@ -1863,6 +1996,10 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
/* Shouldn't happen, but we do want to initialise to _something_. */
preferred_cipher = &ssh_3des_ssh2;
}
if (cfg.compression)
preferred_comp = &ssh_zlib;
else
preferred_comp = &ssh_comp_none;
/*
* Be prepared to work around the buggy MAC problem.
@ -1925,16 +2062,18 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
}
/* List client->server compression algorithms. */
ssh2_pkt_addstring_start();
for (i = 0; i < lenof(compressions); i++) {
ssh2_pkt_addstring_str(compressions[i]->name);
if (i < lenof(compressions)-1)
for (i = 0; i < lenof(compressions)+1; i++) {
const struct ssh_compress *c = i==0 ? preferred_comp : compressions[i-1];
ssh2_pkt_addstring_str(c->name);
if (i < lenof(compressions))
ssh2_pkt_addstring_str(",");
}
/* List server->client compression algorithms. */
ssh2_pkt_addstring_start();
for (i = 0; i < lenof(compressions); i++) {
ssh2_pkt_addstring_str(compressions[i]->name);
if (i < lenof(compressions)-1)
for (i = 0; i < lenof(compressions)+1; i++) {
const struct ssh_compress *c = i==0 ? preferred_comp : compressions[i-1];
ssh2_pkt_addstring_str(c->name);
if (i < lenof(compressions))
ssh2_pkt_addstring_str(",");
}
/* List client->server languages. Empty list. */
@ -2007,16 +2146,18 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
}
}
ssh2_pkt_getstring(&str, &len); /* client->server compression */
for (i = 0; i < lenof(compressions); i++) {
if (in_commasep_string(compressions[i]->name, str, len)) {
cscomp_tobe = compressions[i];
for (i = 0; i < lenof(compressions)+1; i++) {
const struct ssh_compress *c = i==0 ? preferred_comp : compressions[i-1];
if (in_commasep_string(c->name, str, len)) {
cscomp_tobe = c;
break;
}
}
ssh2_pkt_getstring(&str, &len); /* server->client compression */
for (i = 0; i < lenof(compressions); i++) {
if (in_commasep_string(compressions[i]->name, str, len)) {
sccomp_tobe = compressions[i];
for (i = 0; i < lenof(compressions)+1; i++) {
const struct ssh_compress *c = i==0 ? preferred_comp : compressions[i-1];
if (in_commasep_string(c->name, str, len)) {
sccomp_tobe = c;
break;
}
}
@ -2105,6 +2246,8 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
scmac = scmac_tobe;
cscomp = cscomp_tobe;
sccomp = sccomp_tobe;
cscomp->compress_init();
sccomp->decompress_init();
/*
* Set IVs after keys.
*/

16
ssh.h
View File

@ -137,6 +137,12 @@ struct ssh_hostkey {
struct ssh_compress {
char *name;
void (*compress_init)(void);
int (*compress)(unsigned char *block, int len,
unsigned char **outblock, int *outlen);
void (*decompress_init)(void);
int (*decompress)(unsigned char *block, int len,
unsigned char **outblock, int *outlen);
};
#ifndef MSCRYPTOAPI
@ -197,3 +203,13 @@ int rsa_generate(struct RSAKey *key, struct RSAAux *aux, int bits,
progfn_t pfn, void *pfnparam);
Bignum primegen(int bits, int modulus, int residue,
int phase, progfn_t pfn, void *pfnparam);
/*
* zlib compression.
*/
void zlib_compress_init(void);
void zlib_decompress_init(void);
int zlib_compress_block(unsigned char *block, int len,
unsigned char **outblock, int *outlen);
int zlib_decompress_block(unsigned char *block, int len,
unsigned char **outblock, int *outlen);

1010
sshzlib.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,24 +31,24 @@ BEGIN
END
/* Accelerators used: aco */
IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 280, 232
IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 280, 242
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "PuTTY Configuration"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "&Open", IDOK, 184, 215, 44, 14
PUSHBUTTON "&Cancel", IDCANCEL, 231, 215, 44, 14
PUSHBUTTON "&About", IDC_ABOUT, 3, 215, 44, 14, NOT WS_TABSTOP
DEFPUSHBUTTON "&Open", IDOK, 184, 225, 44, 14
PUSHBUTTON "&Cancel", IDCANCEL, 231, 225, 44, 14
PUSHBUTTON "&About", IDC_ABOUT, 3, 225, 44, 14, NOT WS_TABSTOP
END
/* Accelerators used: ac */
IDD_RECONF DIALOG DISCARDABLE 0, 0, 280, 232
IDD_RECONF DIALOG DISCARDABLE 0, 0, 280, 242
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "PuTTY Reconfiguration"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "&Apply", IDOK, 184, 215, 44, 14
PUSHBUTTON "&Cancel", IDCANCEL, 231, 215, 44, 14
DEFPUSHBUTTON "&Apply", IDOK, 184, 225, 44, 14
PUSHBUTTON "&Cancel", IDCANCEL, 231, 225, 44, 14
END
/* Accelerators used: co */

View File

@ -326,6 +326,7 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
IDC_AGENTFWD,
IDC_CMDSTATIC,
IDC_CMDEDIT,
IDC_COMPRESS,
sshpanelend,
selectionpanelstart,
@ -486,6 +487,7 @@ static void init_dlg_ctrls(HWND hwnd) {
SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
CheckDlgButton (hwnd, IDC_COMPRESS, cfg.compression);
CheckDlgButton (hwnd, IDC_BUGGYMAC, cfg.buggymac);
CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
@ -631,7 +633,7 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
r.left = 3; r.right = r.left + 75;
r.top = 13; r.bottom = r.top + 196;
r.top = 13; r.bottom = r.top + 206;
MapDialogRect(hwnd, &r);
treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
WS_CHILD | WS_VISIBLE |
@ -972,6 +974,7 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
beginbox(&cp, "Protocol options",
IDC_BOX_SSH3, IDC_BOXT_SSH3);
checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
checkbox(&cp, "Enable compr&ession", IDC_COMPRESS);
radioline(&cp, "Preferred SSH protocol version:",
IDC_SSHPROTSTATIC, 2,
"&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
@ -1497,6 +1500,11 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
HIWORD(wParam) == BN_DOUBLECLICKED)
cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
break;
case IDC_COMPRESS:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED)
cfg.compression = IsDlgButtonChecked (hwnd, IDC_COMPRESS);
break;
case IDC_BUGGYMAC:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED)