1999-01-08 13:02:13 +00:00
|
|
|
/*
|
|
|
|
* Noise generation for PuTTY's cryptographic random number
|
|
|
|
* generator.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "putty.h"
|
|
|
|
#include "ssh.h"
|
2000-09-27 15:21:04 +00:00
|
|
|
#include "storage.h"
|
1999-01-08 13:02:13 +00:00
|
|
|
|
2013-07-20 08:34:54 +00:00
|
|
|
#include <wincrypt.h>
|
|
|
|
|
|
|
|
DECL_WINDOWS_FUNCTION(static, BOOL, CryptAcquireContextA,
|
|
|
|
(HCRYPTPROV *, LPCTSTR, LPCTSTR, DWORD, DWORD));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, BOOL, CryptGenRandom,
|
|
|
|
(HCRYPTPROV, DWORD, BYTE *));
|
|
|
|
DECL_WINDOWS_FUNCTION(static, BOOL, CryptReleaseContext,
|
|
|
|
(HCRYPTPROV, DWORD));
|
|
|
|
static HMODULE wincrypt_module = NULL;
|
|
|
|
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool win_read_random(void *buf, unsigned wanted)
|
2018-06-03 13:41:31 +00:00
|
|
|
{
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
bool toret = false;
|
2018-06-03 13:41:31 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1999-01-08 13:02:13 +00:00
|
|
|
/*
|
2013-07-20 08:34:54 +00:00
|
|
|
* This function is called once, at PuTTY startup.
|
1999-01-08 13:02:13 +00:00
|
|
|
*/
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
void noise_get_heavy(void (*func) (void *, int))
|
|
|
|
{
|
1999-01-08 13:02:13 +00:00
|
|
|
HANDLE srch;
|
|
|
|
WIN32_FIND_DATA finddata;
|
2005-04-22 15:47:28 +00:00
|
|
|
DWORD pid;
|
2001-05-06 14:35:20 +00:00
|
|
|
char winpath[MAX_PATH + 3];
|
2018-06-03 13:41:31 +00:00
|
|
|
BYTE buf[32];
|
1999-01-08 13:02:13 +00:00
|
|
|
|
|
|
|
GetWindowsDirectory(winpath, sizeof(winpath));
|
|
|
|
strcat(winpath, "\\*");
|
|
|
|
srch = FindFirstFile(winpath, &finddata);
|
|
|
|
if (srch != INVALID_HANDLE_VALUE) {
|
2019-09-08 19:29:00 +00:00
|
|
|
do {
|
|
|
|
func(&finddata, sizeof(finddata));
|
|
|
|
} while (FindNextFile(srch, &finddata));
|
|
|
|
FindClose(srch);
|
1999-01-08 13:02:13 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 15:47:28 +00:00
|
|
|
pid = GetCurrentProcessId();
|
|
|
|
func(&pid, sizeof(pid));
|
|
|
|
|
2018-06-03 13:41:31 +00:00
|
|
|
if (win_read_random(buf, sizeof(buf))) {
|
|
|
|
func(buf, sizeof(buf));
|
|
|
|
smemclr(buf, sizeof(buf));
|
2013-07-20 08:34:54 +00:00
|
|
|
}
|
|
|
|
|
2000-09-27 15:21:04 +00:00
|
|
|
read_random_seed(func);
|
1999-01-08 13:02:13 +00:00
|
|
|
}
|
|
|
|
|
2000-10-23 15:20:05 +00:00
|
|
|
/*
|
|
|
|
* This function is called on a timer, and it will monitor
|
|
|
|
* frequently changing quantities such as the state of physical and
|
|
|
|
* virtual memory, the state of the process's message queue, which
|
|
|
|
* window is in the foreground, which owns the clipboard, etc.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
void noise_regular(void)
|
|
|
|
{
|
2000-10-23 15:20:05 +00:00
|
|
|
HWND w;
|
|
|
|
DWORD z;
|
|
|
|
POINT pt;
|
|
|
|
MEMORYSTATUS memstat;
|
|
|
|
FILETIME times[4];
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
w = GetForegroundWindow();
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_FGWINDOW, &w, sizeof(w));
|
2001-05-06 14:35:20 +00:00
|
|
|
w = GetCapture();
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_CAPTURE, &w, sizeof(w));
|
2001-05-06 14:35:20 +00:00
|
|
|
w = GetClipboardOwner();
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_CLIPBOARD, &w, sizeof(w));
|
2001-05-06 14:35:20 +00:00
|
|
|
z = GetQueueStatus(QS_ALLEVENTS);
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_QUEUE, &z, sizeof(z));
|
2000-10-23 15:20:05 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
GetCursorPos(&pt);
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_CURSORPOS, &pt, sizeof(pt));
|
2000-10-23 15:20:05 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
GlobalMemoryStatus(&memstat);
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_MEMINFO, &memstat, sizeof(memstat));
|
2000-10-23 15:20:05 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
GetThreadTimes(GetCurrentThread(), times, times + 1, times + 2,
|
2019-09-08 19:29:00 +00:00
|
|
|
times + 3);
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_THREADTIME, ×, sizeof(times));
|
2001-05-06 14:35:20 +00:00
|
|
|
GetProcessTimes(GetCurrentProcess(), times, times + 1, times + 2,
|
2019-09-08 19:29:00 +00:00
|
|
|
times + 3);
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_PROCTIME, ×, sizeof(times));
|
2000-10-23 15:20:05 +00:00
|
|
|
}
|
|
|
|
|
1999-01-08 13:02:13 +00:00
|
|
|
/*
|
|
|
|
* This function is called on every keypress or mouse move, and
|
|
|
|
* will add the current Windows time and performance monitor
|
|
|
|
* counter to the noise pool. It gets the scan code or mouse
|
|
|
|
* position passed in.
|
|
|
|
*/
|
2019-01-22 18:25:54 +00:00
|
|
|
void noise_ultralight(NoiseSourceId id, unsigned long data)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
1999-01-08 13:02:13 +00:00
|
|
|
DWORD wintime;
|
|
|
|
LARGE_INTEGER perftime;
|
|
|
|
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(id, &data, sizeof(DWORD));
|
1999-01-08 13:02:13 +00:00
|
|
|
|
|
|
|
wintime = GetTickCount();
|
2019-01-22 18:25:54 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_TIME, &wintime, sizeof(DWORD));
|
1999-01-08 13:02:13 +00:00
|
|
|
|
|
|
|
if (QueryPerformanceCounter(&perftime))
|
2019-09-08 19:29:00 +00:00
|
|
|
random_add_noise(NOISE_SOURCE_PERFCOUNT, &perftime, sizeof(perftime));
|
1999-01-08 13:02:13 +00:00
|
|
|
}
|
Replace PuTTY's PRNG with a Fortuna-like system.
This tears out the entire previous random-pool system in sshrand.c. In
its place is a system pretty close to Ferguson and Schneier's
'Fortuna' generator, with the main difference being that I use SHA-256
instead of AES for the generation side of the system (rationale given
in comment).
The PRNG implementation lives in sshprng.c, and defines a self-
contained data type with no state stored outside the object, so you
can instantiate however many of them you like. The old sshrand.c still
exists, but in place of the previous random pool system, it's just
become a client of sshprng.c, whose job is to hold a single global
instance of the PRNG type, and manage its reference count, save file,
noise-collection timers and similar administrative business.
Advantages of this change include:
- Fortuna is designed with a more varied threat model in mind than my
old home-grown random pool. For example, after any request for
random numbers, it automatically re-seeds itself, so that if the
state of the PRNG should be leaked, it won't give enough
information to find out what past outputs _were_.
- The PRNG type can be instantiated with any hash function; the
instance used by the main tools is based on SHA-256, an improvement
on the old pool's use of SHA-1.
- The new PRNG only uses the completely standard interface to the
hash function API, instead of having to have privileged access to
the internal SHA-1 block transform function. This will make it
easier to revamp the hash code in general, and also it means that
hardware-accelerated versions of SHA-256 will automatically be used
for the PRNG as well as for everything else.
- The new PRNG can be _tested_! Because it has an actual (if not
quite explicit) specification for exactly what the output numbers
_ought_ to be derived from the hashes of, I can (and have) put
tests in cryptsuite that ensure the output really is being derived
in the way I think it is. The old pool could have been returning
any old nonsense and it would have been very hard to tell for sure.
2019-01-22 22:42:41 +00:00
|
|
|
|
|
|
|
uint64_t prng_reseed_time_ms(void)
|
|
|
|
{
|
|
|
|
FILETIME ft;
|
|
|
|
GetSystemTimeAsFileTime(&ft);
|
|
|
|
uint64_t value = ft.dwHighDateTime;
|
|
|
|
value = (value << 32) + ft.dwLowDateTime;
|
|
|
|
return value / 10000; /* 1 millisecond / 100ns */
|
|
|
|
}
|