/* Reseed Mutex is held */ static void reseed(uint8_t *junk, u_int length) { struct randomdev_hash context; uint8_t hash[KEYSIZE]; KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0")); #ifdef _KERNEL mtx_assert(&random_reseed_mtx, MA_OWNED); #endif /* FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m)) */ randomdev_hash_init(&context); randomdev_hash_iterate(&context, zero_region, 512/8); randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key)); randomdev_hash_iterate(&context, junk, length); randomdev_hash_finish(&context, hash); randomdev_hash_init(&context); randomdev_hash_iterate(&context, hash, KEYSIZE); randomdev_hash_finish(&context, hash); randomdev_encrypt_init(&fortuna_state.key, hash); memset(hash, 0, sizeof(hash)); /* Unblock the device if it was blocked due to being unseeded */ if (uint128_is_zero(fortuna_state.counter.whole)) random_adaptor_unblock(); /* FS&K - C = C + 1 */ uint128_increment(&fortuna_state.counter.whole); }
/* Internal function to hand external entropy to the PRNG */ void random_fortuna_write(uint8_t *buf, u_int count) { uint8_t temp[KEYSIZE]; int i; uintmax_t timestamp; timestamp = get_cyclecount(); randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp)); randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count); timestamp = get_cyclecount(); randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp)); randomdev_hash_finish(&fortuna_start_cache.hash, temp); for (i = 0; i < KEYSIZE; i++) fortuna_start_cache.junk[(fortuna_start_cache.length + i)%PAGE_SIZE] ^= temp[i]; fortuna_start_cache.length += KEYSIZE; #ifdef RANDOM_DEBUG printf("random: %s - ", __func__); for (i = 0; i < KEYSIZE; i++) printf("%02X", temp[i]); printf("\n"); #endif memset(temp, 0, KEYSIZE); /* We must be locked for all this as plenty of state gets messed with */ mtx_lock(&random_reseed_mtx); randomdev_hash_init(&fortuna_start_cache.hash); reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length)); memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk)); mtx_unlock(&random_reseed_mtx); }
static void reseed(u_int fastslow) { /* Interrupt-context stack is a limited resource; make large * structures static. */ static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */ static struct randomdev_hash context; uint8_t hash[KEYSIZE]; /* h' */ uint8_t temp[KEYSIZE]; u_int i; enum esource j; #if 0 printf("Yarrow: %s reseed\n", fastslow == FAST ? "fast" : "slow"); #endif /* The reseed task must not be jumped on */ mtx_lock(&random_reseed_mtx); /* 1. Hash the accumulated entropy into v[0] */ randomdev_hash_init(&context); /* Feed the slow pool hash in if slow */ if (fastslow == SLOW) randomdev_hash_iterate(&context, &random_state.pool[SLOW].hash, sizeof(struct randomdev_hash)); randomdev_hash_iterate(&context, &random_state.pool[FAST].hash, sizeof(struct randomdev_hash)); randomdev_hash_finish(&context, v[0]); /* 2. Compute hash values for all v. _Supposed_ to be computationally * intensive. */ if (random_state.bins > TIMEBIN) random_state.bins = TIMEBIN; for (i = 1; i < random_state.bins; i++) { randomdev_hash_init(&context); /* v[i] #= h(v[i - 1]) */ randomdev_hash_iterate(&context, v[i - 1], KEYSIZE); /* v[i] #= h(v[0]) */ randomdev_hash_iterate(&context, v[0], KEYSIZE); /* v[i] #= h(i) */ randomdev_hash_iterate(&context, &i, sizeof(u_int)); /* Return the hashval */ randomdev_hash_finish(&context, v[i]); } /* 3. Compute a new key; h' is the identity function here; * it is not being ignored! */ randomdev_hash_init(&context); randomdev_hash_iterate(&context, &random_state.key, KEYSIZE); for (i = 1; i < random_state.bins; i++) randomdev_hash_iterate(&context, &v[i], KEYSIZE); randomdev_hash_finish(&context, temp); randomdev_encrypt_init(&random_state.key, temp); /* 4. Recompute the counter */ clear_counter(); randomdev_encrypt(&random_state.key, random_state.counter.byte, temp, BLOCKSIZE); memcpy(random_state.counter.byte, temp, BLOCKSIZE); /* 5. Reset entropy estimate accumulators to zero */ for (i = 0; i <= fastslow; i++) for (j = RANDOM_START; j < ENTROPYSOURCE; j++) random_state.pool[i].source[j].bits = 0; /* 6. Wipe memory of intermediate values */ memset((void *)v, 0, sizeof(v)); memset((void *)temp, 0, sizeof(temp)); memset((void *)hash, 0, sizeof(hash)); /* 7. Dump to seed file */ /* XXX Not done here yet */ /* Unblock the device if it was blocked due to being unseeded */ randomdev_unblock(); /* Release the reseed mutex */ mtx_unlock(&random_reseed_mtx); }
/* The argument buf points to a whole number of blocks. */ void random_fortuna_read(uint8_t *buf, u_int bytecount) { #ifdef _KERNEL sbintime_t thistime; #endif struct randomdev_hash context; uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE]; int i; u_int seedlength; /* We must be locked for all this as plenty of state gets messed with */ mtx_lock(&random_reseed_mtx); /* if buf == NULL and bytecount == 0 then this is the pre-read. */ /* if buf == NULL and bytecount != 0 then this is the post-read; ignore. */ if (buf == NULL) { if (bytecount == 0) { if (fortuna_state.pool[0].length >= fortuna_state.minpoolsize #ifdef _KERNEL /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */ && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10) #endif ) { #ifdef _KERNEL fortuna_state.lasttime = thistime; #endif seedlength = 0U; /* F&S - ReseedCNT = ReseedCNT + 1 */ fortuna_state.reseedcount++; /* s = \epsilon by default */ for (i = 0; i < NPOOLS; i++) { /* F&S - if Divides(ReseedCnt, 2^i) ... */ if ((fortuna_state.reseedcount % (1 << i)) == 0U) { seedlength += KEYSIZE; /* F&S - temp = (P_i) */ randomdev_hash_finish(&fortuna_state.pool[i].hash, temp); /* F&S - P_i = \epsilon */ randomdev_hash_init(&fortuna_state.pool[i].hash); fortuna_state.pool[i].length = 0U; /* F&S - s = s|H(temp) */ randomdev_hash_init(&context); randomdev_hash_iterate(&context, temp, KEYSIZE); randomdev_hash_finish(&context, s + i*KEYSIZE); } else break; } #ifdef RANDOM_DEBUG printf("random: active reseed: reseedcount [%d] ", fortuna_state.reseedcount); for (i = 0; i < NPOOLS; i++) printf(" %d", fortuna_state.pool[i].length); printf("\n"); #endif /* F&S */ reseed(s, seedlength); /* Clean up */ memset(s, 0, seedlength); seedlength = 0U; memset(temp, 0, sizeof(temp)); memset(&context, 0, sizeof(context)); } } } /* if buf != NULL do a regular read. */ else random_fortuna_genrandom(buf, bytecount); mtx_unlock(&random_reseed_mtx); }