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:
parent
16f4ffe616
commit
a1d5dab580
141
ssh.c
141
ssh.c
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user