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:
parent
025599ec99
commit
6142013abc
@ -19,6 +19,29 @@ DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext,
|
||||
(HCRYPTPROV, DWORD));
|
||||
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.
|
||||
*/
|
||||
@ -28,8 +51,8 @@ void noise_get_heavy(void (*func) (void *, int))
|
||||
HANDLE srch;
|
||||
WIN32_FIND_DATA finddata;
|
||||
DWORD pid;
|
||||
HCRYPTPROV crypt_provider;
|
||||
char winpath[MAX_PATH + 3];
|
||||
BYTE buf[32];
|
||||
|
||||
GetWindowsDirectory(winpath, sizeof(winpath));
|
||||
strcat(winpath, "\\*");
|
||||
@ -44,22 +67,9 @@ void noise_get_heavy(void (*func) (void *, int))
|
||||
pid = GetCurrentProcessId();
|
||||
func(&pid, sizeof(pid));
|
||||
|
||||
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)) {
|
||||
BYTE buf[32];
|
||||
if (p_CryptGenRandom(crypt_provider, 32, buf)) {
|
||||
if (win_read_random(buf, sizeof(buf))) {
|
||||
func(buf, sizeof(buf));
|
||||
}
|
||||
p_CryptReleaseContext(crypt_provider, 0);
|
||||
smemclr(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
read_random_seed(func);
|
||||
|
@ -809,14 +809,45 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
|
||||
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.
|
||||
*/
|
||||
static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static const char generating_msg[] =
|
||||
"Please wait while a key is generated...";
|
||||
static const char entropy_msg[] =
|
||||
"Please generate some randomness by moving the mouse over the blank area.";
|
||||
struct MainDlgState *state;
|
||||
@ -1009,9 +1040,6 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||
SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS,
|
||||
state->entropy_got, 0);
|
||||
if (state->entropy_got >= state->entropy_required) {
|
||||
struct rsa_key_thread_params *params;
|
||||
DWORD threadid;
|
||||
|
||||
/*
|
||||
* Seed the entropy pool
|
||||
*/
|
||||
@ -1020,29 +1048,7 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||
sfree(state->entropy);
|
||||
state->collecting_entropy = FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
start_generating_key(hwnd, state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1102,6 +1108,8 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||
state =
|
||||
(struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if (!state->generation_thread_exists) {
|
||||
unsigned raw_entropy_required;
|
||||
unsigned char *raw_entropy_buf;
|
||||
BOOL ok;
|
||||
state->key_bits = GetDlgItemInt(hwnd, IDC_BITS, &ok, FALSE);
|
||||
if (!ok)
|
||||
@ -1149,30 +1157,49 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||
break;
|
||||
}
|
||||
|
||||
ui_set_state(hwnd, state, 1);
|
||||
SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
|
||||
state->key_exists = FALSE;
|
||||
state->collecting_entropy = TRUE;
|
||||
if (state->keytype == RSA || state->keytype == DSA)
|
||||
raw_entropy_required = (state->key_bits / 2) * 2;
|
||||
else if (state->keytype == ECDSA)
|
||||
raw_entropy_required = (state->curve_bits / 2) * 2;
|
||||
else
|
||||
raw_entropy_required = 256;
|
||||
|
||||
raw_entropy_buf = snewn(raw_entropy_required, unsigned char);
|
||||
if (win_read_random(raw_entropy_buf, raw_entropy_required)) {
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
if (state->keytype == RSA || state->keytype == DSA)
|
||||
state->entropy_required = (state->key_bits / 2) * 2;
|
||||
else if (state->keytype == ECDSA)
|
||||
state->entropy_required = (state->curve_bits / 2) * 2;
|
||||
else
|
||||
state->entropy_required = 256;
|
||||
state->entropy_required = raw_entropy_required;
|
||||
|
||||
ui_set_state(hwnd, state, 1);
|
||||
SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
|
||||
state->key_exists = FALSE;
|
||||
state->collecting_entropy = TRUE;
|
||||
|
||||
state->entropy_got = 0;
|
||||
state->entropy_size = (state->entropy_required *
|
||||
@ -1183,6 +1210,10 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
|
||||
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;
|
||||
case IDC_SAVE:
|
||||
case IDC_EXPORT_OPENSSH_AUTO:
|
||||
|
@ -607,6 +607,11 @@ void remove_session_from_jumplist(const char * const sessionname);
|
||||
void clear_jumplist(void);
|
||||
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
|
||||
* storage.h.
|
||||
|
Loading…
Reference in New Issue
Block a user