yarrow.c revision 119418
1/*- 2 * Copyright (c) 2000 Mark R V Murray 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/dev/random/yarrow.c 119418 2003-08-24 17:55:58Z obrien $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kernel.h> 34#include <sys/lock.h> 35#include <sys/mutex.h> 36#include <sys/random.h> 37#include <sys/sysctl.h> 38 39#include <crypto/rijndael/rijndael.h> 40#include <crypto/sha2/sha2.h> 41 42#include <dev/random/hash.h> 43#include <dev/random/randomdev.h> 44#include <dev/random/yarrow.h> 45 46/* #define DEBUG */ 47 48RANDOM_CHECK_UINT(gengateinterval, 4, 64); 49RANDOM_CHECK_UINT(bins, 2, 16); 50RANDOM_CHECK_UINT(fastthresh, BLOCKSIZE/4, BLOCKSIZE); 51RANDOM_CHECK_UINT(slowthresh, BLOCKSIZE/4, BLOCKSIZE); 52RANDOM_CHECK_UINT(slowoverthresh, 1, 5); 53 54/* Structure holding the entropy state */ 55static struct random_state random_state; 56 57SYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters"); 58SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, gengateinterval, 59 CTLTYPE_INT|CTLFLAG_RW, &random_state.gengateinterval, 10, 60 random_check_uint_gengateinterval, "I", "Generator Gate Interval"); 61SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, bins, 62 CTLTYPE_INT|CTLFLAG_RW, &random_state.bins, 10, 63 random_check_uint_bins, "I", "Execution time tuner"); 64SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, fastthresh, 65 CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[0].thresh, (3*BLOCKSIZE)/4, 66 random_check_uint_fastthresh, "I", "Fast reseed threshold"); 67SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowthresh, 68 CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[1].thresh, BLOCKSIZE, 69 random_check_uint_slowthresh, "I", "Slow reseed threshold"); 70SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowoverthresh, 71 CTLTYPE_INT|CTLFLAG_RW, &random_state.slowoverthresh, 2, 72 random_check_uint_slowoverthresh, "I", "Slow over-threshold reseed"); 73 74static void generator_gate(void); 75static void reseed(u_int); 76 77/* The reseed thread mutex */ 78static struct mtx random_reseed_mtx; 79 80/* Process a single stochastic event off the harvest queue */ 81void 82random_process_event(struct harvest *event) 83{ 84 u_int pl, overthreshhold[2]; 85 struct source *source; 86 enum esource src; 87 88 /* Unpack the event into the appropriate source accumulator */ 89 pl = random_state.which; 90 source = &random_state.pool[pl].source[event->source]; 91 yarrow_hash_iterate(&random_state.pool[pl].hash, event->entropy, 92 sizeof(event->entropy)); 93 yarrow_hash_iterate(&random_state.pool[pl].hash, &event->somecounter, 94 sizeof(event->somecounter)); 95 source->frac += event->frac; 96 source->bits += event->bits + source->frac/1024; 97 source->frac %= 1024; 98 99 /* Count the over-threshold sources in each pool */ 100 for (pl = 0; pl < 2; pl++) { 101 overthreshhold[pl] = 0; 102 for (src = RANDOM_START; src < ENTROPYSOURCE; src++) { 103 if (random_state.pool[pl].source[src].bits 104 > random_state.pool[pl].thresh) 105 overthreshhold[pl]++; 106 } 107 } 108 109 /* if any fast source over threshhold, reseed */ 110 if (overthreshhold[FAST]) 111 reseed(FAST); 112 113 /* if enough slow sources are over threshhold, reseed */ 114 if (overthreshhold[SLOW] >= random_state.slowoverthresh) 115 reseed(SLOW); 116 117 /* Invert the fast/slow pool selector bit */ 118 random_state.which = !random_state.which; 119} 120 121void 122random_init(void) 123{ 124 int i; 125 126 /* Yarrow parameters. Do not adjust these unless you have 127 * have a very good clue about what they do! 128 */ 129 random_state.gengateinterval = 10; 130 random_state.bins = 10; 131 random_state.pool[0].thresh = (3*BLOCKSIZE)/4; 132 random_state.pool[1].thresh = BLOCKSIZE; 133 random_state.slowoverthresh = 2; 134 random_state.which = FAST; 135 136 /* Initialise the fast and slow entropy pools */ 137 for (i = 0; i < 2; i++) 138 yarrow_hash_init(&random_state.pool[i].hash); 139 140 /* Clear the counter */ 141 for (i = 0; i < 4; i++) 142 random_state.counter[i] = 0; 143 144 /* Set up a lock for the reseed process */ 145 mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF); 146} 147 148void 149random_deinit(void) 150{ 151 mtx_destroy(&random_reseed_mtx); 152} 153 154static void 155reseed(u_int fastslow) 156{ 157 /* Interrupt-context stack is a limited resource; make large 158 * structures static. 159 */ 160 static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */ 161 static struct yarrowhash context; 162 u_char hash[KEYSIZE]; /* h' */ 163 u_char temp[KEYSIZE]; 164 u_int i; 165 enum esource j; 166 167#ifdef DEBUG 168 printf("Reseed type %d\n", fastslow); 169#endif 170 171 /* The reseed task must not be jumped on */ 172 mtx_lock(&random_reseed_mtx); 173 174 /* 1. Hash the accumulated entropy into v[0] */ 175 176 yarrow_hash_init(&context); 177 /* Feed the slow pool hash in if slow */ 178 if (fastslow == SLOW) 179 yarrow_hash_iterate(&context, 180 &random_state.pool[SLOW].hash, 181 sizeof(struct yarrowhash)); 182 yarrow_hash_iterate(&context, 183 &random_state.pool[FAST].hash, sizeof(struct yarrowhash)); 184 yarrow_hash_finish(&context, v[0]); 185 186 /* 2. Compute hash values for all v. _Supposed_ to be computationally 187 * intensive. 188 */ 189 190 if (random_state.bins > TIMEBIN) 191 random_state.bins = TIMEBIN; 192 for (i = 1; i < random_state.bins; i++) { 193 yarrow_hash_init(&context); 194 /* v[i] #= h(v[i - 1]) */ 195 yarrow_hash_iterate(&context, v[i - 1], KEYSIZE); 196 /* v[i] #= h(v[0]) */ 197 yarrow_hash_iterate(&context, v[0], KEYSIZE); 198 /* v[i] #= h(i) */ 199 yarrow_hash_iterate(&context, &i, sizeof(u_int)); 200 /* Return the hashval */ 201 yarrow_hash_finish(&context, v[i]); 202 } 203 204 /* 3. Compute a new key; h' is the identity function here; 205 * it is not being ignored! 206 */ 207 208 yarrow_hash_init(&context); 209 yarrow_hash_iterate(&context, &random_state.key, KEYSIZE); 210 for (i = 1; i < random_state.bins; i++) 211 yarrow_hash_iterate(&context, &v[i], KEYSIZE); 212 yarrow_hash_finish(&context, temp); 213 yarrow_encrypt_init(&random_state.key, temp); 214 215 /* 4. Recompute the counter */ 216 217 for (i = 0; i < 4; i++) 218 random_state.counter[i] = 0; 219 yarrow_encrypt(&random_state.key, random_state.counter, temp); 220 memcpy(random_state.counter, temp, sizeof(random_state.counter)); 221 222 /* 5. Reset entropy estimate accumulators to zero */ 223 224 for (i = 0; i <= fastslow; i++) { 225 for (j = RANDOM_START; j < ENTROPYSOURCE; j++) { 226 random_state.pool[i].source[j].bits = 0; 227 random_state.pool[i].source[j].frac = 0; 228 } 229 } 230 231 /* 6. Wipe memory of intermediate values */ 232 233 memset((void *)v, 0, sizeof(v)); 234 memset((void *)temp, 0, sizeof(temp)); 235 memset((void *)hash, 0, sizeof(hash)); 236 237 /* 7. Dump to seed file */ 238 /* XXX Not done here yet */ 239 240 /* Release the reseed mutex */ 241 mtx_unlock(&random_reseed_mtx); 242 243#ifdef DEBUG 244 printf("Reseed finish\n"); 245#endif 246 247 /* Unblock the device if it was blocked due to being unseeded */ 248 random_unblock(); 249} 250 251/* Internal function to return processed entropy from the PRNG */ 252int 253read_random_real(void *buf, int count) 254{ 255 static int cur = 0; 256 static int gate = 1; 257 static u_char genval[KEYSIZE]; 258 size_t tomove; 259 int i; 260 int retval; 261 262 /* The reseed task must not be jumped on */ 263 mtx_lock(&random_reseed_mtx); 264 265 if (gate) { 266 generator_gate(); 267 random_state.outputblocks = 0; 268 gate = 0; 269 } 270 if (count > 0 && (size_t)count >= sizeof(random_state.counter)) { 271 retval = 0; 272 for (i = 0; i < count; i += (int)sizeof(random_state.counter)) { 273 random_state.counter[0]++; 274 yarrow_encrypt(&random_state.key, random_state.counter, 275 genval); 276 tomove = min(count - i, sizeof(random_state.counter)); 277 memcpy((char *)buf + i, genval, tomove); 278 if (++random_state.outputblocks >= 279 random_state.gengateinterval) { 280 generator_gate(); 281 random_state.outputblocks = 0; 282 } 283 retval += (int)tomove; 284 } 285 } 286 else { 287 if (!cur) { 288 random_state.counter[0]++; 289 yarrow_encrypt(&random_state.key, random_state.counter, 290 genval); 291 memcpy(buf, genval, (size_t)count); 292 cur = (int)sizeof(random_state.counter) - count; 293 if (++random_state.outputblocks >= 294 random_state.gengateinterval) { 295 generator_gate(); 296 random_state.outputblocks = 0; 297 } 298 retval = count; 299 } 300 else { 301 retval = cur < count ? cur : count; 302 memcpy(buf, 303 &genval[(int)sizeof(random_state.counter) - cur], 304 (size_t)retval); 305 cur -= retval; 306 } 307 } 308 mtx_unlock(&random_reseed_mtx); 309 return retval; 310} 311 312static void 313generator_gate(void) 314{ 315 u_int i; 316 u_char temp[KEYSIZE]; 317 318#ifdef DEBUG 319 printf("Generator gate\n"); 320#endif 321 322 for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) { 323 random_state.counter[0]++; 324 yarrow_encrypt(&random_state.key, random_state.counter, 325 &(temp[i])); 326 } 327 328 yarrow_encrypt_init(&random_state.key, temp); 329 memset((void *)temp, 0, KEYSIZE); 330 331#ifdef DEBUG 332 printf("Generator gate finish\n"); 333#endif 334} 335 336/* Helper routine to perform explicit reseeds */ 337void 338random_reseed(void) 339{ 340 reseed(SLOW); 341} 342