1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -05:00

Further traffic analysis defences

[originally from svn r981]
This commit is contained in:
Simon Tatham 2001-03-05 10:32:36 +00:00
parent 16f4ffe616
commit a1d5dab580

141
ssh.c
View File

@ -653,7 +653,7 @@ static void s_wrpkt_start(int type, int len) {
pktout.type = type; pktout.type = type;
} }
static void s_wrpkt(void) { static int s_wrpkt_prepare(void) {
int pad, len, biglen, i; int pad, len, biglen, i;
unsigned long crc; unsigned long crc;
@ -700,93 +700,118 @@ static void s_wrpkt(void) {
if (cipher) if (cipher)
cipher->encrypt(pktout.data+4, biglen); cipher->encrypt(pktout.data+4, biglen);
sk_write(s, pktout.data, biglen+4); return biglen+4;
}
static void s_wrpkt(void) {
int len;
len = s_wrpkt_prepare();
sk_write(s, pktout.data, len);
}
static void s_wrpkt_defer(void) {
int len;
len = s_wrpkt_prepare();
if (deferred_len + len > deferred_size) {
deferred_size = deferred_len + len + 128;
deferred_send_data = srealloc(deferred_send_data, deferred_size);
}
memcpy(deferred_send_data+deferred_len, pktout.data, len);
deferred_len += len;
} }
/* /*
* Construct a packet with the specified contents and * Construct a packet with the specified contents.
* send it to the server.
*/ */
static void send_packet(int pkttype, ...) static void construct_packet(int pkttype, va_list ap1, va_list ap2)
{ {
va_list args;
unsigned char *p, *argp, argchar; unsigned char *p, *argp, argchar;
unsigned long argint; unsigned long argint;
int pktlen, argtype, arglen; int pktlen, argtype, arglen;
Bignum bn; Bignum bn;
pktlen = 0; pktlen = 0;
va_start(args, pkttype); while ((argtype = va_arg(ap1, int)) != PKT_END) {
while ((argtype = va_arg(args, int)) != PKT_END) {
switch (argtype) { switch (argtype) {
case PKT_INT: case PKT_INT:
(void) va_arg(args, int); (void) va_arg(ap1, int);
pktlen += 4; pktlen += 4;
break; break;
case PKT_CHAR: case PKT_CHAR:
(void) va_arg(args, char); (void) va_arg(ap1, char);
pktlen++; pktlen++;
break; break;
case PKT_DATA: case PKT_DATA:
(void) va_arg(args, unsigned char *); (void) va_arg(ap1, unsigned char *);
arglen = va_arg(args, int); arglen = va_arg(ap1, int);
pktlen += arglen; pktlen += arglen;
break; break;
case PKT_STR: case PKT_STR:
argp = va_arg(args, unsigned char *); argp = va_arg(ap1, unsigned char *);
arglen = strlen(argp); arglen = strlen(argp);
pktlen += 4 + arglen; pktlen += 4 + arglen;
break; break;
case PKT_BIGNUM: case PKT_BIGNUM:
bn = va_arg(args, Bignum); bn = va_arg(ap1, Bignum);
pktlen += ssh1_bignum_length(bn); pktlen += ssh1_bignum_length(bn);
break; break;
default: default:
assert(0); assert(0);
} }
} }
va_end(args);
s_wrpkt_start(pkttype, pktlen); s_wrpkt_start(pkttype, pktlen);
p = pktout.body; p = pktout.body;
va_start(args, pkttype); while ((argtype = va_arg(ap2, int)) != PKT_END) {
while ((argtype = va_arg(args, int)) != PKT_END) {
switch (argtype) { switch (argtype) {
case PKT_INT: case PKT_INT:
argint = va_arg(args, int); argint = va_arg(ap2, int);
PUT_32BIT(p, argint); PUT_32BIT(p, argint);
p += 4; p += 4;
break; break;
case PKT_CHAR: case PKT_CHAR:
argchar = va_arg(args, unsigned char); argchar = va_arg(ap2, unsigned char);
*p = argchar; *p = argchar;
p++; p++;
break; break;
case PKT_DATA: case PKT_DATA:
argp = va_arg(args, unsigned char *); argp = va_arg(ap2, unsigned char *);
arglen = va_arg(args, int); arglen = va_arg(ap2, int);
memcpy(p, argp, arglen); memcpy(p, argp, arglen);
p += arglen; p += arglen;
break; break;
case PKT_STR: case PKT_STR:
argp = va_arg(args, unsigned char *); argp = va_arg(ap2, unsigned char *);
arglen = strlen(argp); arglen = strlen(argp);
PUT_32BIT(p, arglen); PUT_32BIT(p, arglen);
memcpy(p + 4, argp, arglen); memcpy(p + 4, argp, arglen);
p += 4 + arglen; p += 4 + arglen;
break; break;
case PKT_BIGNUM: case PKT_BIGNUM:
bn = va_arg(args, Bignum); bn = va_arg(ap2, Bignum);
p += ssh1_write_bignum(p, bn); p += ssh1_write_bignum(p, bn);
break; break;
} }
} }
va_end(args); }
static void send_packet(int pkttype, ...) {
va_list ap1, ap2;
va_start(ap1, pkttype);
va_start(ap2, pkttype);
construct_packet(pkttype, ap1, ap2);
s_wrpkt(); s_wrpkt();
} }
static void defer_packet(int pkttype, ...) {
va_list ap1, ap2;
va_start(ap1, pkttype);
va_start(ap2, pkttype);
construct_packet(pkttype, ap1, ap2);
s_wrpkt_defer();
}
static int ssh_versioncmp(char *a, char *b) { static int ssh_versioncmp(char *a, char *b) {
char *ae, *be; char *ae, *be;
unsigned long av, bv; unsigned long av, bv;
@ -989,9 +1014,9 @@ static void ssh2_pkt_defer(void) {
/* /*
* Send the whole deferred data block constructed by * Send the whole deferred data block constructed by
* ssh2_pkt_defer(). * ssh2_pkt_defer() or SSH1's defer_packet().
*/ */
static void ssh2_pkt_defersend(void) { static void ssh_pkt_defersend(void) {
sk_write(s, deferred_send_data, deferred_len); sk_write(s, deferred_send_data, deferred_len);
deferred_len = deferred_size = 0; deferred_len = deferred_size = 0;
sfree(deferred_send_data); sfree(deferred_send_data);
@ -1784,7 +1809,67 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
break; /* we're through! */ break; /* we're through! */
} else { } else {
send_packet(pwpkt_type, PKT_STR, password, PKT_END); if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
/*
* Defence against traffic analysis: we send a
* whole bunch of packets containing strings of
* different lengths. One of these strings is the
* password, in a SSH1_CMSG_AUTH_PASSWORD packet.
* The others are all random data in
* SSH1_MSG_IGNORE packets. This way a passive
* listener can't tell which is the password, and
* hence can't deduce the password length.
*
* Anybody with a password length greater than 16
* bytes is going to have enough entropy in their
* password that a listener won't find it _that_
* much help to know how long it is. So what we'll
* do is:
*
* - if password length < 16, we send 15 packets
* containing string lengths 1 through 15
*
* - otherwise, we let N be the nearest multiple
* of 8 below the password length, and send 8
* packets containing string lengths N through
* N+7. This won't obscure the order of
* magnitude of the password length, but it will
* introduce a bit of extra uncertainty.
*/
int bottom, top, pwlen, i;
char *randomstr;
pwlen = strlen(password);
if (pwlen < 16) {
bottom = 1;
top = 15;
} else {
bottom = pwlen &~ 7;
top = bottom + 7;
}
assert(pwlen >= bottom && pwlen <= top);
randomstr = smalloc(top+1);
for (i = bottom; i <= top; i++) {
if (i == pwlen)
defer_packet(pwpkt_type, PKT_STR, password, PKT_END);
else {
for (j = 0; j < i; j++) {
do {
randomstr[j] = random_byte();
} while (randomstr[j] == '\0');
}
randomstr[i] = '\0';
defer_packet(SSH1_MSG_IGNORE,
PKT_STR, randomstr, PKT_END);
}
}
ssh_pkt_defersend();
} else {
send_packet(pwpkt_type, PKT_STR, password, PKT_END);
}
} }
logevent("Sent password"); logevent("Sent password");
memset(password, 0, strlen(password)); memset(password, 0, strlen(password));
@ -3151,7 +3236,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
} }
ssh2_pkt_defer(); ssh2_pkt_defer();
} }
ssh2_pkt_defersend(); ssh_pkt_defersend();
logevent("Sent password"); logevent("Sent password");
type = AUTH_TYPE_PASSWORD; type = AUTH_TYPE_PASSWORD;
} else { } else {