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