entropy.c revision 43f117d5f0bc9d3e5d95798a9c25ef2c66c6da34
6fb9b25791778f69002eb72be6235e20d98ec452Tinderbox User * Copyright (C) 2000, 2001 Internet Software Consortium.
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
c1aef54e14bb92518b1c062ba8c0292a7cb949cbAutomatic Updater * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
b8a9a7bef2c3060204c68aef4f3fce04afc1aaeeAutomatic Updater * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews/* $Id: entropy.c,v 1.4 2001/09/01 00:46:04 gson Exp $ */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * This is the system independent part of the entropy module. It is
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * compiled via inclusion from the relevant OS source file, ie,
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Much of this code is modeled after the NetBSD /dev/random implementation,
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * written by Michael Graff <explorer@netbsd.org>.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
e334405421979688f2d838805ac67ee47bd62976Mark Andrews *** "constants." Do not change these unless you _really_ know what
f2ea8c2f965be7ff4c59f805712c12d469226b7bEvan Hunt *** you are doing.
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews * size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Number of bytes returned per hash. This must be true:
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * threshold * 2 <= digest_size_in_bytes
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Size of the input event queue in samples.
e851ea826066ac5a5b01c2c23218faa0273a12e8Evan Hunt * The number of times we'll "reseed" for pseudorandom seeds. This is an
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews * extremely weak pseudorandom seed. If the caller is using lots of
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * pseudorandom data and they cannot provide a stronger random source,
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews * there is little we can do other than hope they're smart enough to
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews * call _adddata() with something better than we can come up with.
e334405421979688f2d838805ac67ee47bd62976Mark Andrewstypedef struct {
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews isc_uint32_t cursor; /* current add point in the pool */
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews isc_uint32_t entropy; /* current entropy estimate in bits */
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews isc_uint32_t pseudo; /* bits extracted in pseudorandom */
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews isc_uint32_t rotate; /* how many bits to rotate by */
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews isc_uint32_t pool[RND_POOLWORDS]; /* random pool data */
44c0cfd2be65cebdfce66e0911c4da11186ee651Mark Andrews unsigned int magic;
e334405421979688f2d838805ac67ee47bd62976Mark Andrews unsigned int refcnt;
e334405421979688f2d838805ac67ee47bd62976Mark Andrews unsigned int nsources;
e334405421979688f2d838805ac67ee47bd62976Mark Andrewstypedef struct {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_uint32_t last_time; /* last time recorded */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_uint32_t last_delta; /* last delta value */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_uint32_t last_delta2; /* last delta2 value */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_uint32_t nsamples; /* number of samples filled in */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_uint32_t *extra; /* extra samples added in */
e334405421979688f2d838805ac67ee47bd62976Mark Andrewstypedef struct {
e334405421979688f2d838805ac67ee47bd62976Mark Andrewstypedef struct {
e334405421979688f2d838805ac67ee47bd62976Mark Andrewstypedef struct {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews unsigned int magic;
e334405421979688f2d838805ac67ee47bd62976Mark Andrews unsigned int type;
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_uint32_t total; /* entropy from this source */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define ENTROPY_SOURCETYPE_SAMPLE 1 /* Type is a sample source */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define ENTROPY_SOURCETYPE_FILE 2 /* Type is a file source */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews#define ENTROPY_SOURCETYPE_CALLBACK 3 /* Type is a callback source */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * The random pool "taps"
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Declarations for function provided by the system dependent sources that
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * include this file.
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsfillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsdestroyfilesource(isc_entropyfilesource_t *source);
e334405421979688f2d838805ac67ee47bd62976Mark Andrewssamplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
e334405421979688f2d838805ac67ee47bd62976Mark Andrewssamplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
b8a9a7bef2c3060204c68aef4f3fce04afc1aaeeAutomatic Updater sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
e334405421979688f2d838805ac67ee47bd62976Mark Andrews isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Add in entropy, even when the value we're adding in could be
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * very large.
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsstatic inline void
b8a9a7bef2c3060204c68aef4f3fce04afc1aaeeAutomatic Updateradd_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews /* clamp input. Yes, this must be done. */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews /* Add in the entropy we already have. */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews /* Clamp. */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Decrement the amount of entropy the pool has.
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsstatic inline void
e334405421979688f2d838805ac67ee47bd62976Mark Andrewssubtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Add in entropy, even when the value we're adding in could be
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * very large.
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsstatic inline void
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsadd_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews /* clamp input. Yes, this must be done. */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews /* Add in the pseudo we already have. */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews /* Clamp. */
e334405421979688f2d838805ac67ee47bd62976Mark Andrews ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Decrement the amount of pseudo the pool has.
cf4ceeee5fee2ebdca74f82514c14fd50939f85bMark Andrewsstatic inline void
e334405421979688f2d838805ac67ee47bd62976Mark Andrewssubtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Add one word to the pool, rotating the input as needed.
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsstatic inline void
e334405421979688f2d838805ac67ee47bd62976Mark Andrewsentropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Steal some values out of the pool, and xor them into the
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * word we were given.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Mix the new value into the pool using xor. This will
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * prevent the actual values from being known to the caller
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * since the previous values are assumed to be unknown as well.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
e334405421979688f2d838805ac67ee47bd62976Mark Andrews val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
e334405421979688f2d838805ac67ee47bd62976Mark Andrews val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
e334405421979688f2d838805ac67ee47bd62976Mark Andrews val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
e334405421979688f2d838805ac67ee47bd62976Mark Andrews val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
e334405421979688f2d838805ac67ee47bd62976Mark Andrews ((val << rp->rotate) | (val >> (32 - rp->rotate)));
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * If we have looped around the pool, increment the rotate
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * variable so the next value will get xored in rotated to
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * a different position.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Increment by a value that is relativly prime to the word size
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * to try to spread the bits throughout the pool quickly when the
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * pool is empty.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Add a buffer's worth of data to the pool.
e334405421979688f2d838805ac67ee47bd62976Mark Andrews * Requires that the lock is held on the entropy pool.
unsigned long addr;
addr = (unsigned long)p;
buf = p;
val = 0;
switch (len) {
len--;
len--;
len--;
if (len != 0) {
val = 0;
switch (len) {
isc_time_t t;
if (delta < 0)
if (delta2 < 0)
if (delta3 < 0)
unsigned int ns;
unsigned int added;
added = 0;
return (added);
unsigned int added;
unsigned int got;
if (desired == 0)
added = 0;
return (added);
total = 0;
while (remain != 0) {
if (goodonly) {
unsigned int fillcount;
if (!partial)
goto zeroize;
goto partial_output;
for (i = 0; i < count; i++)
return (ISC_R_SUCCESS);
*returned = 0;
return (ISC_R_NOENTROPY);
return (ISC_R_NOMEMORY);
goto errout;
return (ISC_R_SUCCESS);
return (ret);
case ENTROPY_SOURCETYPE_FILE:
static inline isc_boolean_t
return (ISC_FALSE);
case ENTROPY_SOURCETYPE_FILE:
return (ISC_FALSE);
return (ISC_TRUE);
case ENTROPY_SOURCETYPE_FILE:
if (killit)
void *arg,
goto errout;
goto errout;
return (ISC_R_SUCCESS);
return (ret);
goto errout;
goto errout;
return (ISC_R_SUCCESS);
return (ret);
static isc_result_t
return (ISC_R_NOMORE);
return (ISC_R_QUEUEFULL);
return (ISC_R_SUCCESS);
unsigned int entropy;
return (result);
return (result);
if (killit)
static isc_result_t
if (! blocking)
return (ISC_R_NOENTROPY);
if (first) {
static isc_result_t
isc_time_t t;
if (!blocking)
return (ISC_R_NOTBLOCKING);
return (result);
return (result);
extra = c;
return (result);
return (result);
#ifdef PATH_RANDOMDEV
return (final_result);