procmem at riseup.net
2023-Sep-06 18:57 UTC
Privacy improving suggestions for ObscureKeystrokeTiming
Hi, Whonix OS privacy dev here. I had a discussion concerning the new ObscureKeystrokeTiming feature with a prominent researcher and author of the mouse and keyboard biometrics obfuscation tool called Kloak. While it's exciting to see keystroke obfuscation measures [1] start to become more prevalent mainstream, the current implementation of using a 50Hz fixed packet timing has the potential to create fingerprinting risks for hosts. Reason being, not all computer clocks have the exact same precision. Some may oscillate slightly faster or slower because of the physical discrepancies of clock crystals. A network adversary monitoring connections on the clearnet could potentially link future ones of the same host even if routed through an anonymity network like Tor. Advanced attacks where attackers run loads on onion services that influence CPU activity and clock skew in predictable ways [2] may be possibly used to deanonymize them. We would suggest drawing the padding packet intervals from some other distribution instead of firing these off on a fixed timer. Basically, do what kloak does but at the network layer. [0] https://github.com/vmonaco/kloak [1] http://undeadly.org/cgi?action=article;sid=20230829051257 [2] https://murdoch.is/talks/ccs06hotornot.pdf
Damien Miller
2023-Sep-07 04:47 UTC
Privacy improving suggestions for ObscureKeystrokeTiming
On Wed, 6 Sep 2023, procmem at riseup.net wrote:> Hi, Whonix OS privacy dev here. I had a discussion concerning the new > ObscureKeystrokeTiming feature with a prominent researcher and author of the > mouse and keyboard biometrics obfuscation tool called Kloak. While it's > exciting to see keystroke obfuscation measures [1] start to become more > prevalent mainstream, the current implementation of using a 50Hz fixed packet > timing has the potential to create fingerprinting risks for hosts. Reason > being, not all computer clocks have the exact same precision. Some may > oscillate slightly faster or slower because of the physical discrepancies of > clock crystals. A network adversary monitoring connections on the clearnet > could potentially link future ones of the same host even if routed through an > anonymity network like Tor. > > Advanced attacks where attackers run loads on onion services that influence > CPU activity and clock skew in predictable ways [2] may be possibly used to > deanonymize them. > > We would suggest drawing the padding packet intervals from some other > distribution instead of firing these off on a fixed timer. Basically, do what > kloak does but at the network layer.Yeah, making the intervals a bit uncertain seems like a reasonable idea. This gives them 10% jitter. diff --git a/clientloop.c b/clientloop.c index b461917..73cdd09 100644 --- a/clientloop.c +++ b/clientloop.c @@ -109,6 +109,9 @@ /* Permitted RSA signature algorithms for UpdateHostkeys proofs */ #define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" +/* Uncertainty (in percent) of keystroke timing intervals */ +#define SSH_KEYSTROKE_TIMING_FUZZ 10 + /* import options */ extern Options options; @@ -519,6 +522,33 @@ send_chaff(struct ssh *ssh) return 1; } +/* Sets the next interval to send a keystroke or chaff packet */ +static void +set_next_interval(const struct timespec *now, struct timespec *next_interval, + u_int interval_ms, u_int interval_fuzz_pct) +{ + struct timespec tmp; + long long interval_ns, fuzz_ns; + + interval_ns = interval_ms * (1000LL * 1000); + fuzz_ns = (interval_ns * interval_fuzz_pct) / 100; + /* Center fuzz around requested interval */ + if (fuzz_ns > INT_MAX) + fuzz_ns = INT_MAX; + if (fuzz_ns > interval_ns) { + /* Shouldn't happen */ + fatal_f("internal error: fuzz %u%% %lldns > interval %lldns", + interval_fuzz_pct, fuzz_ns, interval_ns); + } + interval_ns -= fuzz_ns / 2; + interval_ns += arc4random_uniform(fuzz_ns); + + tmp.tv_sec = interval_ns / (1000 * 1000 * 1000); + tmp.tv_nsec = interval_ns % (1000 * 1000 * 1000); + + timespecadd(now, &tmp, next_interval); +} + /* * Performs keystroke timing obfuscation. Returns non-zero if the * output fd should be polled. @@ -586,8 +616,9 @@ obfuscate_keystroke_timing(struct ssh *ssh, struct timespec *timeout, options.obscure_keystroke_timing_interval); just_started = had_keystroke = active = 1; nchaff = 0; - ms_to_timespec(&tmp, options.obscure_keystroke_timing_interval); - timespecadd(&now, &tmp, &next_interval); + set_next_interval(&now, &next_interval, + options.obscure_keystroke_timing_interval, + SSH_KEYSTROKE_TIMING_FUZZ); } /* Don't hold off if obfuscation inactive */ @@ -620,8 +651,9 @@ obfuscate_keystroke_timing(struct ssh *ssh, struct timespec *timeout, n = (n < 0) ? 1 : n + 1; /* Advance to the next interval */ - ms_to_timespec(&tmp, options.obscure_keystroke_timing_interval * n); - timespecadd(&now, &tmp, &next_interval); + set_next_interval(&now, &next_interval, + options.obscure_keystroke_timing_interval * n, + SSH_KEYSTROKE_TIMING_FUZZ); return 1; }