yarrow.c revision 62053
162053Smarkm/*-
262053Smarkm * Copyright (c) 2000 Mark 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 62053 2000-06-25 08:38:58Z markm $
2762053Smarkm */
2862053Smarkm
2962053Smarkm/* NOTE NOTE NOTE - This is not finished! It will supply numbers, but
3062053Smarkm                    it is not yet cryptographically secure!! */
3162053Smarkm
3262053Smarkm#include <sys/param.h>
3362053Smarkm#include <sys/systm.h>
3462053Smarkm#include <sys/queue.h>
3562053Smarkm#include <sys/linker.h>
3662053Smarkm#include <sys/libkern.h>
3762053Smarkm#include <sys/mbuf.h>
3862053Smarkm#include <sys/random.h>
3962053Smarkm#include <sys/types.h>
4062053Smarkm#include <crypto/blowfish/blowfish.h>
4162053Smarkm
4262053Smarkm#include "yarrow.h"
4362053Smarkm
4462053Smarkmvoid generator_gate(void);
4562053Smarkmvoid reseed(void);
4662053Smarkmvoid randominit(void);
4762053Smarkm
4862053Smarkm/* This is the beastie that needs protecting. It contains all of the
4962053Smarkm * state that we are excited about.
5062053Smarkm */
5162053Smarkmstruct state state;
5262053Smarkm
5362053Smarkmvoid
5462053Smarkmrandominit(void)
5562053Smarkm{
5662053Smarkm	/* XXX much more to come */
5762053Smarkm	state.gengateinterval = 10;
5862053Smarkm}
5962053Smarkm
6062053Smarkmvoid
6162053Smarkmreseed(void)
6262053Smarkm{
6362053Smarkm	unsigned char v[BINS][KEYSIZE];	/* v[i] */
6462053Smarkm	unsigned char hash[KEYSIZE];	/* h' */
6562053Smarkm	BF_KEY hashkey;
6662053Smarkm	unsigned char ivec[8];
6762053Smarkm	unsigned char temp[KEYSIZE];
6862053Smarkm	int i, j;
6962053Smarkm
7062053Smarkm	/* 1. Hash the accumulated entropy into v[0] */
7162053Smarkm
7262053Smarkm	/* XXX to be done properly */
7362053Smarkm	bzero((void *)&v[0], KEYSIZE);
7462053Smarkm	for (j = 0; j < sizeof(state.randomstuff); j += KEYSIZE) {
7562053Smarkm		BF_set_key(&hashkey, KEYSIZE, &state.randomstuff[j]);
7662053Smarkm		BF_cbc_encrypt(v[0], temp, KEYSIZE, &hashkey,
7762053Smarkm					ivec, BF_ENCRYPT);
7862053Smarkm		memcpy(&v[0], temp, KEYSIZE);
7962053Smarkm	}
8062053Smarkm
8162053Smarkm	/* 2. Compute hash values for all v. _Supposed_ to be computationally */
8262053Smarkm	/*    intensive.                                                      */
8362053Smarkm
8462053Smarkm	for (i = 1; i < BINS; i++) {
8562053Smarkm		bzero((void *)&v[i], KEYSIZE);
8662053Smarkm		for (j = 0; j < sizeof(state.randomstuff); j += KEYSIZE) {
8762053Smarkm			/* v[i] #= h(v[i-1]) */
8862053Smarkm			BF_set_key(&hashkey, KEYSIZE, v[i - 1]);
8962053Smarkm			BF_cbc_encrypt(v[i], temp, KEYSIZE, &hashkey,
9062053Smarkm						ivec, BF_ENCRYPT);
9162053Smarkm			memcpy(&v[i], temp, KEYSIZE);
9262053Smarkm			/* v[i] #= h(v[0]) */
9362053Smarkm			BF_set_key(&hashkey, KEYSIZE, v[0]);
9462053Smarkm			BF_cbc_encrypt(v[i], temp, KEYSIZE, &hashkey,
9562053Smarkm						ivec, BF_ENCRYPT);
9662053Smarkm			memcpy(&v[i], temp, KEYSIZE);
9762053Smarkm			/* v[i] #= h(i) */
9862053Smarkm			BF_set_key(&hashkey, sizeof(int), (unsigned char *)&i);
9962053Smarkm			BF_cbc_encrypt(v[i], temp, KEYSIZE, &hashkey,
10062053Smarkm						ivec, BF_ENCRYPT);
10162053Smarkm			memcpy(&v[i], temp, KEYSIZE);
10262053Smarkm		}
10362053Smarkm	}
10462053Smarkm
10562053Smarkm	/* 3. Compute a new Key. */
10662053Smarkm
10762053Smarkm	bzero((void *)hash, KEYSIZE);
10862053Smarkm	BF_set_key(&hashkey, KEYSIZE, (unsigned char *)&state.key);
10962053Smarkm	BF_cbc_encrypt(hash, temp, KEYSIZE, &hashkey,
11062053Smarkm				ivec, BF_ENCRYPT);
11162053Smarkm	memcpy(hash, temp, KEYSIZE);
11262053Smarkm	for (i = 1; i < BINS; i++) {
11362053Smarkm		BF_set_key(&hashkey, KEYSIZE, v[i]);
11462053Smarkm		BF_cbc_encrypt(hash, temp, KEYSIZE, &hashkey,
11562053Smarkm					ivec, BF_ENCRYPT);
11662053Smarkm		memcpy(hash, temp, KEYSIZE);
11762053Smarkm	}
11862053Smarkm
11962053Smarkm	BF_set_key(&state.key, KEYSIZE, hash);
12062053Smarkm
12162053Smarkm	/* 4. Recompute the counter */
12262053Smarkm
12362053Smarkm	state.counter = 0;
12462053Smarkm	BF_cbc_encrypt((unsigned char *)&state.counter, temp,
12562053Smarkm		sizeof(state.counter), &state.key, state.ivec,
12662053Smarkm		BF_ENCRYPT);
12762053Smarkm	memcpy(&state.counter, temp, state.counter);
12862053Smarkm
12962053Smarkm	/* 5. Reset all entropy estimate accumulators to zero */
13062053Smarkm
13162053Smarkm	bzero((void *)state.randomstuff, sizeof(state.randomstuff));
13262053Smarkm
13362053Smarkm	/* 6. Wipe memory of intermediate values */
13462053Smarkm
13562053Smarkm	bzero((void *)v, sizeof(v));
13662053Smarkm	bzero((void *)temp, sizeof(temp));
13762053Smarkm	bzero((void *)hash, sizeof(hash));
13862053Smarkm
13962053Smarkm	/* 7. Dump to seed file (XXX done by external process?) */
14062053Smarkm
14162053Smarkm}
14262053Smarkm
14362053Smarkmu_int
14462053Smarkmread_random(char *buf, u_int count)
14562053Smarkm{
14662053Smarkm	static int cur = 0;
14762053Smarkm	static int gate = 1;
14862053Smarkm	u_int i;
14962053Smarkm	u_int retval;
15062053Smarkm	u_int64_t genval;
15162053Smarkm
15262053Smarkm	if (gate) {
15362053Smarkm		generator_gate();
15462053Smarkm		state.outputblocks = 0;
15562053Smarkm		gate = 0;
15662053Smarkm	}
15762053Smarkm	if (count >= sizeof(state.counter)) {
15862053Smarkm		retval = 0;
15962053Smarkm		for (i = 0; i < count; i += sizeof(state.counter)) {
16062053Smarkm			state.counter++;
16162053Smarkm			BF_cbc_encrypt((unsigned char *)&state.counter,
16262053Smarkm				(unsigned char *)&genval, sizeof(state.counter),
16362053Smarkm				&state.key, state.ivec, BF_ENCRYPT);
16462053Smarkm			memcpy(&buf[i], &genval, sizeof(state.counter));
16562053Smarkm			if (++state.outputblocks >= state.gengateinterval) {
16662053Smarkm				generator_gate();
16762053Smarkm				state.outputblocks = 0;
16862053Smarkm			}
16962053Smarkm			retval += sizeof(state.counter);
17062053Smarkm		}
17162053Smarkm	}
17262053Smarkm	else {
17362053Smarkm		if (!cur) {
17462053Smarkm			state.counter++;
17562053Smarkm			BF_cbc_encrypt((unsigned char *)&state.counter,
17662053Smarkm				(unsigned char *)&genval, sizeof(state.counter),
17762053Smarkm				&state.key, state.ivec, BF_ENCRYPT);
17862053Smarkm			memcpy(buf, &genval, count);
17962053Smarkm			cur = sizeof(state.counter) - count;
18062053Smarkm			if (++state.outputblocks >= state.gengateinterval) {
18162053Smarkm				generator_gate();
18262053Smarkm				state.outputblocks = 0;
18362053Smarkm			}
18462053Smarkm			retval = count;
18562053Smarkm		}
18662053Smarkm		else {
18762053Smarkm			retval = cur < count ? cur : count;
18862053Smarkm			memcpy(buf,
18962053Smarkm				(char *)&state.counter +
19062053Smarkm					(sizeof(state.counter) - retval),
19162053Smarkm				retval);
19262053Smarkm			cur -= retval;
19362053Smarkm		}
19462053Smarkm	}
19562053Smarkm	return retval;
19662053Smarkm}
19762053Smarkm
19862053Smarkmvoid
19962053Smarkmgenerator_gate(void)
20062053Smarkm{
20162053Smarkm	int i;
20262053Smarkm	unsigned char temp[KEYSIZE];
20362053Smarkm
20462053Smarkm	for (i = 0; i < KEYSIZE; i += sizeof(state.counter)) {
20562053Smarkm		state.counter++;
20662053Smarkm		BF_cbc_encrypt((unsigned char *)&state.counter, &temp[i],
20762053Smarkm			sizeof(state.counter), &state.key, state.ivec,
20862053Smarkm			BF_ENCRYPT);
20962053Smarkm	}
21062053Smarkm
21162053Smarkm	BF_set_key(&state.key, KEYSIZE, temp);
21262053Smarkm	bzero((void *)temp, KEYSIZE);
21362053Smarkm}
214