1 /*- 2 * Copyright (c) 2013-2015 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 /* 29 * This implementation of Fortuna is based on the descriptions found in 30 * ISBN 978-0-470-47424-2 "Cryptography Engineering" by Ferguson, Schneier 31 * and Kohno ("FS&K"). 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/limits.h> 38 39 #ifdef _KERNEL 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/conf.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/module.h> 46 #include <sys/mutex.h> 47 #include <sys/random.h> 48 #include <sys/sysctl.h> 49 #include <sys/systm.h> 50 51 #include <machine/cpu.h> 52 53 #include <crypto/rijndael/rijndael-api-fst.h> 54 #include <crypto/sha2/sha2.h> 55 56 #include <dev/random/hash.h> 57 #include <dev/random/randomdev.h> 58 #include <dev/random/random_harvestq.h> 59 #include <dev/random/uint128.h> 60 #include <dev/random/fortuna.h> 61 #else /* !_KERNEL */ 62 #include <inttypes.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <threads.h> 67 68 #include "unit_test.h" 69 70 #include <crypto/rijndael/rijndael-api-fst.h> 71 #include <crypto/sha2/sha2.h> 72 73 #include <dev/random/hash.h> 74 #include <dev/random/uint128.h> 75 #include <dev/random/fortuna.h> 76 #endif /* _KERNEL */ 77 78 /* Defined in FS&K */ 79 #define RANDOM_FORTUNA_NPOOLS 32 /* The number of accumulation pools */ 80 #define RANDOM_FORTUNA_DEFPOOLSIZE 64 /* The default pool size/length for a (re)seed */ 81 #define RANDOM_FORTUNA_MAX_READ (1 << 20) /* Max bytes in a single read */ 82 83 /* 84 * The allowable range of RANDOM_FORTUNA_DEFPOOLSIZE. The default value is above. 85 * Making RANDOM_FORTUNA_DEFPOOLSIZE too large will mean a long time between reseeds, 86 * and too small may compromise initial security but get faster reseeds. 87 */ 88 #define RANDOM_FORTUNA_MINPOOLSIZE 16 89 #define RANDOM_FORTUNA_MAXPOOLSIZE UINT_MAX 90 CTASSERT(RANDOM_FORTUNA_MINPOOLSIZE <= RANDOM_FORTUNA_DEFPOOLSIZE); 91 CTASSERT(RANDOM_FORTUNA_DEFPOOLSIZE <= RANDOM_FORTUNA_MAXPOOLSIZE); 92 93 /* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */ 94 CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t)); 95 CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE); 96 97 /* 98 * This is the beastie that needs protecting. It contains all of the 99 * state that we are excited about. Exactly one is instantiated. 100 */ 101 static struct fortuna_state { 102 struct fs_pool { /* P_i */ 103 u_int fsp_length; /* Only the first one is used by Fortuna */ 104 struct randomdev_hash fsp_hash; 105 } fs_pool[RANDOM_FORTUNA_NPOOLS]; 106 u_int fs_reseedcount; /* ReseedCnt */ 107 uint128_t fs_counter; /* C */ 108 struct randomdev_key fs_key; /* K */ 109 u_int fs_minpoolsize; /* Extras */ 110 /* Extras for the OS */ 111 #ifdef _KERNEL 112 /* For use when 'pacing' the reseeds */ 113 sbintime_t fs_lasttime; 114 #endif 115 /* Reseed lock */ 116 mtx_t fs_mtx; 117 } fortuna_state; 118 119 #ifdef _KERNEL 120 static struct sysctl_ctx_list random_clist; 121 RANDOM_CHECK_UINT(fs_minpoolsize, RANDOM_FORTUNA_MINPOOLSIZE, RANDOM_FORTUNA_MAXPOOLSIZE); 122 #else 123 static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE]; 124 #endif 125 126 static void random_fortuna_pre_read(void); 127 static void random_fortuna_read(uint8_t *, u_int); 128 static void random_fortuna_post_read(void); 129 static void random_fortuna_write(uint8_t *, u_int); 130 static void random_fortuna_reseed(void); 131 static int random_fortuna_seeded(void); 132 static void random_fortuna_process_event(struct harvest_event *); 133 134 #ifdef _KERNEL 135 /* Interface to Adaptors system */ 136 struct random_algorithm random_alg_context = { 137 .ra_ident = "Fortuna", 138 .ra_pre_read = random_fortuna_pre_read, 139 .ra_read = random_fortuna_read, 140 .ra_post_read = random_fortuna_post_read, 141 .ra_write = random_fortuna_write, 142 .ra_reseed = random_fortuna_reseed, 143 .ra_seeded = random_fortuna_seeded, 144 .ra_event_processor = random_fortuna_process_event, 145 .ra_poolcount = RANDOM_FORTUNA_NPOOLS, 146 }; 147 #endif 148 149 /* ARGSUSED */ 150 static void 151 random_fortuna_init_alg(void *unused __unused) 152 { 153 int i; 154 #ifdef _KERNEL 155 struct sysctl_oid *random_fortuna_o; 156 #endif 157 158 RANDOM_RESEED_INIT_LOCK(); 159 /* 160 * Fortuna parameters. Do not adjust these unless you have 161 * have a very good clue about what they do! 162 */ 163 fortuna_state.fs_minpoolsize = RANDOM_FORTUNA_DEFPOOLSIZE; 164 #ifdef _KERNEL 165 fortuna_state.fs_lasttime = 0; 166 random_fortuna_o = SYSCTL_ADD_NODE(&random_clist, 167 SYSCTL_STATIC_CHILDREN(_kern_random), 168 OID_AUTO, "fortuna", CTLFLAG_RW, 0, 169 "Fortuna Parameters"); 170 SYSCTL_ADD_PROC(&random_clist, 171 SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO, 172 "minpoolsize", CTLTYPE_UINT | CTLFLAG_RWTUN, 173 &fortuna_state.fs_minpoolsize, RANDOM_FORTUNA_DEFPOOLSIZE, 174 random_check_uint_fs_minpoolsize, "IU", 175 "Minimum pool size necessary to cause a reseed"); 176 KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0 at startup")); 177 #endif 178 179 /*- 180 * FS&K - InitializePRNG() 181 * - P_i = \epsilon 182 * - ReseedCNT = 0 183 */ 184 for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) { 185 randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash); 186 fortuna_state.fs_pool[i].fsp_length = 0; 187 } 188 fortuna_state.fs_reseedcount = 0; 189 /*- 190 * FS&K - InitializeGenerator() 191 * - C = 0 192 * - K = 0 193 */ 194 fortuna_state.fs_counter = UINT128_ZERO; 195 explicit_bzero(&fortuna_state.fs_key, sizeof(fortuna_state.fs_key)); 196 } 197 #ifdef _KERNEL 198 SYSINIT(random_fortuna, SI_SUB_RANDOM, SI_ORDER_THIRD, random_fortuna_init_alg, NULL); 199 #endif 200 201 /* ARGSUSED */ 202 static void 203 random_fortuna_deinit_alg(void *unused __unused) 204 { 205 206 RANDOM_RESEED_DEINIT_LOCK(); 207 explicit_bzero(&fortuna_state, sizeof(fortuna_state)); 208 #ifdef _KERNEL 209 sysctl_ctx_free(&random_clist); 210 #endif 211 } 212 #ifdef _KERNEL 213 SYSUNINIT(random_fortuna, SI_SUB_RANDOM, SI_ORDER_THIRD, random_fortuna_deinit_alg, NULL); 214 #endif 215 216 /*- 217 * FS&K - AddRandomEvent() 218 * Process a single stochastic event off the harvest queue 219 */ 220 void 221 random_fortuna_process_event(struct harvest_event *event) 222 { 223 u_int pl; 224 225 RANDOM_RESEED_LOCK(); 226 /*- 227 * FS&K - P_i = P_i|<harvested stuff> 228 * Accumulate the event into the appropriate pool 229 * where each event carries the destination information. 230 * 231 * The hash_init() and hash_finish() calls are done in 232 * random_fortuna_pre_read(). 233 * 234 * We must be locked against pool state modification which can happen 235 * during accumulation/reseeding and reading/regating. 236 */ 237 pl = event->he_destination % RANDOM_FORTUNA_NPOOLS; 238 randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash, event, sizeof(*event)); 239 /*- 240 * Don't wrap the length. Doing the the hard way so as not to wrap at MAXUINT. 241 * This is a "saturating" add. 242 * XXX: FIX!!: We don't actually need lengths for anything but fs_pool[0], 243 * but it's been useful debugging to see them all. 244 */ 245 if (RANDOM_FORTUNA_MAXPOOLSIZE - fortuna_state.fs_pool[pl].fsp_length > event->he_size) 246 fortuna_state.fs_pool[pl].fsp_length += event->he_size; 247 else 248 fortuna_state.fs_pool[pl].fsp_length = RANDOM_FORTUNA_MAXPOOLSIZE; 249 explicit_bzero(event, sizeof(*event)); 250 RANDOM_RESEED_UNLOCK(); 251 } 252 253 /*- 254 * Process a block of data suspected to be slightly stochastic. 255 * Do this by breaking it up and inserting the pieces as if 256 * they were separate events. 257 */ 258 static void 259 random_fortuna_process_buffer(uint32_t *buf, u_int wordcount) 260 { 261 static struct harvest_event event; 262 static u_int destination = 0; 263 int i; 264 265 for (i = 0; i < wordcount; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { 266 event.he_somecounter = (uint32_t)get_cyclecount(); 267 event.he_size = sizeof(event.he_entropy); 268 event.he_bits = event.he_size/8; 269 event.he_source = RANDOM_CACHED; 270 event.he_destination = destination++; /* Harmless cheating */ 271 memcpy(event.he_entropy, buf + i, sizeof(event.he_entropy)); 272 random_fortuna_process_event(&event); 273 } 274 } 275 276 /*- 277 * FS&K - Reseed() 278 * This introduces new key material into the output generator. 279 * Additionaly it increments the output generator's counter 280 * variable C. When C > 0, the output generator is seeded and 281 * will deliver output. 282 * The entropy_data buffer passed is a very specific size; the 283 * product of RANDOM_FORTUNA_NPOOLS and RANDOM_KEYSIZE. 284 */ 285 static void 286 random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount) 287 { 288 struct randomdev_hash context; 289 uint8_t hash[RANDOM_KEYSIZE]; 290 291 RANDOM_RESEED_ASSERT_LOCK_OWNED(); 292 /*- 293 * FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m)) 294 * - C = C + 1 295 */ 296 randomdev_hash_init(&context); 297 randomdev_hash_iterate(&context, zero_region, RANDOM_ZERO_BLOCKSIZE); 298 randomdev_hash_iterate(&context, &fortuna_state.fs_key, sizeof(fortuna_state.fs_key)); 299 randomdev_hash_iterate(&context, entropy_data, RANDOM_KEYSIZE*blockcount); 300 randomdev_hash_finish(&context, hash); 301 randomdev_hash_init(&context); 302 randomdev_hash_iterate(&context, hash, RANDOM_KEYSIZE); 303 randomdev_hash_finish(&context, hash); 304 randomdev_encrypt_init(&fortuna_state.fs_key, hash); 305 explicit_bzero(hash, sizeof(hash)); 306 /* Unblock the device if this is the first time we are reseeding. */ 307 if (uint128_is_zero(fortuna_state.fs_counter)) 308 randomdev_unblock(); 309 uint128_increment(&fortuna_state.fs_counter); 310 } 311 312 /*- 313 * FS&K - GenerateBlocks() 314 * Generate a number of complete blocks of random output. 315 */ 316 static __inline void 317 random_fortuna_genblocks(uint8_t *buf, u_int blockcount) 318 { 319 u_int i; 320 321 RANDOM_RESEED_ASSERT_LOCK_OWNED(); 322 for (i = 0; i < blockcount; i++) { 323 /*- 324 * FS&K - r = r|E(K,C) 325 * - C = C + 1 326 */ 327 randomdev_encrypt(&fortuna_state.fs_key, &fortuna_state.fs_counter, buf, RANDOM_BLOCKSIZE); 328 buf += RANDOM_BLOCKSIZE; 329 uint128_increment(&fortuna_state.fs_counter); 330 } 331 } 332 333 /*- 334 * FS&K - PseudoRandomData() 335 * This generates no more than 2^20 bytes of data, and cleans up its 336 * internal state when finished. It is assumed that a whole number of 337 * blocks are available for writing; any excess generated will be 338 * ignored. 339 */ 340 static __inline void 341 random_fortuna_genrandom(uint8_t *buf, u_int bytecount) 342 { 343 static uint8_t temp[RANDOM_BLOCKSIZE*(RANDOM_KEYS_PER_BLOCK)]; 344 u_int blockcount; 345 346 RANDOM_RESEED_ASSERT_LOCK_OWNED(); 347 /*- 348 * FS&K - assert(n < 2^20 (== 1 MB) 349 * - r = first-n-bytes(GenerateBlocks(ceil(n/16))) 350 * - K = GenerateBlocks(2) 351 */ 352 KASSERT((bytecount <= RANDOM_FORTUNA_MAX_READ), ("invalid single read request to Fortuna of %d bytes", bytecount)); 353 blockcount = (bytecount + RANDOM_BLOCKSIZE - 1)/RANDOM_BLOCKSIZE; 354 random_fortuna_genblocks(buf, blockcount); 355 random_fortuna_genblocks(temp, RANDOM_KEYS_PER_BLOCK); 356 randomdev_encrypt_init(&fortuna_state.fs_key, temp); 357 explicit_bzero(temp, sizeof(temp)); 358 } 359 360 /*- 361 * FS&K - RandomData() 362 * Used to return processed entropy from the PRNG. 363 * There is a pre_read and a post_read required to be present 364 * (but they can be null functions) in order to allow specific 365 * actions at the begin or the end of a read. Fortuna does its 366 * reseeding in the _pre_read() part, and _post_read() is not 367 * used. 368 */ 369 void 370 random_fortuna_pre_read(void) 371 { 372 #ifdef _KERNEL 373 sbintime_t now; 374 #endif 375 struct randomdev_hash context; 376 uint32_t s[RANDOM_FORTUNA_NPOOLS*RANDOM_KEYSIZE_WORDS]; 377 uint8_t temp[RANDOM_KEYSIZE]; 378 u_int i; 379 380 KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0")); 381 #ifdef _KERNEL 382 /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */ 383 now = getsbinuptime(); 384 #endif 385 RANDOM_RESEED_LOCK(); 386 387 if (fortuna_state.fs_pool[0].fsp_length >= fortuna_state.fs_minpoolsize 388 #ifdef _KERNEL 389 /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */ 390 && (now - fortuna_state.fs_lasttime > hz/10) 391 #endif 392 ) { 393 #ifdef _KERNEL 394 fortuna_state.fs_lasttime = now; 395 #endif 396 397 /* FS&K - ReseedCNT = ReseedCNT + 1 */ 398 fortuna_state.fs_reseedcount++; 399 /* s = \epsilon at start */ 400 for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) { 401 /* FS&K - if Divides(ReseedCnt, 2^i) ... */ 402 if ((fortuna_state.fs_reseedcount % (1 << i)) == 0) { 403 /*- 404 * FS&K - temp = (P_i) 405 * - P_i = \epsilon 406 * - s = s|H(temp) 407 */ 408 randomdev_hash_finish(&fortuna_state.fs_pool[i].fsp_hash, temp); 409 randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash); 410 fortuna_state.fs_pool[i].fsp_length = 0; 411 randomdev_hash_init(&context); 412 randomdev_hash_iterate(&context, temp, RANDOM_KEYSIZE); 413 randomdev_hash_finish(&context, s + i*RANDOM_KEYSIZE_WORDS); 414 } else 415 break; 416 } 417 #ifdef RANDOM_DEBUG 418 { 419 u_int j; 420 421 printf("random: reseedcount [%d]", fortuna_state.fs_reseedcount); 422 for (j = 0; j < RANDOM_FORTUNA_NPOOLS; j++) 423 printf(" %X", fortuna_state.fs_pool[j].fsp_length); 424 printf("\n"); 425 } 426 #endif 427 /* FS&K */ 428 random_fortuna_reseed_internal(s, i < RANDOM_FORTUNA_NPOOLS ? i + 1 : RANDOM_FORTUNA_NPOOLS); 429 /* Clean up and secure */ 430 explicit_bzero(s, sizeof(s)); 431 explicit_bzero(temp, sizeof(temp)); 432 explicit_bzero(&context, sizeof(context)); 433 } 434 RANDOM_RESEED_UNLOCK(); 435 } 436 437 /*- 438 * Main read from Fortuna. 439 * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size. 440 * Lots of code presumes this for efficiency, both here and in other 441 * routines. You are NOT allowed to break this! 442 */ 443 void 444 random_fortuna_read(uint8_t *buf, u_int bytecount) 445 { 446 447 RANDOM_RESEED_LOCK(); 448 random_fortuna_genrandom(buf, bytecount); 449 RANDOM_RESEED_UNLOCK(); 450 } 451 452 void 453 random_fortuna_post_read(void) 454 { 455 456 /* CWOT */ 457 } 458 459 /* Internal function to hand external entropy to the PRNG. */ 460 void 461 random_fortuna_write(uint8_t *buf, u_int count) 462 { 463 struct randomdev_hash hash; 464 uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp; 465 466 /* Extra timing here is helpful to scrape scheduler timing entropy */ 467 randomdev_hash_init(&hash); 468 timestamp = (uint32_t)get_cyclecount(); 469 randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); 470 randomdev_hash_iterate(&hash, buf, count); 471 timestamp = (uint32_t)get_cyclecount(); 472 randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); 473 randomdev_hash_finish(&hash, entropy_data); 474 explicit_bzero(&hash, sizeof(hash)); 475 random_fortuna_process_buffer(entropy_data, sizeof(entropy_data)/sizeof(entropy_data[0])); 476 explicit_bzero(entropy_data, sizeof(entropy_data)); 477 } 478 479 void 480 random_fortuna_reseed(void) 481 { 482 483 /* CWOT */ 484 } 485 486 int 487 random_fortuna_seeded(void) 488 { 489 490 return (!uint128_is_zero(fortuna_state.fs_counter)); 491 } 492