yarrow.c revision 67112
162053Smarkm/*-
262765Smarkm * Copyright (c) 2000 Mark R V Murray
362053Smarkm * All rights reserved.
462053Smarkm *
562053Smarkm * Redistribution and use in source and binary forms, with or without
662053Smarkm * modification, are permitted provided that the following conditions
762053Smarkm * are met:
862053Smarkm * 1. Redistributions of source code must retain the above copyright
962053Smarkm *    notice, this list of conditions and the following disclaimer
1062053Smarkm *    in this position and unchanged.
1162053Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1262053Smarkm *    notice, this list of conditions and the following disclaimer in the
1362053Smarkm *    documentation and/or other materials provided with the distribution.
1462053Smarkm *
1562053Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1662053Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1762053Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1862053Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1962053Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2062053Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2162053Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2262053Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2362053Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2462053Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2562053Smarkm *
2662053Smarkm * $FreeBSD: head/sys/dev/random/yarrow.c 67112 2000-10-14 10:59:56Z markm $
2762053Smarkm */
2862053Smarkm
2962053Smarkm/* NOTE NOTE NOTE - This is not finished! It will supply numbers, but
3063771Smarkm *                  it is not yet cryptographically secure!!
3163771Smarkm */
3262053Smarkm
3362053Smarkm#include <sys/param.h>
3462053Smarkm#include <sys/systm.h>
3562053Smarkm#include <sys/queue.h>
3665686Smarkm#include <sys/kernel.h>
3765686Smarkm#include <sys/kthread.h>
3862053Smarkm#include <sys/libkern.h>
3965686Smarkm#include <sys/malloc.h>
4065686Smarkm#include <sys/proc.h>
4167112Smarkm#include <sys/select.h>
4262053Smarkm#include <sys/random.h>
4362765Smarkm#include <sys/time.h>
4462053Smarkm#include <sys/types.h>
4565712Sjhb#include <sys/unistd.h>
4665686Smarkm#include <machine/mutex.h>
4762053Smarkm#include <crypto/blowfish/blowfish.h>
4862053Smarkm
4967112Smarkm#include <dev/random/hash.h>
5067112Smarkm#include <dev/random/yarrow.h>
5162053Smarkm
5262765Smarkm/* #define DEBUG */
5365686Smarkm/* #define DEBUG1 */	/* Very noisy - prints plenty harvesting stats */
5462053Smarkm
5562765Smarkmstatic void generator_gate(void);
5662765Smarkmstatic void reseed(int);
5763855Smarkmstatic void random_harvest_internal(struct timespec *, void *, u_int, u_int, u_int, enum esource);
5862053Smarkm
5965686Smarkmstatic void random_kthread(void *);
6065686Smarkm
6162765Smarkm/* Structure holding the entropy state */
6262765Smarkmstruct random_state random_state;
6362765Smarkm
6465686Smarkm/* Queue holding harvested entropy */
6565686SmarkmTAILQ_HEAD(harvestqueue, harvest) harvestqueue,
6665686Smarkm	initqueue = TAILQ_HEAD_INITIALIZER(harvestqueue);
6765686Smarkm
6865686Smarkm/* These are used to queue harvested packets of entropy. The entropy
6967112Smarkm * buffer size is pretty arbitrary.
7063771Smarkm */
7165686Smarkmstruct harvest {
7265686Smarkm	struct timespec time;		/* nanotime for clock jitter */
7367112Smarkm	u_char entropy[HARVESTSIZE];	/* the harvested entropy */
7465686Smarkm	u_int size, bits, frac;		/* stats about the entropy */
7565686Smarkm	enum esource source;		/* stats about the entropy */
7665686Smarkm	u_int pool;			/* which pool this goes into */
7765686Smarkm	TAILQ_ENTRY(harvest) harvest;	/* link to next */
7865686Smarkm};
7962765Smarkm
8065686Smarkm/* The reseed thread mutex */
8165856Sjhbstatic struct mtx random_reseed_mtx;
8262765Smarkm
8367112Smarkm/* The entropy harvest mutex, as well as the mutex associated
8467112Smarkm * with the msleep() call during deinit
8567112Smarkm */
8665856Sjhbstatic struct mtx random_harvest_mtx;
8765686Smarkm
8865686Smarkm/* <0 to end the kthread, 0 to let it run */
8965686Smarkmstatic int random_kthread_control = 0;
9065686Smarkm
9165686Smarkmstatic struct proc *random_kthread_proc;
9265686Smarkm
9362765Smarkmstatic void
9467112Smarkmrandom_kthread(void *arg /* NOTUSED */)
9562765Smarkm{
9665686Smarkm	int pl, src, overthreshhold[2];
9765686Smarkm	struct harvest *event;
9865686Smarkm	struct source *source;
9965686Smarkm#ifdef DEBUG1
10065686Smarkm	int queuecount;
10165686Smarkm#endif
10265686Smarkm
10362765Smarkm#ifdef DEBUG
10467112Smarkm	printf("At %s, line %d: mtx_owned(&Giant) == %d, mtx_owned(&sched_lock) == %d\n", __FILE__, __LINE__, mtx_owned(&Giant), mtx_owned(&sched_lock));
10562765Smarkm#endif
10665686Smarkm
10765686Smarkm	for (pl = 0; pl < 2; pl++)
10865686Smarkm		yarrow_hash_init(&random_state.pool[pl].hash, NULL, 0);
10965686Smarkm
11065686Smarkm	for (;;) {
11165686Smarkm
11265686Smarkm		if (TAILQ_EMPTY(&harvestqueue)) {
11365686Smarkm
11465686Smarkm			/* Sleep for a second to give the system a chance */
11565686Smarkm			mtx_enter(&Giant, MTX_DEF);
11665686Smarkm			tsleep(&harvestqueue, PUSER, "rndslp", hz);
11765686Smarkm			mtx_exit(&Giant, MTX_DEF);
11865686Smarkm
11965686Smarkm		}
12065686Smarkm		else {
12165686Smarkm
12265686Smarkm			/* Suck the harvested entropy out of the queue and hash
12365686Smarkm			 * it into the fast and slow pools.
12465686Smarkm			 */
12565686Smarkm#ifdef DEBUG1
12665686Smarkm			queuecount = 0;
12765686Smarkm#endif
12865712Sjhb			while (!TAILQ_EMPTY(&harvestqueue)) {
12965686Smarkm#ifdef DEBUG1
13065686Smarkm				queuecount++;
13165686Smarkm#endif
13265686Smarkm				mtx_enter(&random_harvest_mtx, MTX_DEF);
13365686Smarkm
13465686Smarkm				event = TAILQ_FIRST(&harvestqueue);
13565686Smarkm				TAILQ_REMOVE(&harvestqueue, event, harvest);
13665686Smarkm
13765686Smarkm				mtx_exit(&random_harvest_mtx, MTX_DEF);
13865686Smarkm
13965686Smarkm				source = &random_state.pool[event->pool].source[event->source];
14065686Smarkm				yarrow_hash_iterate(&random_state.pool[event->pool].hash,
14165686Smarkm					event->entropy, sizeof(event->entropy));
14265686Smarkm				yarrow_hash_iterate(&random_state.pool[event->pool].hash,
14365686Smarkm					&event->time, sizeof(event->time));
14465686Smarkm				source->frac += event->frac;
14565686Smarkm				source->bits += event->bits + source->frac/1024;
14665686Smarkm				source->frac %= 1024;
14765686Smarkm				free(event, M_TEMP);
14865686Smarkm
14965686Smarkm			}
15065686Smarkm#ifdef DEBUG1
15165686Smarkm			printf("Harvested %d events\n", queuecount);
15265686Smarkm#endif
15365686Smarkm
15465686Smarkm			/* Count the over-threshold sources in each pool */
15565686Smarkm			for (pl = 0; pl < 2; pl++) {
15665686Smarkm				overthreshhold[pl] = 0;
15765686Smarkm				for (src = 0; src < ENTROPYSOURCE; src++) {
15865686Smarkm					if (random_state.pool[pl].source[src].bits
15965686Smarkm						> random_state.pool[pl].thresh)
16065686Smarkm						overthreshhold[pl]++;
16165686Smarkm				}
16265686Smarkm			}
16365686Smarkm
16465686Smarkm			/* if any fast source over threshhold, reseed */
16565686Smarkm			if (overthreshhold[FAST])
16665686Smarkm				reseed(FAST);
16765686Smarkm
16865686Smarkm			/* if enough slow sources are over threshhold, reseed */
16965686Smarkm			if (overthreshhold[SLOW] >= random_state.slowoverthresh)
17065686Smarkm				reseed(SLOW);
17165686Smarkm
17265686Smarkm		}
17365686Smarkm
17465686Smarkm		/* Is the thread scheduled for a shutdown? */
17567112Smarkm		if (random_kthread_control != 0) {
17665686Smarkm			if (!TAILQ_EMPTY(&harvestqueue)) {
17765686Smarkm#ifdef DEBUG
17865686Smarkm				printf("Random cleaning extraneous events\n");
17965686Smarkm#endif
18065686Smarkm				mtx_enter(&random_harvest_mtx, MTX_DEF);
18165686Smarkm				TAILQ_FOREACH(event, &harvestqueue, harvest) {
18265686Smarkm					TAILQ_REMOVE(&harvestqueue, event, harvest);
18365686Smarkm					free(event, M_TEMP);
18465686Smarkm				}
18565686Smarkm				mtx_exit(&random_harvest_mtx, MTX_DEF);
18665686Smarkm			}
18765686Smarkm#ifdef DEBUG
18865686Smarkm			printf("Random kthread setting terminate\n");
18965686Smarkm#endif
19067112Smarkm			random_set_wakeup_exit(&random_kthread_control);
19167112Smarkm			/* NOTREACHED */
19265686Smarkm			break;
19365686Smarkm		}
19465686Smarkm
19565686Smarkm	}
19665686Smarkm
19762765Smarkm}
19862765Smarkm
19965686Smarkmint
20062765Smarkmrandom_init(void)
20162053Smarkm{
20265686Smarkm	int error;
20365686Smarkm
20462765Smarkm#ifdef DEBUG
20565686Smarkm	printf("Random initialise\n");
20662765Smarkm#endif
20765686Smarkm
20862765Smarkm	random_state.gengateinterval = 10;
20962765Smarkm	random_state.bins = 10;
21062765Smarkm	random_state.pool[0].thresh = 100;
21162765Smarkm	random_state.pool[1].thresh = 160;
21262765Smarkm	random_state.slowoverthresh = 2;
21362765Smarkm	random_state.which = FAST;
21465686Smarkm
21565686Smarkm	harvestqueue = initqueue;
21665686Smarkm
21765686Smarkm	/* Initialise the mutexes */
21865686Smarkm	mtx_init(&random_reseed_mtx, "random reseed", MTX_DEF);
21965686Smarkm	mtx_init(&random_harvest_mtx, "random harvest", MTX_DEF);
22065686Smarkm
22165686Smarkm	/* Start the hash/reseed thread */
22267112Smarkm	error = kthread_create(random_kthread, NULL,
22365712Sjhb		&random_kthread_proc, RFHIGHPID, "random");
22465686Smarkm	if (error != 0)
22565686Smarkm		return error;
22665686Smarkm
22765686Smarkm	/* Register the randomness harvesting routine */
22867112Smarkm	random_init_harvester(random_harvest_internal, read_random_real);
22965686Smarkm
23065686Smarkm#ifdef DEBUG
23165686Smarkm	printf("Random initalise finish\n");
23265686Smarkm#endif
23365686Smarkm
23465686Smarkm	return 0;
23562053Smarkm}
23662053Smarkm
23762053Smarkmvoid
23862765Smarkmrandom_deinit(void)
23962053Smarkm{
24062765Smarkm#ifdef DEBUG
24165686Smarkm	printf("Random deinitalise\n");
24262765Smarkm#endif
24365686Smarkm
24465686Smarkm	/* Deregister the randomness harvesting routine */
24562765Smarkm	random_deinit_harvester();
24665686Smarkm
24765686Smarkm#ifdef DEBUG
24865686Smarkm	printf("Random deinitalise waiting for thread to terminate\n");
24965686Smarkm#endif
25065686Smarkm
25165686Smarkm	/* Command the hash/reseed thread to end and wait for it to finish */
25267112Smarkm	mtx_enter(&random_harvest_mtx, MTX_DEF);
25365686Smarkm	random_kthread_control = -1;
25467112Smarkm	msleep((void *)&random_kthread_control, &random_harvest_mtx, PUSER,
25567112Smarkm		"rndend", 0);
25667112Smarkm	mtx_exit(&random_harvest_mtx, MTX_DEF);
25765686Smarkm
25865686Smarkm#ifdef DEBUG
25965686Smarkm	printf("Random deinitalise removing mutexes\n");
26065686Smarkm#endif
26165686Smarkm
26265686Smarkm	/* Remove the mutexes */
26365686Smarkm	mtx_destroy(&random_reseed_mtx);
26465686Smarkm	mtx_destroy(&random_harvest_mtx);
26565686Smarkm
26665686Smarkm#ifdef DEBUG
26765686Smarkm	printf("Random deinitalise finish\n");
26865686Smarkm#endif
26962765Smarkm}
27062765Smarkm
27162765Smarkmstatic void
27262765Smarkmreseed(int fastslow)
27362765Smarkm{
27465686Smarkm	/* Interrupt-context stack is a limited resource; make large
27565686Smarkm	 * structures static.
27663771Smarkm	 */
27765686Smarkm	static u_char v[TIMEBIN][KEYSIZE];	/* v[i] */
27865686Smarkm	static struct yarrowhash context;
27965686Smarkm	u_char hash[KEYSIZE];			/* h' */
28065686Smarkm	u_char temp[KEYSIZE];
28162053Smarkm	int i, j;
28262053Smarkm
28362765Smarkm#ifdef DEBUG
28462765Smarkm	printf("Reseed type %d\n", fastslow);
28562765Smarkm#endif
28662765Smarkm
28765686Smarkm	/* The reseed task must not be jumped on */
28865686Smarkm	mtx_enter(&random_reseed_mtx, MTX_DEF);
28965686Smarkm
29062053Smarkm	/* 1. Hash the accumulated entropy into v[0] */
29162053Smarkm
29265686Smarkm	yarrow_hash_init(&context, NULL, 0);
29365686Smarkm	/* Feed the slow pool hash in if slow */
29465686Smarkm	if (fastslow == SLOW)
29565686Smarkm		yarrow_hash_iterate(&context,
29665686Smarkm			&random_state.pool[SLOW].hash, sizeof(struct yarrowhash));
29762053Smarkm
29865686Smarkm	yarrow_hash_iterate(&context,
29965686Smarkm		&random_state.pool[FAST].hash, sizeof(struct yarrowhash));
30062765Smarkm
30163771Smarkm	/* 2. Compute hash values for all v. _Supposed_ to be computationally
30263771Smarkm	 *    intensive.
30363771Smarkm	 */
30462053Smarkm
30562765Smarkm	if (random_state.bins > TIMEBIN)
30662765Smarkm		random_state.bins = TIMEBIN;
30762765Smarkm	for (i = 1; i < random_state.bins; i++) {
30865686Smarkm		yarrow_hash_init(&context, NULL, 0);
30962765Smarkm		/* v[i] #= h(v[i-1]) */
31065686Smarkm		yarrow_hash_iterate(&context, v[i - 1], KEYSIZE);
31162765Smarkm		/* v[i] #= h(v[0]) */
31265686Smarkm		yarrow_hash_iterate(&context, v[0], KEYSIZE);
31362765Smarkm		/* v[i] #= h(i) */
31465686Smarkm		yarrow_hash_iterate(&context, &i, sizeof(int));
31565686Smarkm		/* Return the hashval */
31665686Smarkm		yarrow_hash_finish(&context, v[i]);
31762053Smarkm	}
31862053Smarkm
31965686Smarkm	/* 3. Compute a new key; h' is the identity function here;
32065686Smarkm	 *    it is not being ignored!
32165686Smarkm	 */
32262053Smarkm
32365686Smarkm	yarrow_hash_init(&context, NULL, 0);
32465686Smarkm	yarrow_hash_iterate(&context, &random_state.key, KEYSIZE);
32565686Smarkm	for (i = 1; i < random_state.bins; i++)
32665686Smarkm		yarrow_hash_iterate(&context, &v[i], KEYSIZE);
32765686Smarkm	yarrow_hash_finish(&context, temp);
32865686Smarkm	yarrow_encrypt_init(&random_state.key, temp, KEYSIZE);
32962053Smarkm
33062053Smarkm	/* 4. Recompute the counter */
33162053Smarkm
33262765Smarkm	random_state.counter = 0;
33365686Smarkm	yarrow_encrypt(&random_state.key, &random_state.counter, temp,
33465686Smarkm		sizeof(random_state.counter));
33562765Smarkm	memcpy(&random_state.counter, temp, random_state.counter);
33662053Smarkm
33762765Smarkm	/* 5. Reset entropy estimate accumulators to zero */
33862053Smarkm
33962765Smarkm	for (i = 0; i <= fastslow; i++) {
34062765Smarkm		for (j = 0; j < ENTROPYSOURCE; j++) {
34165686Smarkm			if (random_state.pool[i].source[j].bits >
34265686Smarkm				random_state.pool[i].thresh) {
34365686Smarkm				random_state.pool[i].source[j].bits = 0;
34465686Smarkm				random_state.pool[i].source[j].frac = 0;
34565686Smarkm			}
34662765Smarkm		}
34762765Smarkm	}
34862053Smarkm
34962053Smarkm	/* 6. Wipe memory of intermediate values */
35062053Smarkm
35165686Smarkm	memset((void *)v, 0, sizeof(v));
35265686Smarkm	memset((void *)temp, 0, sizeof(temp));
35365686Smarkm	memset((void *)hash, 0, sizeof(hash));
35462053Smarkm
35565686Smarkm	/* 7. Dump to seed file */
35665686Smarkm	/* XXX Not done here yet */
35762053Smarkm
35865686Smarkm	/* Release the reseed mutex */
35965686Smarkm	mtx_exit(&random_reseed_mtx, MTX_DEF);
36065686Smarkm
36165686Smarkm#ifdef DEBUG
36265686Smarkm	printf("Reseed finish\n");
36365686Smarkm#endif
36465686Smarkm
36567112Smarkm	if (!random_state.seeded) {
36667112Smarkm		random_state.seeded = 1;
36767112Smarkm		selwakeup(&random_state.rsel);
36867112Smarkm		wakeup(&random_state);
36967112Smarkm	}
37067112Smarkm
37162053Smarkm}
37262053Smarkm
37362053Smarkmu_int
37467112Smarkmread_random_real(void *buf, u_int count)
37562053Smarkm{
37663855Smarkm	static u_int64_t genval;
37762053Smarkm	static int cur = 0;
37862053Smarkm	static int gate = 1;
37962053Smarkm	u_int i;
38062053Smarkm	u_int retval;
38162053Smarkm
38262875Smarkm	/* The reseed task must not be jumped on */
38365686Smarkm	mtx_enter(&random_reseed_mtx, MTX_DEF);
38462875Smarkm
38562053Smarkm	if (gate) {
38662053Smarkm		generator_gate();
38762765Smarkm		random_state.outputblocks = 0;
38862053Smarkm		gate = 0;
38962053Smarkm	}
39062765Smarkm	if (count >= sizeof(random_state.counter)) {
39162053Smarkm		retval = 0;
39262765Smarkm		for (i = 0; i < count; i += sizeof(random_state.counter)) {
39362765Smarkm			random_state.counter++;
39465686Smarkm			yarrow_encrypt(&random_state.key, &random_state.counter,
39565686Smarkm				&genval, sizeof(random_state.counter));
39663855Smarkm			memcpy((char *)buf + i, &genval,
39763855Smarkm				sizeof(random_state.counter));
39862765Smarkm			if (++random_state.outputblocks >= random_state.gengateinterval) {
39962053Smarkm				generator_gate();
40062765Smarkm				random_state.outputblocks = 0;
40162053Smarkm			}
40262765Smarkm			retval += sizeof(random_state.counter);
40362053Smarkm		}
40462053Smarkm	}
40562053Smarkm	else {
40662053Smarkm		if (!cur) {
40762765Smarkm			random_state.counter++;
40865686Smarkm			yarrow_encrypt(&random_state.key, &random_state.counter,
40965686Smarkm				&genval, sizeof(random_state.counter));
41062053Smarkm			memcpy(buf, &genval, count);
41162765Smarkm			cur = sizeof(random_state.counter) - count;
41262765Smarkm			if (++random_state.outputblocks >= random_state.gengateinterval) {
41362053Smarkm				generator_gate();
41462765Smarkm				random_state.outputblocks = 0;
41562053Smarkm			}
41662053Smarkm			retval = count;
41762053Smarkm		}
41862053Smarkm		else {
41962053Smarkm			retval = cur < count ? cur : count;
42062053Smarkm			memcpy(buf,
42163855Smarkm				(char *)&genval +
42263855Smarkm					(sizeof(random_state.counter) - cur),
42362053Smarkm				retval);
42462053Smarkm			cur -= retval;
42562053Smarkm		}
42662053Smarkm	}
42765686Smarkm	mtx_exit(&random_reseed_mtx, MTX_DEF);
42862053Smarkm	return retval;
42962053Smarkm}
43062053Smarkm
43163306Smarkmvoid
43263855Smarkmwrite_random(void *buf, u_int count)
43363306Smarkm{
43463306Smarkm	u_int i;
43563771Smarkm	struct timespec timebuf;
43663306Smarkm
43767112Smarkm	/* arbitrarily break the input up into HARVESTSIZE chunks */
43867112Smarkm	for (i = 0; i < count; i += HARVESTSIZE) {
43963771Smarkm		nanotime(&timebuf);
44067112Smarkm		random_harvest_internal(&timebuf, (char *)buf + i, HARVESTSIZE, 0, 0,
44163855Smarkm			RANDOM_WRITE);
44263306Smarkm	}
44365686Smarkm
44463855Smarkm	/* Maybe the loop iterated at least once */
44563855Smarkm	if (i > count)
44667112Smarkm		i -= HARVESTSIZE;
44765686Smarkm
44867112Smarkm	/* Get the last bytes even if the input length is not a multiple of HARVESTSIZE */
44967112Smarkm	count %= HARVESTSIZE;
45063855Smarkm	if (count) {
45163855Smarkm		nanotime(&timebuf);
45263855Smarkm		random_harvest_internal(&timebuf, (char *)buf + i, count, 0, 0,
45363855Smarkm			RANDOM_WRITE);
45463855Smarkm	}
45565686Smarkm
45665686Smarkm	/* Explicit reseed */
45763306Smarkm	reseed(FAST);
45863306Smarkm}
45963306Smarkm
46062765Smarkmstatic void
46162053Smarkmgenerator_gate(void)
46262053Smarkm{
46362053Smarkm	int i;
46465686Smarkm	u_char temp[KEYSIZE];
46562053Smarkm
46662765Smarkm#ifdef DEBUG
46762875Smarkm	printf("Generator gate\n");
46862765Smarkm#endif
46962875Smarkm
47062765Smarkm	for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) {
47162765Smarkm		random_state.counter++;
47265686Smarkm		yarrow_encrypt(&random_state.key, &random_state.counter,
47365686Smarkm			&(temp[i]), sizeof(random_state.counter));
47462053Smarkm	}
47562053Smarkm
47665686Smarkm	yarrow_encrypt_init(&random_state.key, temp, KEYSIZE);
47765686Smarkm	memset((void *)temp, 0, KEYSIZE);
47862875Smarkm
47965686Smarkm#ifdef DEBUG
48065686Smarkm	printf("Generator gate finish\n");
48165686Smarkm#endif
48262053Smarkm}
48362765Smarkm
48463771Smarkm/* Entropy harvesting routine. This is supposed to be fast; do
48563771Smarkm * not do anything slow in here!
48663771Smarkm */
48762765Smarkm
48862765Smarkmstatic void
48963855Smarkmrandom_harvest_internal(struct timespec *timep, void *entropy, u_int count,
49062841Smarkm	u_int bits, u_int frac, enum esource origin)
49162765Smarkm{
49265686Smarkm	struct harvest *event;
49362765Smarkm
49465686Smarkm#if 0
49562765Smarkm#ifdef DEBUG
49662765Smarkm	printf("Random harvest\n");
49762765Smarkm#endif
49865686Smarkm#endif
49965686Smarkm	event = malloc(sizeof(struct harvest), M_TEMP, M_NOWAIT);
50062765Smarkm
50165686Smarkm	if (origin < ENTROPYSOURCE && event != NULL) {
50262850Smarkm
50365686Smarkm		/* nanotime provides clock jitter */
50465686Smarkm		event->time = *timep;
50562765Smarkm
50665686Smarkm		/* the harvested entropy */
50767112Smarkm		count = count > sizeof(event->entropy)
50867112Smarkm			? sizeof(event->entropy)
50965686Smarkm			: count;
51065686Smarkm		memcpy(event->entropy, entropy, count);
51162765Smarkm
51265686Smarkm		event->size = count;
51365686Smarkm		event->bits = bits;
51465686Smarkm		event->frac = frac;
51565686Smarkm		event->source = origin;
51662765Smarkm
51765686Smarkm		/* protect the queue from simultaneous updates */
51865686Smarkm		mtx_enter(&random_harvest_mtx, MTX_DEF);
51962765Smarkm
52065686Smarkm		/* toggle the pool for next insertion */
52165686Smarkm		event->pool = random_state.which;
52265686Smarkm		random_state.which = !random_state.which;
52362765Smarkm
52465686Smarkm		TAILQ_INSERT_TAIL(&harvestqueue, event, harvest);
52562765Smarkm
52665686Smarkm		mtx_exit(&random_harvest_mtx, MTX_DEF);
52762765Smarkm	}
52862765Smarkm}
529