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

Windows PuTTYgen: switch to CryptGenRandom.

We now only use the mouse-movement based entropy collection system if
the system CPRNG fails to provide us with as much entropy as we want.
This commit is contained in:
Simon Tatham 2018-06-03 14:41:31 +01:00
parent 025599ec99
commit 6142013abc
3 changed files with 119 additions and 73 deletions

View File

@ -19,6 +19,29 @@ DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext,
(HCRYPTPROV, DWORD)); (HCRYPTPROV, DWORD));
static HMODULE wincrypt_module = NULL; static HMODULE wincrypt_module = NULL;
int win_read_random(void *buf, unsigned wanted)
{
int toret = FALSE;
HCRYPTPROV crypt_provider;
if (!wincrypt_module) {
wincrypt_module = load_system32_dll("advapi32.dll");
GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA);
GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom);
GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext);
}
if (wincrypt_module && p_CryptAcquireContextA &&
p_CryptGenRandom && p_CryptReleaseContext &&
p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
toret = p_CryptGenRandom(crypt_provider, wanted, buf);
p_CryptReleaseContext(crypt_provider, 0);
}
return toret;
}
/* /*
* This function is called once, at PuTTY startup. * This function is called once, at PuTTY startup.
*/ */
@ -28,8 +51,8 @@ void noise_get_heavy(void (*func) (void *, int))
HANDLE srch; HANDLE srch;
WIN32_FIND_DATA finddata; WIN32_FIND_DATA finddata;
DWORD pid; DWORD pid;
HCRYPTPROV crypt_provider;
char winpath[MAX_PATH + 3]; char winpath[MAX_PATH + 3];
BYTE buf[32];
GetWindowsDirectory(winpath, sizeof(winpath)); GetWindowsDirectory(winpath, sizeof(winpath));
strcat(winpath, "\\*"); strcat(winpath, "\\*");
@ -44,22 +67,9 @@ void noise_get_heavy(void (*func) (void *, int))
pid = GetCurrentProcessId(); pid = GetCurrentProcessId();
func(&pid, sizeof(pid)); func(&pid, sizeof(pid));
if (!wincrypt_module) { if (win_read_random(buf, sizeof(buf))) {
wincrypt_module = load_system32_dll("advapi32.dll"); func(buf, sizeof(buf));
GET_WINDOWS_FUNCTION(wincrypt_module, CryptAcquireContextA); smemclr(buf, sizeof(buf));
GET_WINDOWS_FUNCTION(wincrypt_module, CryptGenRandom);
GET_WINDOWS_FUNCTION(wincrypt_module, CryptReleaseContext);
}
if (wincrypt_module && p_CryptAcquireContextA &&
p_CryptGenRandom && p_CryptReleaseContext &&
p_CryptAcquireContextA(&crypt_provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
BYTE buf[32];
if (p_CryptGenRandom(crypt_provider, 32, buf)) {
func(buf, sizeof(buf));
}
p_CryptReleaseContext(crypt_provider, 0);
} }
read_random_seed(func); read_random_seed(func);

View File

@ -809,14 +809,45 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
burnstr(passphrase); burnstr(passphrase);
} }
static void start_generating_key(HWND hwnd, struct MainDlgState *state)
{
static const char generating_msg[] =
"Please wait while a key is generated...";
struct rsa_key_thread_params *params;
DWORD threadid;
SetDlgItemText(hwnd, IDC_GENERATING, generating_msg);
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
MAKELPARAM(0, PROGRESSRANGE));
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
params = snew(struct rsa_key_thread_params);
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
params->dialog = hwnd;
params->key_bits = state->key_bits;
params->curve_bits = state->curve_bits;
params->keytype = state->keytype;
params->key = &state->key;
params->dsskey = &state->dsskey;
if (!CreateThread(NULL, 0, generate_key_thread,
params, 0, &threadid)) {
MessageBox(hwnd, "Out of thread resources",
"Key generation error",
MB_OK | MB_ICONERROR);
sfree(params);
} else {
state->generation_thread_exists = TRUE;
}
}
/* /*
* Dialog-box function for the main PuTTYgen dialog box. * Dialog-box function for the main PuTTYgen dialog box.
*/ */
static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg, static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) WPARAM wParam, LPARAM lParam)
{ {
static const char generating_msg[] =
"Please wait while a key is generated...";
static const char entropy_msg[] = static const char entropy_msg[] =
"Please generate some randomness by moving the mouse over the blank area."; "Please generate some randomness by moving the mouse over the blank area.";
struct MainDlgState *state; struct MainDlgState *state;
@ -1009,9 +1040,6 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
state->entropy_got, 0); state->entropy_got, 0);
if (state->entropy_got >= state->entropy_required) { if (state->entropy_got >= state->entropy_required) {
struct rsa_key_thread_params *params;
DWORD threadid;
/* /*
* Seed the entropy pool * Seed the entropy pool
*/ */
@ -1020,29 +1048,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
sfree(state->entropy); sfree(state->entropy);
state->collecting_entropy = FALSE; state->collecting_entropy = FALSE;
SetDlgItemText(hwnd, IDC_GENERATING, generating_msg); start_generating_key(hwnd, state);
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
MAKELPARAM(0, PROGRESSRANGE));
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
params = snew(struct rsa_key_thread_params);
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
params->dialog = hwnd;
params->key_bits = state->key_bits;
params->curve_bits = state->curve_bits;
params->keytype = state->keytype;
params->key = &state->key;
params->dsskey = &state->dsskey;
if (!CreateThread(NULL, 0, generate_key_thread,
params, 0, &threadid)) {
MessageBox(hwnd, "Out of thread resources",
"Key generation error",
MB_OK | MB_ICONERROR);
sfree(params);
} else {
state->generation_thread_exists = TRUE;
}
} }
} }
break; break;
@ -1102,6 +1108,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
state = state =
(struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (!state->generation_thread_exists) { if (!state->generation_thread_exists) {
unsigned raw_entropy_required;
unsigned char *raw_entropy_buf;
BOOL ok; BOOL ok;
state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE); state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE);
if (!ok) if (!ok)
@ -1149,39 +1157,62 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
break; break;
} }
ui_set_state(hwnd, state, 1);
SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
state->key_exists = FALSE;
state->collecting_entropy = TRUE;
/*
* My brief statistical tests on mouse movements
* suggest that there are about 2.5 bits of
* randomness in the x position, 2.5 in the y
* position, and 1.7 in the message time, making
* 5.7 bits of unpredictability per mouse movement.
* However, other people have told me it's far less
* than that, so I'm going to be stupidly cautious
* and knock that down to a nice round 2. With this
* method, we require two words per mouse movement,
* so with 2 bits per mouse movement we expect 2
* bits every 2 words.
*/
if (state->keytype == RSA || state->keytype == DSA) if (state->keytype == RSA || state->keytype == DSA)
state->entropy_required = (state->key_bits / 2) * 2; raw_entropy_required = (state->key_bits / 2) * 2;
else if (state->keytype == ECDSA) else if (state->keytype == ECDSA)
state->entropy_required = (state->curve_bits / 2) * 2; raw_entropy_required = (state->curve_bits / 2) * 2;
else else
state->entropy_required = 256; raw_entropy_required = 256;
state->entropy_got = 0; raw_entropy_buf = snewn(raw_entropy_required, unsigned char);
state->entropy_size = (state->entropy_required * if (win_read_random(raw_entropy_buf, raw_entropy_required)) {
sizeof(unsigned)); /*
state->entropy = snewn(state->entropy_required, unsigned); * If we can get the entropy we need from
* CryptGenRandom, just do that, and go straight
* to the key-generation phase.
*/
random_add_heavynoise(raw_entropy_buf,
raw_entropy_required);
start_generating_key(hwnd, state);
} else {
/*
* Manual entropy input, by making the user wave
* the mouse over the window a lot.
*
* My brief statistical tests on mouse movements
* suggest that there are about 2.5 bits of
* randomness in the x position, 2.5 in the y
* position, and 1.7 in the message time, making
* 5.7 bits of unpredictability per mouse
* movement. However, other people have told me
* it's far less than that, so I'm going to be
* stupidly cautious and knock that down to a nice
* round 2. With this method, we require two words
* per mouse movement, so with 2 bits per mouse
* movement we expect 2 bits every 2 words, i.e.
* the number of _words_ of mouse data we want to
* collect is just the same as the number of
* _bits_ of entropy we want.
*/
state->entropy_required = raw_entropy_required;
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, ui_set_state(hwnd, state, 1);
MAKELPARAM(0, state->entropy_required)); SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); state->key_exists = FALSE;
state->collecting_entropy = TRUE;
state->entropy_got = 0;
state->entropy_size = (state->entropy_required *
sizeof(unsigned));
state->entropy = snewn(state->entropy_required, unsigned);
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
MAKELPARAM(0, state->entropy_required));
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0);
}
smemclr(raw_entropy_buf, raw_entropy_required);
sfree(raw_entropy_buf);
} }
break; break;
case IDC_SAVE: case IDC_SAVE:

View File

@ -607,6 +607,11 @@ void remove_session_from_jumplist(const char * const sessionname);
void clear_jumplist(void); void clear_jumplist(void);
BOOL set_explicit_app_user_model_id(); BOOL set_explicit_app_user_model_id();
/*
* Exports from winnoise.c.
*/
int win_read_random(void *buf, unsigned wanted); /* returns TRUE on success */
/* /*
* Extra functions in winstore.c over and above the interface in * Extra functions in winstore.c over and above the interface in
* storage.h. * storage.h.