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