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