/* 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); }
/* Reseed Mutex is held, and buf points to a whole number of blocks. */ static __inline void random_fortuna_genblocks(uint8_t *buf, u_int blockcount) { u_int i; for (i = 0u; i < blockcount; i++) { /* F&S - r = r|E(K,C) */ randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE); buf += BLOCKSIZE; /* F&S - C = C + 1 */ uint128_increment(&fortuna_state.counter.whole); } }
/* * Create a psuedorandom output stream of 'blockcount' blocks using a CTR-mode * cipher or similar. The 128-bit counter is supplied in the in-out parmeter * 'ctr.' The output stream goes to 'd_out.' 'blockcount' RANDOM_BLOCKSIZE * bytes are generated. */ void randomdev_keystream(union randomdev_key *context, uint128_t *ctr, void *d_out, u_int blockcount) { u_int i; if (random_chachamode) { uint128_t lectr; /* * Chacha always encodes and increments the counter little * endian. So on BE machines, we must provide a swapped * counter to chacha, and swap the output too. */ le128enc(&lectr, *ctr); chacha_ivsetup(&context->chacha, NULL, (const void *)&lectr); chacha_encrypt_bytes(&context->chacha, NULL, d_out, RANDOM_BLOCKSIZE * blockcount); /* * Decode Chacha-updated LE counter to native endian and store * it back in the caller's in-out parameter. */ chacha_ctrsave(&context->chacha, (void *)&lectr); *ctr = le128dec(&lectr); } else { for (i = 0; i < blockcount; i++) { /*- * FS&K - r = r|E(K,C) * - C = C + 1 */ rijndael_blockEncrypt(&context->cipher, &context->key, (void *)ctr, RANDOM_BLOCKSIZE * 8, d_out); d_out = (char *)d_out + RANDOM_BLOCKSIZE; uint128_increment(ctr); } } }