1 /*- 2 * Copyright (c) 2013-2014 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 /* This implementation of Fortuna is based on the descriptions found in 29 * ISBN 0-471-22357-3 "Practical Cryptography" by Ferguson and Schneier 30 * ("F&S"). 31 * 32 * The above book is superseded by ISBN 978-0-470-47424-2 "Cryptography 33 * Engineering" by Ferguson, Schneier and Kohno ("FS&K"). The code has 34 * not yet fully caught up with FS&K. 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #ifdef _KERNEL 41 #include "opt_random.h" 42 43 #include <sys/param.h> 44 #include <sys/kernel.h> 45 #include <sys/lock.h> 46 #include <sys/malloc.h> 47 #include <sys/mutex.h> 48 #include <sys/random.h> 49 #include <sys/sysctl.h> 50 #include <sys/systm.h> 51 52 #include <machine/cpu.h> 53 54 #include <crypto/rijndael/rijndael-api-fst.h> 55 #include <crypto/sha2/sha2.h> 56 57 #include <dev/random/hash.h> 58 #include <dev/random/randomdev.h> 59 #include <dev/random/random_adaptors.h> 60 #include <dev/random/random_harvestq.h> 61 #include <dev/random/uint128.h> 62 #include <dev/random/fortuna.h> 63 #else /* !_KERNEL */ 64 #include <sys/param.h> 65 #include <sys/types.h> 66 #include <inttypes.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <threads.h> 71 72 #include "unit_test.h" 73 74 #include <crypto/rijndael/rijndael-api-fst.h> 75 #include <crypto/sha2/sha2.h> 76 77 #include <dev/random/hash.h> 78 #include <dev/random/uint128.h> 79 #include <dev/random/fortuna.h> 80 #endif /* _KERNEL */ 81 82 #if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA) 83 #define RANDOM_YARROW 84 #elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA) 85 #error "Must define either RANDOM_YARROW or RANDOM_FORTUNA" 86 #endif 87 88 #if defined(RANDOM_FORTUNA) 89 90 #define NPOOLS 32 91 #define MINPOOLSIZE 64 92 #define DEFPOOLSIZE 256 93 #define MAXPOOLSIZE 65536 94 95 /* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */ 96 CTASSERT(BLOCKSIZE == sizeof(uint128_t)); 97 CTASSERT(KEYSIZE == 2*BLOCKSIZE); 98 99 /* This is the beastie that needs protecting. It contains all of the 100 * state that we are excited about. 101 * Exactly one is instantiated. 102 */ 103 static struct fortuna_state { 104 /* P_i */ 105 struct pool { 106 u_int length; 107 struct randomdev_hash hash; 108 } pool[NPOOLS]; 109 110 /* ReseedCnt */ 111 u_int reseedcount; 112 113 /* C - 128 bits */ 114 union { 115 uint8_t byte[BLOCKSIZE]; 116 uint128_t whole; 117 } counter; 118 119 /* K */ 120 struct randomdev_key key; 121 122 /* Extras */ 123 u_int minpoolsize; 124 125 /* Extras for the OS */ 126 127 #ifdef _KERNEL 128 /* For use when 'pacing' the reseeds */ 129 sbintime_t lasttime; 130 #endif 131 } fortuna_state; 132 133 /* The random_reseed_mtx mutex protects seeding and polling/blocking. */ 134 static mtx_t random_reseed_mtx; 135 136 static struct fortuna_start_cache { 137 uint8_t junk[PAGE_SIZE]; 138 size_t length; 139 struct randomdev_hash hash; 140 } fortuna_start_cache; 141 142 #ifdef _KERNEL 143 static struct sysctl_ctx_list random_clist; 144 RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE); 145 #endif 146 147 void 148 random_fortuna_init_alg(void) 149 { 150 int i; 151 #ifdef _KERNEL 152 struct sysctl_oid *random_fortuna_o; 153 #endif 154 155 memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk)); 156 fortuna_start_cache.length = 0U; 157 randomdev_hash_init(&fortuna_start_cache.hash); 158 159 /* Set up a lock for the reseed process */ 160 #ifdef _KERNEL 161 mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF); 162 #else /* !_KERNEL */ 163 mtx_init(&random_reseed_mtx, mtx_plain); 164 #endif /* _KERNEL */ 165 166 #ifdef _KERNEL 167 /* Fortuna parameters. Do not adjust these unless you have 168 * have a very good clue about what they do! 169 */ 170 random_fortuna_o = SYSCTL_ADD_NODE(&random_clist, 171 SYSCTL_STATIC_CHILDREN(_kern_random), 172 OID_AUTO, "fortuna", CTLFLAG_RW, 0, 173 "Fortuna Parameters"); 174 175 SYSCTL_ADD_PROC(&random_clist, 176 SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO, 177 "minpoolsize", CTLTYPE_UINT|CTLFLAG_RW, 178 &fortuna_state.minpoolsize, DEFPOOLSIZE, 179 random_check_uint_minpoolsize, "IU", 180 "Minimum pool size necessary to cause a reseed automatically"); 181 182 fortuna_state.lasttime = 0U; 183 #endif 184 185 fortuna_state.minpoolsize = DEFPOOLSIZE; 186 187 /* F&S - InitializePRNG() */ 188 189 /* F&S - P_i = \epsilon */ 190 for (i = 0; i < NPOOLS; i++) { 191 randomdev_hash_init(&fortuna_state.pool[i].hash); 192 fortuna_state.pool[i].length = 0U; 193 } 194 195 /* F&S - ReseedCNT = 0 */ 196 fortuna_state.reseedcount = 0U; 197 198 /* F&S - InitializeGenerator() */ 199 200 /* F&S - C = 0 */ 201 uint128_clear(&fortuna_state.counter.whole); 202 203 /* F&S - K = 0 */ 204 memset(&fortuna_state.key, 0, sizeof(fortuna_state.key)); 205 } 206 207 void 208 random_fortuna_deinit_alg(void) 209 { 210 211 mtx_destroy(&random_reseed_mtx); 212 memset(&fortuna_state, 0, sizeof(fortuna_state)); 213 } 214 215 /* F&S - AddRandomEvent() */ 216 /* Process a single stochastic event off the harvest queue */ 217 void 218 random_fortuna_process_event(struct harvest_event *event) 219 { 220 u_int pl; 221 222 /* We must be locked for all this as plenty of state gets messed with */ 223 mtx_lock(&random_reseed_mtx); 224 225 /* Accumulate the event into the appropriate pool 226 * where each event carries the destination information 227 */ 228 /* F&S - P_i = P_i|<harvested stuff> */ 229 /* The hash_init and hash_finish are done in random_fortuna_read() below */ 230 pl = event->he_destination % NPOOLS; 231 randomdev_hash_iterate(&fortuna_state.pool[pl].hash, event, sizeof(*event)); 232 /* No point in counting above the outside maximum */ 233 fortuna_state.pool[pl].length += event->he_size; 234 fortuna_state.pool[pl].length = MIN(fortuna_state.pool[pl].length, MAXPOOLSIZE); 235 236 /* Done with state-messing */ 237 mtx_unlock(&random_reseed_mtx); 238 } 239 240 /* F&S - Reseed() */ 241 /* Reseed Mutex is held */ 242 static void 243 reseed(uint8_t *junk, u_int length) 244 { 245 struct randomdev_hash context; 246 uint8_t hash[KEYSIZE]; 247 248 KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0")); 249 #ifdef _KERNEL 250 mtx_assert(&random_reseed_mtx, MA_OWNED); 251 #endif 252 253 /* FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m)) */ 254 randomdev_hash_init(&context); 255 randomdev_hash_iterate(&context, zero_region, 512/8); 256 randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key)); 257 randomdev_hash_iterate(&context, junk, length); 258 randomdev_hash_finish(&context, hash); 259 randomdev_hash_init(&context); 260 randomdev_hash_iterate(&context, hash, KEYSIZE); 261 randomdev_hash_finish(&context, hash); 262 randomdev_encrypt_init(&fortuna_state.key, hash); 263 memset(hash, 0, sizeof(hash)); 264 265 /* Unblock the device if it was blocked due to being unseeded */ 266 if (uint128_is_zero(fortuna_state.counter.whole)) 267 random_adaptor_unblock(); 268 /* FS&K - C = C + 1 */ 269 uint128_increment(&fortuna_state.counter.whole); 270 } 271 272 /* F&S - GenerateBlocks() */ 273 /* Reseed Mutex is held, and buf points to a whole number of blocks. */ 274 static __inline void 275 random_fortuna_genblocks(uint8_t *buf, u_int blockcount) 276 { 277 u_int i; 278 279 for (i = 0u; i < blockcount; i++) { 280 /* F&S - r = r|E(K,C) */ 281 randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE); 282 buf += BLOCKSIZE; 283 284 /* F&S - C = C + 1 */ 285 uint128_increment(&fortuna_state.counter.whole); 286 } 287 } 288 289 /* F&S - PseudoRandomData() */ 290 /* Reseed Mutex is held, and buf points to a whole number of blocks. */ 291 static __inline void 292 random_fortuna_genrandom(uint8_t *buf, u_int bytecount) 293 { 294 static uint8_t temp[BLOCKSIZE*(KEYSIZE/BLOCKSIZE)]; 295 u_int blockcount; 296 297 /* F&S - assert(n < 2^20) */ 298 KASSERT((bytecount <= (1 << 20)), ("invalid single read request to fortuna of %d bytes", bytecount)); 299 300 /* F&S - r = first-n-bytes(GenerateBlocks(ceil(n/16))) */ 301 blockcount = bytecount / BLOCKSIZE; 302 random_fortuna_genblocks(buf, blockcount); 303 /* TODO: FIX! remove memcpy()! */ 304 if (bytecount % BLOCKSIZE > 0) { 305 random_fortuna_genblocks(temp, 1); 306 memcpy(buf + (blockcount * BLOCKSIZE), temp, bytecount % BLOCKSIZE); 307 } 308 309 /* F&S - K = GenerateBlocks(2) */ 310 random_fortuna_genblocks(temp, KEYSIZE/BLOCKSIZE); 311 randomdev_encrypt_init(&fortuna_state.key, temp); 312 memset(temp, 0, sizeof(temp)); 313 } 314 315 /* F&S - RandomData() */ 316 /* Used to return processed entropy from the PRNG */ 317 /* The argument buf points to a whole number of blocks. */ 318 void 319 random_fortuna_read(uint8_t *buf, u_int bytecount) 320 { 321 #ifdef _KERNEL 322 sbintime_t thistime; 323 #endif 324 struct randomdev_hash context; 325 uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE]; 326 int i; 327 u_int seedlength; 328 329 /* We must be locked for all this as plenty of state gets messed with */ 330 mtx_lock(&random_reseed_mtx); 331 332 /* if buf == NULL and bytecount == 0 then this is the pre-read. */ 333 /* if buf == NULL and bytecount != 0 then this is the post-read; ignore. */ 334 if (buf == NULL) { 335 if (bytecount == 0) { 336 if (fortuna_state.pool[0].length >= fortuna_state.minpoolsize 337 #ifdef _KERNEL 338 /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */ 339 && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10) 340 #endif 341 ) { 342 #ifdef _KERNEL 343 fortuna_state.lasttime = thistime; 344 #endif 345 346 seedlength = 0U; 347 /* F&S - ReseedCNT = ReseedCNT + 1 */ 348 fortuna_state.reseedcount++; 349 /* s = \epsilon by default */ 350 for (i = 0; i < NPOOLS; i++) { 351 /* F&S - if Divides(ReseedCnt, 2^i) ... */ 352 if ((fortuna_state.reseedcount % (1 << i)) == 0U) { 353 seedlength += KEYSIZE; 354 /* F&S - temp = (P_i) */ 355 randomdev_hash_finish(&fortuna_state.pool[i].hash, temp); 356 /* F&S - P_i = \epsilon */ 357 randomdev_hash_init(&fortuna_state.pool[i].hash); 358 fortuna_state.pool[i].length = 0U; 359 /* F&S - s = s|H(temp) */ 360 randomdev_hash_init(&context); 361 randomdev_hash_iterate(&context, temp, KEYSIZE); 362 randomdev_hash_finish(&context, s + i*KEYSIZE); 363 } 364 else 365 break; 366 } 367 #ifdef RANDOM_DEBUG 368 printf("random: active reseed: reseedcount [%d] ", fortuna_state.reseedcount); 369 for (i = 0; i < NPOOLS; i++) 370 printf(" %d", fortuna_state.pool[i].length); 371 printf("\n"); 372 #endif 373 /* F&S */ 374 reseed(s, seedlength); 375 376 /* Clean up */ 377 memset(s, 0, seedlength); 378 seedlength = 0U; 379 memset(temp, 0, sizeof(temp)); 380 memset(&context, 0, sizeof(context)); 381 } 382 } 383 } 384 /* if buf != NULL do a regular read. */ 385 else 386 random_fortuna_genrandom(buf, bytecount); 387 388 mtx_unlock(&random_reseed_mtx); 389 } 390 391 /* Internal function to hand external entropy to the PRNG */ 392 void 393 random_fortuna_write(uint8_t *buf, u_int count) 394 { 395 uint8_t temp[KEYSIZE]; 396 int i; 397 uintmax_t timestamp; 398 399 timestamp = get_cyclecount(); 400 randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp)); 401 randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count); 402 timestamp = get_cyclecount(); 403 randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp)); 404 randomdev_hash_finish(&fortuna_start_cache.hash, temp); 405 for (i = 0; i < KEYSIZE; i++) 406 fortuna_start_cache.junk[(fortuna_start_cache.length + i)%PAGE_SIZE] ^= temp[i]; 407 fortuna_start_cache.length += KEYSIZE; 408 409 #ifdef RANDOM_DEBUG 410 printf("random: %s - ", __func__); 411 for (i = 0; i < KEYSIZE; i++) 412 printf("%02X", temp[i]); 413 printf("\n"); 414 #endif 415 416 memset(temp, 0, KEYSIZE); 417 418 /* We must be locked for all this as plenty of state gets messed with */ 419 mtx_lock(&random_reseed_mtx); 420 421 randomdev_hash_init(&fortuna_start_cache.hash); 422 423 reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length)); 424 memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk)); 425 426 mtx_unlock(&random_reseed_mtx); 427 } 428 429 void 430 random_fortuna_reseed(void) 431 { 432 433 /* CWOT */ 434 } 435 436 int 437 random_fortuna_seeded(void) 438 { 439 440 return (!uint128_is_zero(fortuna_state.counter.whole)); 441 } 442 443 #endif /* RANDOM_FORTUNA */ 444