yarrow.c revision 122871
1/*- 2 * Copyright (c) 2000, 2001, 2002, 2003 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 122871 2003-11-17 23:02:21Z markm $"); 30 31#include <sys/param.h> 32#include <sys/kernel.h> 33#include <sys/lock.h> 34#include <sys/malloc.h> 35#include <sys/mutex.h> 36#include <sys/random.h> 37#include <sys/sysctl.h> 38#include <sys/systm.h> 39 40#include <crypto/rijndael/rijndael.h> 41#include <crypto/sha2/sha2.h> 42 43#include <dev/random/hash.h> 44#include <dev/random/randomdev.h> 45#include <dev/random/yarrow.h> 46 47RANDOM_CHECK_UINT(gengateinterval, 4, 64); 48RANDOM_CHECK_UINT(bins, 2, 16); 49RANDOM_CHECK_UINT(fastthresh, BLOCKSIZE/4, BLOCKSIZE); 50RANDOM_CHECK_UINT(slowthresh, BLOCKSIZE/4, BLOCKSIZE); 51RANDOM_CHECK_UINT(slowoverthresh, 1, 5); 52 53/* Structure holding the entropy state */ 54static struct random_state random_state; 55 56SYSCTL_NODE(_kern_random, OID_AUTO, yarrow, CTLFLAG_RW, 0, "Yarrow Parameters"); 57SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, gengateinterval, 58 CTLTYPE_INT|CTLFLAG_RW, &random_state.gengateinterval, 10, 59 random_check_uint_gengateinterval, "I", "Generator Gate Interval"); 60SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, bins, 61 CTLTYPE_INT|CTLFLAG_RW, &random_state.bins, 10, 62 random_check_uint_bins, "I", "Execution time tuner"); 63SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, fastthresh, 64 CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[0].thresh, (3*BLOCKSIZE)/4, 65 random_check_uint_fastthresh, "I", "Fast reseed threshold"); 66SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowthresh, 67 CTLTYPE_INT|CTLFLAG_RW, &random_state.pool[1].thresh, BLOCKSIZE, 68 random_check_uint_slowthresh, "I", "Slow reseed threshold"); 69SYSCTL_PROC(_kern_random_yarrow, OID_AUTO, slowoverthresh, 70 CTLTYPE_INT|CTLFLAG_RW, &random_state.slowoverthresh, 2, 71 random_check_uint_slowoverthresh, "I", "Slow over-threshold reseed"); 72 73static void generator_gate(void); 74static void reseed(u_int); 75 76/* The reseed thread mutex */ 77static struct mtx random_reseed_mtx; 78 79/* Process a single stochastic event off the harvest queue */ 80void 81random_process_event(struct harvest *event) 82{ 83 u_int pl, overthreshhold[2]; 84 struct source *source; 85 enum esource src; 86 87 /* Unpack the event into the appropriate source accumulator */ 88 pl = random_state.which; 89 source = &random_state.pool[pl].source[event->source]; 90 yarrow_hash_iterate(&random_state.pool[pl].hash, event->entropy, 91 sizeof(event->entropy)); 92 yarrow_hash_iterate(&random_state.pool[pl].hash, &event->somecounter, 93 sizeof(event->somecounter)); 94 source->frac += event->frac; 95 source->bits += event->bits + source->frac/1024; 96 source->frac %= 1024; 97 98 /* Count the over-threshold sources in each pool */ 99 for (pl = 0; pl < 2; pl++) { 100 overthreshhold[pl] = 0; 101 for (src = RANDOM_START; src < ENTROPYSOURCE; src++) { 102 if (random_state.pool[pl].source[src].bits 103 > random_state.pool[pl].thresh) 104 overthreshhold[pl]++; 105 } 106 } 107 108 /* if any fast source over threshhold, reseed */ 109 if (overthreshhold[FAST]) 110 reseed(FAST); 111 112 /* if enough slow sources are over threshhold, reseed */ 113 if (overthreshhold[SLOW] >= random_state.slowoverthresh) 114 reseed(SLOW); 115 116 /* Invert the fast/slow pool selector bit */ 117 random_state.which = !random_state.which; 118} 119 120void 121random_init(void) 122{ 123 int i; 124 125 /* Yarrow parameters. Do not adjust these unless you have 126 * have a very good clue about what they do! 127 */ 128 random_state.gengateinterval = 10; 129 random_state.bins = 10; 130 random_state.pool[0].thresh = (3*BLOCKSIZE)/4; 131 random_state.pool[1].thresh = BLOCKSIZE; 132 random_state.slowoverthresh = 2; 133 random_state.which = FAST; 134 135 /* Initialise the fast and slow entropy pools */ 136 for (i = 0; i < 2; i++) 137 yarrow_hash_init(&random_state.pool[i].hash); 138 139 /* Clear the counter */ 140 for (i = 0; i < 4; i++) 141 random_state.counter[i] = 0; 142 143 /* Set up a lock for the reseed process */ 144 mtx_init(&random_reseed_mtx, "random reseed", NULL, MTX_DEF); 145} 146 147void 148random_deinit(void) 149{ 150 mtx_destroy(&random_reseed_mtx); 151} 152 153static void 154reseed(u_int fastslow) 155{ 156 /* Interrupt-context stack is a limited resource; make large 157 * structures static. 158 */ 159 static u_char v[TIMEBIN][KEYSIZE]; /* v[i] */ 160 static struct yarrowhash context; 161 u_char hash[KEYSIZE]; /* h' */ 162 u_char temp[KEYSIZE]; 163 u_int i; 164 enum esource j; 165 166 /* The reseed task must not be jumped on */ 167 mtx_lock(&random_reseed_mtx); 168 169 /* 1. Hash the accumulated entropy into v[0] */ 170 171 yarrow_hash_init(&context); 172 /* Feed the slow pool hash in if slow */ 173 if (fastslow == SLOW) 174 yarrow_hash_iterate(&context, 175 &random_state.pool[SLOW].hash, 176 sizeof(struct yarrowhash)); 177 yarrow_hash_iterate(&context, 178 &random_state.pool[FAST].hash, sizeof(struct yarrowhash)); 179 yarrow_hash_finish(&context, v[0]); 180 181 /* 2. Compute hash values for all v. _Supposed_ to be computationally 182 * intensive. 183 */ 184 185 if (random_state.bins > TIMEBIN) 186 random_state.bins = TIMEBIN; 187 for (i = 1; i < random_state.bins; i++) { 188 yarrow_hash_init(&context); 189 /* v[i] #= h(v[i - 1]) */ 190 yarrow_hash_iterate(&context, v[i - 1], KEYSIZE); 191 /* v[i] #= h(v[0]) */ 192 yarrow_hash_iterate(&context, v[0], KEYSIZE); 193 /* v[i] #= h(i) */ 194 yarrow_hash_iterate(&context, &i, sizeof(u_int)); 195 /* Return the hashval */ 196 yarrow_hash_finish(&context, v[i]); 197 } 198 199 /* 3. Compute a new key; h' is the identity function here; 200 * it is not being ignored! 201 */ 202 203 yarrow_hash_init(&context); 204 yarrow_hash_iterate(&context, &random_state.key, KEYSIZE); 205 for (i = 1; i < random_state.bins; i++) 206 yarrow_hash_iterate(&context, &v[i], KEYSIZE); 207 yarrow_hash_finish(&context, temp); 208 yarrow_encrypt_init(&random_state.key, temp); 209 210 /* 4. Recompute the counter */ 211 212 for (i = 0; i < 4; i++) 213 random_state.counter[i] = 0; 214 yarrow_encrypt(&random_state.key, random_state.counter, temp); 215 memcpy(random_state.counter, temp, sizeof(random_state.counter)); 216 217 /* 5. Reset entropy estimate accumulators to zero */ 218 219 for (i = 0; i <= fastslow; i++) { 220 for (j = RANDOM_START; j < ENTROPYSOURCE; j++) { 221 random_state.pool[i].source[j].bits = 0; 222 random_state.pool[i].source[j].frac = 0; 223 } 224 } 225 226 /* 6. Wipe memory of intermediate values */ 227 228 memset((void *)v, 0, sizeof(v)); 229 memset((void *)temp, 0, sizeof(temp)); 230 memset((void *)hash, 0, sizeof(hash)); 231 232 /* 7. Dump to seed file */ 233 /* XXX Not done here yet */ 234 235 /* Release the reseed mutex */ 236 mtx_unlock(&random_reseed_mtx); 237 238 /* Unblock the device if it was blocked due to being unseeded */ 239 random_unblock(); 240} 241 242/* Internal function to return processed entropy from the PRNG */ 243int 244read_random_real(void *buf, int count) 245{ 246 static int cur = 0; 247 static int gate = 1; 248 static u_char genval[KEYSIZE]; 249 size_t tomove; 250 int i; 251 int retval; 252 253 /* The reseed task must not be jumped on */ 254 mtx_lock(&random_reseed_mtx); 255 256 if (gate) { 257 generator_gate(); 258 random_state.outputblocks = 0; 259 gate = 0; 260 } 261 if (count > 0 && (size_t)count >= sizeof(random_state.counter)) { 262 retval = 0; 263 for (i = 0; i < count; i += (int)sizeof(random_state.counter)) { 264 random_state.counter[0]++; 265 yarrow_encrypt(&random_state.key, random_state.counter, 266 genval); 267 tomove = min(count - i, sizeof(random_state.counter)); 268 memcpy((char *)buf + i, genval, tomove); 269 if (++random_state.outputblocks >= 270 random_state.gengateinterval) { 271 generator_gate(); 272 random_state.outputblocks = 0; 273 } 274 retval += (int)tomove; 275 } 276 } 277 else { 278 if (!cur) { 279 random_state.counter[0]++; 280 yarrow_encrypt(&random_state.key, random_state.counter, 281 genval); 282 memcpy(buf, genval, (size_t)count); 283 cur = (int)sizeof(random_state.counter) - count; 284 if (++random_state.outputblocks >= 285 random_state.gengateinterval) { 286 generator_gate(); 287 random_state.outputblocks = 0; 288 } 289 retval = count; 290 } 291 else { 292 retval = cur < count ? cur : count; 293 memcpy(buf, 294 &genval[(int)sizeof(random_state.counter) - cur], 295 (size_t)retval); 296 cur -= retval; 297 } 298 } 299 mtx_unlock(&random_reseed_mtx); 300 return retval; 301} 302 303static void 304generator_gate(void) 305{ 306 u_int i; 307 u_char temp[KEYSIZE]; 308 309 for (i = 0; i < KEYSIZE; i += sizeof(random_state.counter)) { 310 random_state.counter[0]++; 311 yarrow_encrypt(&random_state.key, random_state.counter, 312 &(temp[i])); 313 } 314 315 yarrow_encrypt_init(&random_state.key, temp); 316 memset((void *)temp, 0, KEYSIZE); 317 318} 319 320/* Helper routine to perform explicit reseeds */ 321void 322random_reseed(void) 323{ 324 reseed(SLOW); 325} 326