From 5ad601ffcd5d09b5f22d998f71ce9ccdf35140f1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 8 Jan 2022 12:09:36 +0000 Subject: [PATCH] Windows PuTTYgen: rate-limit entropy counter increment. Some pointing devices (e.g. gaming mice) can be set to send mouse-movement events at an extremely high sample rate like 1kHz. This apparently translates into Windows genuinely sending WM_MOUSEMOVE messages at that rate. So if you're using one of those mice, then PuTTYgen's mouse-based entropy collection system will fill its buffer almost immediately, and give you no perceptible time to actually wave the mouse around. I think that in that situation, there's also likely to be a strong correlation between the contents of successive movement events, because human-controlled mouse movements aren't fractals - the more you zoom in on a little piece of one, the more it starts to look more and more like something moving in a straight line at constant speed, because the deviations from that happen on a larger time scale than you're seeing. So this commit adds a rate limit, not on the _collection_ of the data (we'll still take all the bits we can get, thanks!), but on the rate at which we increment the _counter_ for how much entropy we think we've collected so far. That way, the user still has to spend time wiggling the mouse back and forth in a way that varies with muscle motions and introduces randomness. --- windows/puttygen.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/windows/puttygen.c b/windows/puttygen.c index d9b2eb29..887a34b4 100644 --- a/windows/puttygen.c +++ b/windows/puttygen.c @@ -634,6 +634,7 @@ struct MainDlgState { bool key_exists; int entropy_got, entropy_required; strbuf *entropy; + ULONG entropy_prev_msgtime; int key_bits, curve_bits; bool ssh2; keytype keytype; @@ -651,6 +652,23 @@ struct MainDlgState { HMENU filemenu, keymenu, cvtmenu; }; +/* + * Rate limit for incrementing the entropy_got counter. + * + * Some pointing devices (e.g. gaming mice) can be set to send + * mouse-movement events at an extremely high sample rate like 1kHz. + * In that situation, there's likely to be a strong correlation + * between the contents of successive movement events, so you have to + * regard the mouse movements as containing less entropy each. + * + * A reasonably simple approach to this is to continue to buffer all + * mouse data, but limit the rate at which we increment the counter + * for how much entropy we think we've collected. That way, the user + * still has to spend time wiggling the mouse back and forth in a way + * that varies with muscle motions and introduces randomness. + */ +#define ENTROPY_RATE_LIMIT 10 /* in units of GetMessageTime(), i.e. ms */ + static void hidemany(HWND hwnd, const int *ids, bool hideit) { while (*ids) { @@ -1406,9 +1424,13 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, case WM_MOUSEMOVE: state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (state->entropy && state->entropy_got < state->entropy_required) { + ULONG msgtime = GetMessageTime(); put_uint32(state->entropy, lParam); - put_uint32(state->entropy, GetMessageTime()); - state->entropy_got += 2; + put_uint32(state->entropy, msgtime); + if (msgtime - state->entropy_prev_msgtime > ENTROPY_RATE_LIMIT) { + state->entropy_got += 2; + state->entropy_prev_msgtime = msgtime; + } SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, state->entropy_got, 0); if (state->entropy_got >= state->entropy_required) { @@ -1634,6 +1656,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, state->entropy_got = 0; state->entropy = strbuf_new_nm(); + state->entropy_prev_msgtime = GetMessageTime(); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, state->entropy_required));