entropy.c revision ee303f481dfefcd4e4994f8b8b17f2de32aa4d69
499b34cea04a46823d003d4c0520c8b03e8513cbBrian Wellington * Copyright (C) 2000 Internet Software Consortium.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Permission to use, copy, modify, and distribute this software for any
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * purpose with or without fee is hereby granted, provided that the above
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * copyright notice and this permission notice appear in all copies.
15a44745412679c30a6d022733925af70a38b715David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
15a44745412679c30a6d022733925af70a38b715David Lawrence * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
15a44745412679c30a6d022733925af70a38b715David Lawrence * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
15a44745412679c30a6d022733925af70a38b715David Lawrence * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
15a44745412679c30a6d022733925af70a38b715David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
15a44745412679c30a6d022733925af70a38b715David Lawrence * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15a44745412679c30a6d022733925af70a38b715David Lawrence * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
15a44745412679c30a6d022733925af70a38b715David Lawrence * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson/* $Id: entropy.c,v 1.54 2000/12/27 00:11:26 bwelling Exp $ */
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson * Much of this code is modeled after the NetBSD /dev/random implementation,
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson * written by Michael Graff <explorer@netbsd.org>.
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews *** "constants." Do not change these unless you _really_ know what
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews *** you are doing.
eb6bd543c7d072efdca509eb17f8f301c1467b53Mark Andrews * size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * Number of bytes returned per hash. This must be true:
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * threshold * 2 <= digest_size_in_bytes
0b056755b2f423ba5f6adac8f7851d78f7d11437David Lawrence#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * Size of the input event queue in samples.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * The number of times we'll "reseed" for pseudorandom seeds. This is an
0b056755b2f423ba5f6adac8f7851d78f7d11437David Lawrence * extremely weak pseudorandom seed. If the caller is using lots of
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * pseudorandom data and they cannot provide a stronger random source,
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * there is little we can do other than hope they're smart enough to
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * call _adddata() with something better than we can come up with.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrencetypedef struct {
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_uint32_t cursor; /* current add point in the pool */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_uint32_t entropy; /* current entropy estimate in bits */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_uint32_t pseudo; /* bits extracted in pseudorandom */
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson isc_uint32_t rotate; /* how many bits to rotate by */
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_uint32_t pool[RND_POOLWORDS]; /* random pool data */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencetypedef struct {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t last_time; /* last time recorded */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t last_delta; /* last delta value */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t last_delta2; /* last delta2 value */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t nsamples; /* number of samples filled in */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t *extra; /* extra samples added in */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencetypedef struct {
330705066b03f6ce0bc08a4bbfc5d2418038c68dBrian Wellingtontypedef struct {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencetypedef struct {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence int fd; /* fd for the file, or -1 if closed */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence unsigned int type;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_uint32_t total; /* entropy from this source */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define ENTROPY_SOURCETYPE_SAMPLE 1 /* Type is a sample source */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define ENTROPY_SOURCETYPE_FILE 2 /* Type is a file source */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence#define ENTROPY_SOURCETYPE_CALLBACK 3 /* Type is a callback source */
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence * The random pool "taps"
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencestatic inline void
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrenceentropypool_add_word(isc_entropypool_t *, isc_uint32_t);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencefillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafssonstatic unsigned int
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencecrunchsamples(isc_entropy_t *, sample_queue_t *sq);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrencestatic inline void
fd4810861c0c0ccb9aebde94e9d289442b2630dbMark Andrewssamplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrewssamplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * Add in entropy, even when the value we're adding in could be
78838d3e0cd62423c23de5503910e01884d2104bBrian Wellington * very large.
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsstatic inline void
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsadd_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews /* clamp input. Yes, this must be done. */
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews /* Add in the entropy we already have. */
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews /* Clamp. */
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * Decrement the amount of entropy the pool has.
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewsstatic inline void
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewssubtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Add in entropy, even when the value we're adding in could be
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrews * very large.
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrewsstatic inline void
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrewsadd_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews /* clamp input. Yes, this must be done. */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews /* Add in the pseudo we already have. */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews /* Clamp. */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews * Decrement the amount of pseudo the pool has.
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellingtonstatic inline void
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellingtonsubtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * Add one word to the pool, rotating the input as needed.
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellingtonstatic inline void
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellingtonentropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * Steal some values out of the pool, and xor them into the
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * word we were given.
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * Mix the new value into the pool using xor. This will
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington * prevent the actual values from being known to the caller
87ecd67dae468cf5c9bae213c6fa321449b2ebc2Andreas Gustafsson * since the previous values are assumed to be unknown as well.
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
87ecd67dae468cf5c9bae213c6fa321449b2ebc2Andreas Gustafsson val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews ((val << rp->rotate) | (val >> (32 - rp->rotate)));
bcd7fdf06ca76eb2f6eb157f56b612c503e062a7Mark Andrews * If we have looped around the pool, increment the rotate
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews * variable so the next value will get xored in rotated to
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington * a different position.
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington * Increment by a value that is relativly prime to the word size
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington * to try to spread the bits throughout the pool quickly when the
21825a8d005ccc2dfaf12889bf9eef3413555277Brian Wellington * pool is empty.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Add a buffer's worth of data to the pool.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Requires that the lock is held on the entropy pool.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonentropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graff unsigned long addr;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence addr = (unsigned long)p;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrencestatic inline void
d981ca645597116d227a48bf37cc5edc061c854dBob Halley * After we've reseeded 100 times, only add new timing info every
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * 50 requests. This will keep us from using lots and lots of
e6bd97dded968f82e26b270842b789bff7bca422Mark Andrews * CPU just to return bad pseudorandom data anyway.
5d2026ea7b5ae43bbd69d98b747f75ba3290bef1Mark Andrewsstatic unsigned int
6c29053a20f7614167bafa4388c666644a095349Andreas Gustafssonget_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews unsigned int added;
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews while (desired > 0) {
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews if (n < 0) {
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews if (n == 0) {
29c818c7d40fc8898b062903ec703851328a4deaMark Andrewsstatic unsigned int
29c818c7d40fc8898b062903ec703851328a4deaMark Andrewsget_from_callback(isc_entropysource_t *source, unsigned int desired,
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews isc_cbsource_t *cbs = &source->sources.callback;
29c818c7d40fc8898b062903ec703851328a4deaMark Andrews unsigned int added;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews unsigned int got;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews if (!cbs->start_called && cbs->startfunc != NULL) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = cbs->startfunc(source, cbs->arg, blocking);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews while (desired > 0 && result == ISC_R_SUCCESS) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = cbs->getfunc(source, cbs->arg, blocking);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Poll each source, trying to get data from it to stuff into the entropy
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsfillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
d981ca645597116d227a48bf37cc5edc061c854dBob Halley unsigned int added;
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews unsigned int needed;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * This logic is a little strange, so an explanation is in order.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * If needed is 0, it means we are being asked to "fill to whatever
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews * we think is best." This means that if we have at least a
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * partially full pool (say, > 1/4th of the pool) we probably don't
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * need to add anything.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * Also, we will check to see if the "pseudo" count is too high.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * If it is, try to mix in better data. Too high is currently
19d365e4448f1782611280b020987988b7ac3210Mark Andrews * defined as 1/4th of the pool.
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews * Next, if we are asked to add a specific bit of entropy, make
19d365e4448f1782611280b020987988b7ac3210Mark Andrews * certain that we will do so. Clamp how much we try to add to
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Note that if we are in a blocking mode, we will only try to
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * get as much data as we need, not as much as we might want
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff * to build up.
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews * In any case, clamp how much we need to how much we can add.
19d365e4448f1782611280b020987988b7ac3210Mark Andrews needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson * But wait! If we're not yet initialized, we need at least
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * THRESHOLD_BITS
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * of randomness.
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Poll each file source to see if we can read anything useful from
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews * it. XXXMLG When where are multiple sources, we should keep a
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews * record of which one we last used so we can start from it (or the
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews * next one) to avoid letting some sources build up entropy while
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews * others are always drained.
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews for (nsource = 0 ; nsource < ent->nsources ; nsource++) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews unsigned int got;
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews * Here, if there are bits remaining to be had and we can block,
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson * check to see if we have a callback source. If so, call them.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence unsigned int got;
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halley got = get_from_callback(source, remaining, blocking);
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson * Mark as initialized if we've added enough data.
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington cc = select(maxfd + 1, &reads, NULL, NULL, NULL);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * Extract some number of bytes from the random pool, decreasing the
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * estimate of randomness as each byte is extracted.
e086935752b6e2f51ef2985fee21ccfff617b115David Lawrence * Do this by stiring the pool and returning a part of hash as randomness.
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * Note that no secrets are given away here since parts of the hash are
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * xored together before returned.
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * Honor the request from the caller to only return good data, any data,
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellingtonisc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson unsigned int *returned, unsigned int flags)
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington unsigned int i;
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington unsigned char digest[ISC_SHA1_DIGESTLENGTH];
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews while (remain != 0) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson * If we are extracting good data only, make certain we
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * have enough data in our pool for this pass. If we don't,
20b20b23948b90cb2f7d7f402da99d09f837efd0David Lawrence * get some, and fail if we can't, and partial returns
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * are not ok.
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington fillcount = ISC_MAX(remain * 8, count * 8);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews * If, however, we have at least THRESHOLD_BITS
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * of entropy in the pool, don't block here. It is
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * better to drain the pool once in a while and
228c679d7a269423019f7c528db92e855f08240bMark Andrews * then refill it than it is to constantly keep the
228c679d7a269423019f7c528db92e855f08240bMark Andrews * pool full.
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington * Verify that we got enough entropy to do one
228c679d7a269423019f7c528db92e855f08240bMark Andrews * extraction. If we didn't, bail.
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * If we've extracted half our pool size in bits
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington * since the last refresh, try to refresh here.
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews * If we've not initialized with enough good random
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * data, seed with our crappy code.
8dd5237a27e2e824d18f835dc711573aeb23a173Mark Andrews isc_sha1_update(&hash, (void *)(ent->pool.pool),
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews * Stir the extracted data (all of it) back into the pool.
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews for (i = 0; i < count; i++)
82d05588933a3c765aa8518fe455d6477d640b99Mark Andrews buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* put the entropy we almost extracted back */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graffisc_entropypool_invalidate(isc_entropypool_t *pool) {
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrewsisc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews * We need a lock.
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews if (isc_mutex_init(&ent->lock) != ISC_R_SUCCESS) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * From here down, no failures will/can occur.
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews * Requires "ent" be locked.
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencedestroysource(isc_entropysource_t **sourcep) {
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson ISC_LIST_UNLINK(ent->sources, source, link);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews samplequeue_release(ent, &source->sources.sample.samplequeue);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews if (cbs->start_called && cbs->stopfunc != NULL) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews memset(source, 0, sizeof(isc_entropysource_t));
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
d981ca645597116d227a48bf37cc5edc061c854dBob Halley * Here, detach non-sample sources.
d981ca645597116d227a48bf37cc5edc061c854dBob Halley * If there are other types of sources, we've found a bug.
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley * Make a fd non-blocking
0513f89e68f82f9ec54e7af9c979a7c43babbe31Bob Halley "fcntl(%d, F_SETFL, %d): %s",
6324997211a5e2d82528dcde98e8981190a35faeMichael Graffisc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson fd = open(fname, O_RDONLY | O_NONBLOCK, 0);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * From here down, no failures can occur.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson memset(source->name, 0, sizeof(source->name));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Hook it into the entropy system.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson ISC_LIST_APPEND(ent->sources, source, link);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_entropy_destroysource(isc_entropysource_t **sourcep) {
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellingtonisc_entropy_createcallbacksource(isc_entropy_t *ent,
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington REQUIRE(sourcep != NULL && *sourcep == NULL);
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff ret = samplesource_allocate(ent, &cbs->samplequeue);
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff * From here down, no failures can occur.
6b0ce7d29fac9df84ed34aa2d4634e754aec750dAndreas Gustafsson source->type = ENTROPY_SOURCETYPE_CALLBACK;
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff memset(source->name, 0, sizeof(source->name));
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff * Hook it into the entropy system.
d3a86da2e8f09e2c3f55721aae537b9cacc7e537Andreas Gustafsson isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
d3a86da2e8f09e2c3f55721aae537b9cacc7e537Andreas Gustafssonisc_entropy_stopcallbacksources(isc_entropy_t *ent) {
fa460c223a69449eaac67ddb6abafe74f5e1ff02Michael Graff if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (cbs->start_called && cbs->stopfunc != NULL) {
94a537e6ab3069f8d34e12e5ea722250be2b89c8Michael Graffisc_entropy_createsamplesource(isc_entropy_t *ent,
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
ebfcb6cf66283096ebda1503b6cc042ce86b6bedBrian Wellington * From here down, no failures can occur.
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff memset(source->name, 0, sizeof(source->name));
d3a86da2e8f09e2c3f55721aae537b9cacc7e537Andreas Gustafsson * Hook it into the entropy system.
8c962eba3d6faebc008806ebb6bb9d08089118e9Andreas Gustafsson ISC_LIST_APPEND(ent->sources, source, link);
d3a86da2e8f09e2c3f55721aae537b9cacc7e537Andreas Gustafsson isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
d3a86da2e8f09e2c3f55721aae537b9cacc7e537Andreas Gustafssonstatic inline unsigned int
d3a86da2e8f09e2c3f55721aae537b9cacc7e537Andreas Gustafssonestimate_entropy(sample_queue_t *sq, isc_uint32_t t)
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff * If the time counter has overflowed, calculate the real difference.
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews * If it has not, it is simplier.
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews * Calculate the second and third order differentials
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews * If any delta is 0, we got no entropy. If all are non-zero, we
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * might have something.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson if (delta == 0 || delta2 == 0 || delta3 == 0)
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff * We could find the smallest delta and claim we got log2(delta)
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * bits, but for now return that we found 1 bit.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonstatic unsigned int
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssoncrunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson unsigned int ns;
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Prime the values by adding in the first 4 samples in. This
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * should completely initialize the delta calculations.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson (void)estimate_entropy(sq, sq->samples[ns]);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson added += estimate_entropy(sq, sq->samples[ns]);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
54c26ab21c61c6d6b1e484bb88dc3ac263845d17Mark Andrews entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Move the last 4 samples into the first 4 positions, and start
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * adding new samples from that point.
88ba491496daf4463a2c898be8a6c47775a6d048Mark Andrews sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
88ba491496daf4463a2c898be8a6c47775a6d048Mark Andrews sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * queue was full when this function was called.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonaddsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssonisc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafsson sq = &source->sources.sample.samplequeue;
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrenceisc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsisc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews entropypool_adddata(ent, data, length, entropy);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "Entropy pool %p: refcnt %u cursor %u,"
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews " rotate %u entropy %u pseudo %u nsources %u"
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews " nextsource %p initialized %u initcount %u\n"),
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews ent->nsources, ent->nextsource, ent->initialized,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * This function ignores locking. Use at your own risk.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsisc_entropy_stats(isc_entropy_t *ent, FILE *out) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsisc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {