1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-16 02:27:32 -05: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.
This commit is contained in:
Simon Tatham
2019-01-22 22:42:41 +00:00
parent 5087792440
commit 320bf8479f
13 changed files with 483 additions and 328 deletions

32
ssh.h
View File

@ -867,8 +867,6 @@ extern const char sshver[];
*/
extern bool ssh_fallback_cmd(Backend *backend);
void SHATransform(uint32_t *digest, uint32_t *data);
/*
* Check of compiler version
*/
@ -892,9 +890,35 @@ void SHATransform(uint32_t *digest, uint32_t *data);
# undef COMPILER_SUPPORTS_SHA_NI
#endif
/*
* The PRNG type, defined in sshprng.c. Visible data fields are
* 'savesize', which suggests how many random bytes you should request
* from a particular PRNG instance to write to putty.rnd, and a
* BinarySink implementation which you can use to write seed data in
* between calling prng_seed_{begin,finish}.
*/
struct prng {
size_t savesize;
BinarySink_IMPLEMENTATION;
/* (also there's a surrounding implementation struct in sshprng.c) */
};
prng *prng_new(const ssh_hashalg *hashalg);
void prng_free(prng *p);
void prng_seed_begin(prng *p);
void prng_seed_finish(prng *p);
void prng_read(prng *p, void *vout, size_t size);
void prng_add_entropy(prng *p, unsigned source_id, ptrlen data);
/* This function must be implemented by the platform, and returns a
* timer in milliseconds that the PRNG can use to know whether it's
* been reseeded too recently to do it again.
*
* The PRNG system has its own special timing function not because its
* timing needs are unusual in the real applications, but simply so
* that testcrypt can mock it to keep the tests deterministic. */
uint64_t prng_reseed_time_ms(void);
void random_read(void *out, size_t size);
void random_add_noise(void *noise, int length);
void random_add_heavynoise(void *noise, int length);
/* Exports from x11fwd.c */
enum {