X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/7d6ee6ff291302d003f6f6cc6d11cede050c1c87..8d90b8b27bf086da6245030459ab3e5977313eb0:/sshrand.c diff --git a/sshrand.c b/sshrand.c index 3e0a0a8b..c26fc757 100644 --- a/sshrand.c +++ b/sshrand.c @@ -2,7 +2,12 @@ * cryptographic random number generator for PuTTY's ssh client */ +#include "putty.h" #include "ssh.h" +#include + +/* Collect environmental noise every 5 minutes */ +#define NOISE_REGULAR_INTERVAL (5*60*TICKSPERSEC) void noise_get_heavy(void (*func) (void *, int)); void noise_get_light(void (*func) (void *, int)); @@ -36,19 +41,59 @@ struct RandPool { unsigned char incomingb[HASHINPUT]; int incomingpos; + + int stir_pending; }; static struct RandPool pool; -static int random_active = 0; +int random_active = 0; +long next_noise_collection; -void random_stir(void) { - word32 block[HASHINPUT/sizeof(word32)]; - word32 digest[HASHSIZE/sizeof(word32)]; +#ifdef RANDOM_DIAGNOSTICS +int random_diagnostics = 0; +#endif + +static void random_stir(void) +{ + word32 block[HASHINPUT / sizeof(word32)]; + word32 digest[HASHSIZE / sizeof(word32)]; int i, j, k; + /* + * noise_get_light will call random_add_noise, which may call + * back to here. Prevent recursive stirs. + */ + if (pool.stir_pending) + return; + pool.stir_pending = TRUE; + noise_get_light(random_add_noise); - SHATransform((word32 *)pool.incoming, (word32 *)pool.incomingb); +#ifdef RANDOM_DIAGNOSTICS + { + int p, q; + printf("random stir starting\npool:\n"); + for (p = 0; p < POOLSIZE; p += HASHSIZE) { + printf(" "); + for (q = 0; q < HASHSIZE; q += 4) { + printf(" %08x", *(word32 *)(pool.pool + p + q)); + } + printf("\n"); + } + printf("incoming:\n "); + for (q = 0; q < HASHSIZE; q += 4) { + printf(" %08x", *(word32 *)(pool.incoming + q)); + } + printf("\nincomingb:\n "); + for (q = 0; q < HASHINPUT; q += 4) { + printf(" %08x", *(word32 *)(pool.incomingb + q)); + } + printf("\n"); + random_diagnostics++; + } +#endif + + SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb); pool.incomingpos = 0; /* @@ -77,14 +122,14 @@ void random_stir(void) { * things will be that much less predictable that way * round, when we subsequently return bytes ... */ - for (j = POOLSIZE; (j -= HASHSIZE) >= 0 ;) { + for (j = POOLSIZE; (j -= HASHSIZE) >= 0;) { /* * XOR the bit of the pool we're processing into the * digest. */ - for (k = 0; k < sizeof(digest)/sizeof(*digest); k++) - digest[k] ^= ((word32 *)(pool.pool+j))[k]; + for (k = 0; k < sizeof(digest) / sizeof(*digest); k++) + digest[k] ^= ((word32 *) (pool.pool + j))[k]; /* * Munge our unrevealed first block of the pool into @@ -96,9 +141,32 @@ void random_stir(void) { * Stick the result back into the pool. */ - for (k = 0; k < sizeof(digest)/sizeof(*digest); k++) - ((word32 *)(pool.pool+j))[k] = digest[k]; + for (k = 0; k < sizeof(digest) / sizeof(*digest); k++) + ((word32 *) (pool.pool + j))[k] = digest[k]; } + +#ifdef RANDOM_DIAGNOSTICS + if (i == 0) { + int p, q; + printf("random stir midpoint\npool:\n"); + for (p = 0; p < POOLSIZE; p += HASHSIZE) { + printf(" "); + for (q = 0; q < HASHSIZE; q += 4) { + printf(" %08x", *(word32 *)(pool.pool + p + q)); + } + printf("\n"); + } + printf("incoming:\n "); + for (q = 0; q < HASHSIZE; q += 4) { + printf(" %08x", *(word32 *)(pool.incoming + q)); + } + printf("\nincomingb:\n "); + for (q = 0; q < HASHINPUT; q += 4) { + printf(" %08x", *(word32 *)(pool.incomingb + q)); + } + printf("\n"); + } +#endif } /* @@ -109,14 +177,41 @@ void random_stir(void) { memcpy(pool.incoming, digest, sizeof(digest)); pool.poolpos = sizeof(pool.incoming); + + pool.stir_pending = FALSE; + +#ifdef RANDOM_DIAGNOSTICS + { + int p, q; + printf("random stir done\npool:\n"); + for (p = 0; p < POOLSIZE; p += HASHSIZE) { + printf(" "); + for (q = 0; q < HASHSIZE; q += 4) { + printf(" %08x", *(word32 *)(pool.pool + p + q)); + } + printf("\n"); + } + printf("incoming:\n "); + for (q = 0; q < HASHSIZE; q += 4) { + printf(" %08x", *(word32 *)(pool.incoming + q)); + } + printf("\nincomingb:\n "); + for (q = 0; q < HASHINPUT; q += 4) { + printf(" %08x", *(word32 *)(pool.incomingb + q)); + } + printf("\n"); + random_diagnostics--; + } +#endif } -void random_add_noise(void *noise, int length) { +void random_add_noise(void *noise, int length) +{ unsigned char *p = noise; int i; if (!random_active) - return; + return; /* * This function processes HASHINPUT bytes into only HASHSIZE @@ -128,14 +223,14 @@ void random_add_noise(void *noise, int length) { HASHINPUT - pool.incomingpos); p += HASHINPUT - pool.incomingpos; length -= HASHINPUT - pool.incomingpos; - SHATransform((word32 *)pool.incoming, (word32 *)pool.incomingb); - for (i = 0; i < HASHSIZE; i++) { - pool.pool[pool.poolpos++] ^= pool.incomingb[i]; - if (pool.poolpos >= POOLSIZE) - pool.poolpos = 0; - } - if (pool.poolpos < HASHSIZE) - random_stir(); + SHATransform((word32 *) pool.incoming, (word32 *) pool.incomingb); + for (i = 0; i < HASHSIZE; i++) { + pool.pool[pool.poolpos++] ^= pool.incomingb[i]; + if (pool.poolpos >= POOLSIZE) + pool.poolpos = 0; + } + if (pool.poolpos < HASHSIZE) + random_stir(); pool.incomingpos = 0; } @@ -144,56 +239,91 @@ void random_add_noise(void *noise, int length) { pool.incomingpos += length; } -void random_add_heavynoise(void *noise, int length) { +void random_add_heavynoise(void *noise, int length) +{ unsigned char *p = noise; int i; while (length >= POOLSIZE) { - for (i = 0; i < POOLSIZE; i++) - pool.pool[i] ^= *p++; + for (i = 0; i < POOLSIZE; i++) + pool.pool[i] ^= *p++; random_stir(); length -= POOLSIZE; } for (i = 0; i < length; i++) - pool.pool[i] ^= *p++; + pool.pool[i] ^= *p++; random_stir(); } -static void random_add_heavynoise_bitbybit(void *noise, int length) { +static void random_add_heavynoise_bitbybit(void *noise, int length) +{ unsigned char *p = noise; int i; while (length >= POOLSIZE - pool.poolpos) { - for (i = 0; i < POOLSIZE - pool.poolpos; i++) - pool.pool[pool.poolpos + i] ^= *p++; + for (i = 0; i < POOLSIZE - pool.poolpos; i++) + pool.pool[pool.poolpos + i] ^= *p++; random_stir(); length -= POOLSIZE - pool.poolpos; - pool.poolpos = 0; + pool.poolpos = 0; } for (i = 0; i < length; i++) - pool.pool[i] ^= *p++; + pool.pool[i] ^= *p++; pool.poolpos = i; } -void random_init(void) { - memset(&pool, 0, sizeof(pool)); /* just to start with */ +static void random_timer(void *ctx, unsigned long now) +{ + if (random_active > 0 && now == next_noise_collection) { + noise_regular(); + next_noise_collection = + schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool); + } +} - random_active = 1; +void random_ref(void) +{ + if (!random_active) { + memset(&pool, 0, sizeof(pool)); /* just to start with */ - noise_get_heavy(random_add_heavynoise_bitbybit); + random_active++; + + noise_get_heavy(random_add_heavynoise_bitbybit); + random_stir(); + + next_noise_collection = + schedule_timer(NOISE_REGULAR_INTERVAL, random_timer, &pool); + } } -int random_byte(void) { +void random_unref(void) +{ + assert(random_active > 0); + if (random_active == 1) { + random_save_seed(); + expire_timer_context(&pool); + } + random_active--; +} + +int random_byte(void) +{ + assert(random_active); + if (pool.poolpos >= POOLSIZE) random_stir(); return pool.pool[pool.poolpos++]; } -void random_get_savedata(void **data, int *len) { +void random_get_savedata(void **data, int *len) +{ + void *buf = snewn(POOLSIZE / 2, char); + random_stir(); + memcpy(buf, pool.pool + pool.poolpos, POOLSIZE / 2); + *len = POOLSIZE / 2; + *data = buf; random_stir(); - *data = pool.pool+pool.poolpos; - *len = POOLSIZE/2; }