1/*- 2 * Copyright (c) 2000-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#include <sys/cdefs.h> 29__FBSDID("$FreeBSD$"); 30 31#include <sys/param.h> 32#ifdef _KERNEL 33#include <sys/malloc.h> 34#include <sys/mutex.h> 35#include <sys/systm.h> 36 37#include <crypto/rijndael/rijndael-api-fst.h> 38#include <crypto/sha2/sha256.h> 39 40#include <dev/random/hash.h> 41#include <dev/random/randomdev.h> 42#include <dev/random/random_harvestq.h> 43#include <dev/random/uint128.h> 44#include <dev/random/yarrow.h> 45#else /* !_KERNEL */ 46#include <inttypes.h> 47#include <stdbool.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <stdint.h> 51#include <string.h> 52#include <sys/mutex.h> 53 54#include "los_init.h" 55 56#include "unit_test.h" 57 58#include <crypto/rijndael/rijndael-api-fst.h> 59#include <crypto/sha2/sha256.h> 60 61#include <dev/random/hash.h> 62#include <dev/random/randomdev.h> 63#include <dev/random/uint128.h> 64#include <dev/random/yarrow.h> 65#endif /* _KERNEL */ 66 67#define RANDOM_ITERATE_NUMBER 16 68 69#define RANDOM_YARROW_TIMEBIN 16 /* max value for Pt/t */ 70 71#define RANDOM_YARROW_FAST 0 72#define RANDOM_YARROW_SLOW 1 73#define RANDOM_YARROW_NPOOLS 2 74 75/* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */ 76CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t)); 77CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE); 78 79#ifndef __LITEOS__ 80/* Probes for dtrace(1) */ 81SDT_PROVIDER_DECLARE(random); 82SDT_PROVIDER_DEFINE(random); 83SDT_PROBE_DEFINE3(random, yarrow, event_processor, debug, "boolean", "u_int", "struct ys_pool *"); 84#endif 85 86/* 87 * This is the beastie that needs protecting. It contains all of the 88 * state that we are excited about. Exactly one is instantiated. 89 */ 90static struct yarrow_state { 91 uint128_t ys_counter; /* C */ 92 struct randomdev_key ys_key; /* K */ 93 u_int ys_gengateinterval; /* Pg */ 94 u_int ys_bins; /* Pt/t */ 95 u_int ys_outputblocks; /* count output blocks for gates */ 96 u_int ys_slowoverthresh; /* slow pool overthreshhold reseed count */ 97 struct ys_pool { 98 u_int ysp_source_bits[ENTROPYSOURCE]; /* estimated bits of entropy per source */ 99 u_int ysp_thresh; /* pool reseed threshold */ 100 struct randomdev_hash ysp_hash; /* accumulated entropy */ 101 } ys_pool[RANDOM_YARROW_NPOOLS];/* pool[0] is fast, pool[1] is slow */ 102 bool ys_seeded; 103 /* Reseed lock */ 104 mtx_t ys_mtx; 105} yarrow_state; 106 107#ifdef _KERNEL 108static struct sysctl_ctx_list random_clist; 109RANDOM_CHECK_UINT(gengateinterval, 4, 64); 110RANDOM_CHECK_UINT(bins, RANDOM_YARROW_NPOOLS, 16); 111RANDOM_CHECK_UINT(fastthresh, (RANDOM_BLOCKSIZE*8)/4, (RANDOM_BLOCKSIZE*8)); /* Bit counts */ 112RANDOM_CHECK_UINT(slowthresh, (RANDOM_BLOCKSIZE*8)/4, (RANDOM_BLOCKSIZE*8)); /* Bit counts */ 113RANDOM_CHECK_UINT(slowoverthresh, 1, 5); 114#endif /* _KERNEL */ 115 116static void random_yarrow_pre_read(void); 117static void random_yarrow_read(uint8_t *, u_int); 118static bool random_yarrow_seeded(void); 119static void random_yarrow_process_event(struct harvest_event *); 120static void random_yarrow_init_alg(void *); 121static void random_yarrow_deinit_alg(void *); 122 123static void random_yarrow_reseed_internal(u_int); 124 125struct random_algorithm random_alg_context = { 126 .ra_ident = "Yarrow", 127 .ra_init_alg = random_yarrow_init_alg, 128 .ra_deinit_alg = random_yarrow_deinit_alg, 129 .ra_pre_read = random_yarrow_pre_read, 130 .ra_read = random_yarrow_read, 131 .ra_seeded = random_yarrow_seeded, 132 .ra_event_processor = random_yarrow_process_event, 133 .ra_poolcount = RANDOM_YARROW_NPOOLS, 134}; 135 136/* ARGSUSED */ 137static void 138random_yarrow_init_alg(void *unused __unused) 139{ 140 int i, j; 141#ifdef _KERNEL 142 struct sysctl_oid *random_yarrow_o; 143#endif 144 145 RANDOM_RESEED_INIT_LOCK(); 146 /* Start unseeded, therefore blocked. */ 147 yarrow_state.ys_seeded = false; 148#ifdef _KERNEL 149 /* 150 * Yarrow parameters. Do not adjust these unless you have 151 * have a very good clue about what they do! 152 */ 153 random_yarrow_o = SYSCTL_ADD_NODE(&random_clist, 154 SYSCTL_STATIC_CHILDREN(_kern_random), 155 OID_AUTO, "yarrow", CTLFLAG_RW, 0, 156 "Yarrow Parameters"); 157 SYSCTL_ADD_PROC(&random_clist, 158 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, 159 "gengateinterval", CTLTYPE_UINT | CTLFLAG_RWTUN, 160 &yarrow_state.ys_gengateinterval, 0, 161 random_check_uint_gengateinterval, "UI", 162 "Generation gate interval"); 163 SYSCTL_ADD_PROC(&random_clist, 164 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, 165 "bins", CTLTYPE_UINT | CTLFLAG_RWTUN, 166 &yarrow_state.ys_bins, 0, 167 random_check_uint_bins, "UI", 168 "Execution time tuner"); 169 SYSCTL_ADD_PROC(&random_clist, 170 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, 171 "fastthresh", CTLTYPE_UINT | CTLFLAG_RWTUN, 172 &yarrow_state.ys_pool[0].ysp_thresh, 0, 173 random_check_uint_fastthresh, "UI", 174 "Fast reseed threshold"); 175 SYSCTL_ADD_PROC(&random_clist, 176 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, 177 "slowthresh", CTLTYPE_UINT | CTLFLAG_RWTUN, 178 &yarrow_state.ys_pool[1].ysp_thresh, 0, 179 random_check_uint_slowthresh, "UI", 180 "Slow reseed threshold"); 181 SYSCTL_ADD_PROC(&random_clist, 182 SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO, 183 "slowoverthresh", CTLTYPE_UINT | CTLFLAG_RWTUN, 184 &yarrow_state.ys_slowoverthresh, 0, 185 random_check_uint_slowoverthresh, "UI", 186 "Slow over-threshold reseed"); 187#endif /* _KERNEL */ 188 yarrow_state.ys_gengateinterval = 10; 189 yarrow_state.ys_bins = 10; 190 yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh = (3*(RANDOM_BLOCKSIZE*8))/4; 191 yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh = (RANDOM_BLOCKSIZE*8); 192 yarrow_state.ys_slowoverthresh = 2; 193 /* Ensure that the first time we read, we are gated. */ 194 yarrow_state.ys_outputblocks = yarrow_state.ys_gengateinterval; 195 /* Initialise the fast and slow entropy pools */ 196 for (i = RANDOM_YARROW_FAST; i <= RANDOM_YARROW_SLOW; i++) { 197 randomdev_hash_init(&yarrow_state.ys_pool[i].ysp_hash); 198 for (j = RANDOM_START; j < ENTROPYSOURCE; j++) 199 yarrow_state.ys_pool[i].ysp_source_bits[j] = 0; 200 } 201 /* Clear the counter */ 202 yarrow_state.ys_counter = UINT128_ZERO; 203} 204 205/* ARGSUSED */ 206static void 207random_yarrow_deinit_alg(void *unused __unused) 208{ 209 210 RANDOM_RESEED_DEINIT_LOCK(); 211 explicit_bzero(&yarrow_state, sizeof(yarrow_state)); 212#ifdef _KERNEL 213 sysctl_ctx_free(&random_clist); 214#endif 215} 216 217/* Process a single stochastic event off the harvest queue */ 218static void 219random_yarrow_process_event(struct harvest_event *event) 220{ 221 u_int pl, overthreshhold[RANDOM_YARROW_NPOOLS]; 222 enum random_entropy_source src; 223 224 RANDOM_RESEED_LOCK(); 225 /* 226 * Accumulate the event into the appropriate pool 227 * where each event carries the destination information. 228 * We lock against pool state modification which can happen 229 * during accumulation/reseeding and reading/regating 230 */ 231 pl = event->he_destination % RANDOM_YARROW_NPOOLS; 232 randomdev_hash_iterate(&yarrow_state.ys_pool[pl].ysp_hash, event, sizeof(*event)); 233 if((event->he_source < ENTROPYSOURCE)&&(pl < RANDOM_YARROW_NPOOLS)) { 234 yarrow_state.ys_pool[pl].ysp_source_bits[event->he_source] += event->he_bits; 235 } 236 /* Count the over-threshold sources in each pool */ 237 for (pl = RANDOM_YARROW_FAST; (pl <= RANDOM_YARROW_SLOW) && (pl < RANDOM_YARROW_NPOOLS); pl++) { 238 overthreshhold[pl] = 0; 239 for (src = RANDOM_START; src < ENTROPYSOURCE; src++) { 240 if (yarrow_state.ys_pool[pl].ysp_source_bits[src] > yarrow_state.ys_pool[pl].ysp_thresh) 241 overthreshhold[pl]++; 242 } 243 } 244 /* 245 * If enough slow sources are over threshold, then slow reseed 246 * else if any fast source over threshold, then fast reseed. 247 */ 248 if (overthreshhold[RANDOM_YARROW_SLOW] >= yarrow_state.ys_slowoverthresh) 249 random_yarrow_reseed_internal(RANDOM_YARROW_SLOW); 250 else if (overthreshhold[RANDOM_YARROW_FAST] > 0 && yarrow_state.ys_seeded) 251 random_yarrow_reseed_internal(RANDOM_YARROW_FAST); 252 explicit_bzero(event, sizeof(*event)); 253 RANDOM_RESEED_UNLOCK(); 254} 255 256static void 257random_yarrow_reseed_internal(u_int fastslow) 258{ 259 /* 260 * Interrupt-context stack is a limited resource; make large 261 * structures static. 262 */ 263 static uint8_t v[RANDOM_YARROW_TIMEBIN][RANDOM_KEYSIZE]; /* v[i] */ 264 static uint128_t temp; 265 static struct randomdev_hash context; 266 u_int i; 267 enum random_entropy_source j; 268 269 KASSERT(yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh > 0, ("random: Yarrow fast threshold = 0")); 270 KASSERT(yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh > 0, ("random: Yarrow slow threshold = 0")); 271 RANDOM_RESEED_ASSERT_LOCK_OWNED(); 272#ifndef __LITEOS__ 273 SDT_PROBE3(random, yarrow, event_processor, debug, yarrow_state.ys_seeded, yarrow_state.ys_slowoverthresh, yarrow_state.ys_pool); 274#endif 275 /* 1. Hash the accumulated entropy into v[0] */ 276 randomdev_hash_init(&context); 277 /* Feed the slow pool hash in if slow */ 278 if (fastslow == RANDOM_YARROW_SLOW) { 279 randomdev_hash_finish(&yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_hash, &temp); 280 randomdev_hash_iterate(&context, &temp, sizeof(temp)); 281 } 282 randomdev_hash_finish(&yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_hash, &temp); 283 randomdev_hash_iterate(&context, &temp, sizeof(temp)); 284 randomdev_hash_finish(&context, v[0]); 285 /*- 286 * 2. Compute hash values for all v. _Supposed_ to be computationally 287 * intensive. 288 */ 289 if (yarrow_state.ys_bins > RANDOM_YARROW_TIMEBIN) 290 yarrow_state.ys_bins = RANDOM_YARROW_TIMEBIN; 291 for (i = 1; i < yarrow_state.ys_bins; i++) { 292 randomdev_hash_init(&context); 293 /* v[i] #= h(v[i - 1]) */ 294 randomdev_hash_iterate(&context, v[i - 1], RANDOM_KEYSIZE); 295 /* v[i] #= h(v[0]) */ 296 randomdev_hash_iterate(&context, v[0], RANDOM_KEYSIZE); 297 /* v[i] #= h(i) */ 298 randomdev_hash_iterate(&context, &i, sizeof(i)); 299 /* Return the hashval */ 300 randomdev_hash_finish(&context, v[i]); 301 } 302 /*- 303 * 3. Compute a new key; h' is the identity function here; 304 * it is not being ignored! 305 */ 306 randomdev_hash_init(&context); 307 randomdev_hash_iterate(&context, &yarrow_state.ys_key, RANDOM_KEYSIZE); 308 for (i = 1; i < yarrow_state.ys_bins; i++) 309 randomdev_hash_iterate(&context, v[i], RANDOM_KEYSIZE); 310 randomdev_hash_finish(&context, &temp); 311 randomdev_encrypt_init(&yarrow_state.ys_key, &temp); 312 /* 4. Recompute the counter */ 313 yarrow_state.ys_counter = UINT128_ZERO; 314 randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, &temp, RANDOM_BLOCKSIZE); 315 yarrow_state.ys_counter = temp; 316 /* 5. Reset entropy estimate accumulators to zero */ 317 for (i = 0; i <= fastslow; i++) 318 for (j = RANDOM_START; j < ENTROPYSOURCE; j++) 319 yarrow_state.ys_pool[i].ysp_source_bits[j] = 0; 320 /* 6. Wipe memory of intermediate values */ 321 explicit_bzero(v, sizeof(v)); 322 explicit_bzero(&temp, sizeof(temp)); 323 explicit_bzero(&context, sizeof(context)); 324/* Not defined so writes ain't gonna happen. Kept for documenting. */ 325#ifdef RANDOM_RWFILE_WRITE_IS_OK 326 /*- 327 * 7. Dump to seed file. 328 * This pseudo-code is documentation. Please leave it alone. 329 */ 330 seed_file = "<some file>"; 331 error = randomdev_write_file(seed_file, <generated entropy>, PAGE_SIZE); 332 if (error == 0) 333 printf("random: entropy seed file '%s' successfully written\n", seed_file); 334#endif 335 /* Unblock the device if it was blocked due to being unseeded */ 336 if (!yarrow_state.ys_seeded) { 337 yarrow_state.ys_seeded = true; 338 #ifndef __LITEOS__ 339 randomdev_unblock(); 340 #endif 341 } 342} 343 344static __inline void 345random_yarrow_generator_gate(void) 346{ 347 u_int i; 348 uint8_t temp[RANDOM_KEYSIZE]; 349 350 RANDOM_RESEED_ASSERT_LOCK_OWNED(); 351 uint128_increment(&yarrow_state.ys_counter); 352 for (i = 0; i < RANDOM_KEYSIZE; i += RANDOM_BLOCKSIZE) 353 randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, temp + i, RANDOM_BLOCKSIZE); 354 randomdev_encrypt_init(&yarrow_state.ys_key, temp); 355 explicit_bzero(temp, sizeof(temp)); 356} 357 358/*- 359 * Used to return processed entropy from the PRNG. There is a pre_read 360 * required to be present (but it can be a stub) in order to allow 361 * specific actions at the begin of the read. 362 * Yarrow does its reseeding in its own thread; _pre_read() is not used 363 * by Yarrow but must be kept for completeness. 364 */ 365void 366random_yarrow_pre_read(void) 367{ 368} 369 370/*- 371 * Main read from Yarrow. 372 * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size. 373 * Lots of code presumes this for efficiency, both here and in other 374 * routines. You are NOT allowed to break this! 375 */ 376void 377random_yarrow_read(uint8_t *buf, u_int bytecount) 378{ 379 u_int blockcount, i; 380 381 KASSERT((bytecount % RANDOM_BLOCKSIZE) == 0, ("%s(): bytecount (= %d) must be a multiple of %d", __func__, bytecount, RANDOM_BLOCKSIZE )); 382 RANDOM_RESEED_LOCK(); 383 blockcount = howmany(bytecount, RANDOM_BLOCKSIZE); 384 for (i = 0; i < blockcount; i++) { 385 if (yarrow_state.ys_outputblocks++ >= yarrow_state.ys_gengateinterval) { 386 random_yarrow_generator_gate(); 387 yarrow_state.ys_outputblocks = 0; 388 } 389 uint128_increment(&yarrow_state.ys_counter); 390 randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, buf, RANDOM_BLOCKSIZE); 391 buf += RANDOM_BLOCKSIZE; 392 } 393 RANDOM_RESEED_UNLOCK(); 394} 395 396bool 397random_yarrow_seeded(void) 398{ 399 400 return (yarrow_state.ys_seeded); 401} 402 403#if defined(LOSCFG_HW_RANDOM_ENABLE) 404void 405random_hw_getnumber(char *pbuf, size_t len) 406{ 407 extern void HiRandomHwInit(void); 408 extern void HiRandomHwDeinit(void); 409 extern int HiRandomHwGetNumber(char *buffer, size_t buflen); 410 411 HiRandomHwInit(); 412 413 ssize_t ret = HiRandomHwGetNumber((char *)pbuf, len); 414 if (ret != 0) { 415 HiRandomHwDeinit(); 416 errno = EIO; 417 return; 418 } 419 420 HiRandomHwDeinit(); 421} 422#endif 423 424#if defined(LOSCFG_HW_RANDOM_ENABLE) || defined(LOSCFG_DRIVERS_RANDOM) 425void 426run_harvester_once(const char *pentropy, size_t num) 427{ 428 struct harvest_event e; 429 uint64_t data; 430 errno_t err = EOK; 431 432 if (pentropy == NULL) { 433 return; 434 } 435 e.he_somecounter = num; 436 e.he_size = sizeof(e.he_entropy); 437 err = memcpy_s(e.he_entropy, e.he_size, pentropy, e.he_size); 438 if(err != EOK){ 439 return; 440 } 441 err = memcpy_s(&data, sizeof(uint64_t), e.he_entropy, sizeof(uint64_t)); 442 if(err != EOK){ 443 return; 444 } 445 e.he_bits = data % 64 + 60; /* calculate bits */ 446 e.he_destination = num; 447 e.he_source = (num + 3) % 3; /* calculate source */ 448 e.he_next = NULL; 449 random_alg_context.ra_event_processor(&e); 450} 451#endif 452 453void 454run_harvester_iterate(void *arg __unused) 455{ 456#if defined(LOSCFG_HW_RANDOM_ENABLE) 457 int i; 458 char buf[8]; /* store random numbers */ 459 for (i = 0; i < RANDOM_ITERATE_NUMBER; i++) { 460 random_hw_getnumber(buf, sizeof(buf)); 461 run_harvester_once(buf, i); 462 (void)memset_s(buf, sizeof(buf), 0, sizeof(buf)); 463 } 464#elif defined(LOSCFG_DRIVERS_RANDOM) 465 extern VOID LOS_GetCpuCycle(UINT32 *puwCntHi, UINT32 *puwCntLo); 466 int rdata1, rdata2; 467 char buf[8]; /* store random numbers */ 468 int i; 469 for (i = 0; i < RANDOM_ITERATE_NUMBER; i++) { 470 LOS_GetCpuCycle(&rdata1, &rdata2); 471 srand((unsigned int)rdata2); 472 rdata1 = (int)rand(); 473 rdata2 = (int)rand(); 474 (void)memcpy_s(buf, sizeof(int), &rdata1, sizeof(int)); 475 (void)memcpy_s(buf + 4, sizeof(int), &rdata2, sizeof(int)); 476 run_harvester_once(buf, i); 477 } 478 (void)memset_s(buf, sizeof(buf), 0, sizeof(buf)); 479#endif 480} 481 482#if defined(LOSCFG_HW_RANDOM_ENABLE) || defined(LOSCFG_DRIVERS_RANDOM) 483UINT32 OsDriverRandomInit(VOID) 484{ 485 random_alg_context.ra_init_alg(NULL); 486 run_harvester_iterate(NULL); 487 return LOS_OK; 488} 489#endif 490