mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-29 21:47:59 +00:00
Fixed duplicate routines
This commit is contained in:
parent
6f5d6e3f8c
commit
a38e51e5ef
@ -15,7 +15,7 @@
|
|||||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: entropy.c,v 1.1 2001/06/21 14:19:20 tale Exp $ */
|
/* $Id: entropy.c,v 1.2 2001/07/06 05:22:46 mayer Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the system depenedent part of the ISC entropy API.
|
* This is the system depenedent part of the ISC entropy API.
|
||||||
@ -72,47 +72,6 @@ get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
|
|||||||
return (added);
|
return (added);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
get_from_callback(isc_entropysource_t *source, unsigned int desired,
|
|
||||||
isc_boolean_t blocking)
|
|
||||||
{
|
|
||||||
isc_entropy_t *ent = source->ent;
|
|
||||||
isc_cbsource_t *cbs = &source->sources.callback;
|
|
||||||
unsigned int added;
|
|
||||||
unsigned int got;
|
|
||||||
isc_result_t result;
|
|
||||||
|
|
||||||
if (desired == 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
if (source->bad)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
if (!cbs->start_called && cbs->startfunc != NULL) {
|
|
||||||
result = cbs->startfunc(source, cbs->arg, blocking);
|
|
||||||
if (result != ISC_R_SUCCESS)
|
|
||||||
return (0);
|
|
||||||
cbs->start_called = ISC_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
added = 0;
|
|
||||||
result = ISC_R_SUCCESS;
|
|
||||||
while (desired > 0 && result == ISC_R_SUCCESS) {
|
|
||||||
result = cbs->getfunc(source, cbs->arg, blocking);
|
|
||||||
if (result == ISC_R_QUEUEFULL) {
|
|
||||||
got = crunchsamples(ent, &cbs->samplequeue);
|
|
||||||
added += got;
|
|
||||||
desired -= ISC_MIN(got, desired);
|
|
||||||
result = ISC_R_SUCCESS;
|
|
||||||
} else if (result != ISC_R_SUCCESS &&
|
|
||||||
result != ISC_R_NOTBLOCKING)
|
|
||||||
source->bad = ISC_TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return (added);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Poll each source, trying to get data from it to stuff into the entropy
|
* Poll each source, trying to get data from it to stuff into the entropy
|
||||||
* pool.
|
* pool.
|
||||||
@ -258,204 +217,7 @@ fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
|
|||||||
ent->initialized += added;
|
ent->initialized += added;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Extract some number of bytes from the random pool, decreasing the
|
|
||||||
* estimate of randomness as each byte is extracted.
|
|
||||||
*
|
|
||||||
* Do this by stiring the pool and returning a part of hash as randomness.
|
|
||||||
* Note that no secrets are given away here since parts of the hash are
|
|
||||||
* xored together before returned.
|
|
||||||
*
|
|
||||||
* Honor the request from the caller to only return good data, any data,
|
|
||||||
* etc.
|
|
||||||
*/
|
|
||||||
isc_result_t
|
|
||||||
isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
|
|
||||||
unsigned int *returned, unsigned int flags)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
isc_sha1_t hash;
|
|
||||||
unsigned char digest[ISC_SHA1_DIGESTLENGTH];
|
|
||||||
isc_uint32_t remain, deltae, count, total;
|
|
||||||
isc_uint8_t *buf;
|
|
||||||
isc_boolean_t goodonly, partial, blocking;
|
|
||||||
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
REQUIRE(data != NULL);
|
|
||||||
REQUIRE(length > 0);
|
|
||||||
|
|
||||||
goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
|
|
||||||
partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
|
|
||||||
blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
|
|
||||||
|
|
||||||
REQUIRE(!partial || returned != NULL);
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
remain = length;
|
|
||||||
buf = data;
|
|
||||||
total = 0;
|
|
||||||
while (remain != 0) {
|
|
||||||
count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we are extracting good data only, make certain we
|
|
||||||
* have enough data in our pool for this pass. If we don't,
|
|
||||||
* get some, and fail if we can't, and partial returns
|
|
||||||
* are not ok.
|
|
||||||
*/
|
|
||||||
if (goodonly) {
|
|
||||||
unsigned int fillcount;
|
|
||||||
|
|
||||||
fillcount = ISC_MAX(remain * 8, count * 8);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If, however, we have at least THRESHOLD_BITS
|
|
||||||
* of entropy in the pool, don't block here. It is
|
|
||||||
* better to drain the pool once in a while and
|
|
||||||
* then refill it than it is to constantly keep the
|
|
||||||
* pool full.
|
|
||||||
*/
|
|
||||||
if (ent->pool.entropy >= THRESHOLD_BITS)
|
|
||||||
fillpool(ent, fillcount, ISC_FALSE);
|
|
||||||
else
|
|
||||||
fillpool(ent, fillcount, blocking);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Verify that we got enough entropy to do one
|
|
||||||
* extraction. If we didn't, bail.
|
|
||||||
*/
|
|
||||||
if (ent->pool.entropy < THRESHOLD_BITS) {
|
|
||||||
if (!partial)
|
|
||||||
goto zeroize;
|
|
||||||
else
|
|
||||||
goto partial_output;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* If we've extracted half our pool size in bits
|
|
||||||
* since the last refresh, try to refresh here.
|
|
||||||
*/
|
|
||||||
if (ent->initialized < THRESHOLD_BITS)
|
|
||||||
fillpool(ent, THRESHOLD_BITS, blocking);
|
|
||||||
else
|
|
||||||
fillpool(ent, 0, ISC_FALSE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we've not initialized with enough good random
|
|
||||||
* data, seed with our crappy code.
|
|
||||||
*/
|
|
||||||
if (ent->initialized < THRESHOLD_BITS)
|
|
||||||
reseed(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_sha1_init(&hash);
|
|
||||||
isc_sha1_update(&hash, (void *)(ent->pool.pool),
|
|
||||||
RND_POOLBYTES);
|
|
||||||
isc_sha1_final(&hash, digest);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stir the extracted data (all of it) back into the pool.
|
|
||||||
*/
|
|
||||||
entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
|
|
||||||
|
|
||||||
buf += count;
|
|
||||||
remain -= count;
|
|
||||||
|
|
||||||
deltae = count * 8;
|
|
||||||
deltae = ISC_MIN(deltae, ent->pool.entropy);
|
|
||||||
total += deltae;
|
|
||||||
subtract_entropy(ent, deltae);
|
|
||||||
add_pseudo(ent, count * 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
partial_output:
|
|
||||||
memset(digest, 0, sizeof(digest));
|
|
||||||
|
|
||||||
if (returned != NULL)
|
|
||||||
*returned = (length - remain);
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
return (ISC_R_SUCCESS);
|
|
||||||
|
|
||||||
zeroize:
|
|
||||||
/* put the entropy we almost extracted back */
|
|
||||||
add_entropy(ent, total);
|
|
||||||
memset(data, 0, length);
|
|
||||||
memset(digest, 0, sizeof(digest));
|
|
||||||
if (returned != NULL)
|
|
||||||
*returned = 0;
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
return (ISC_R_NOENTROPY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
isc_entropypool_init(isc_entropypool_t *pool) {
|
|
||||||
pool->cursor = RND_POOLWORDS - 1;
|
|
||||||
pool->entropy = 0;
|
|
||||||
pool->pseudo = 0;
|
|
||||||
pool->rotate = 0;
|
|
||||||
memset(pool->pool, 0, RND_POOLBYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
isc_entropypool_invalidate(isc_entropypool_t *pool) {
|
|
||||||
pool->cursor = 0;
|
|
||||||
pool->entropy = 0;
|
|
||||||
pool->pseudo = 0;
|
|
||||||
pool->rotate = 0;
|
|
||||||
memset(pool->pool, 0, RND_POOLBYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_result_t
|
|
||||||
isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
|
|
||||||
isc_result_t ret;
|
|
||||||
isc_entropy_t *ent;
|
|
||||||
|
|
||||||
REQUIRE(mctx != NULL);
|
|
||||||
REQUIRE(entp != NULL && *entp == NULL);
|
|
||||||
|
|
||||||
ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
|
|
||||||
if (ent == NULL)
|
|
||||||
return (ISC_R_NOMEMORY);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need a lock.
|
|
||||||
*/
|
|
||||||
if (isc_mutex_init(&ent->lock) != ISC_R_SUCCESS) {
|
|
||||||
ret = ISC_R_UNEXPECTED;
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* From here down, no failures will/can occur.
|
|
||||||
*/
|
|
||||||
ISC_LIST_INIT(ent->sources);
|
|
||||||
ent->nextsource = NULL;
|
|
||||||
ent->nsources = 0;
|
|
||||||
ent->mctx = NULL;
|
|
||||||
isc_mem_attach(mctx, &ent->mctx);
|
|
||||||
ent->refcnt = 1;
|
|
||||||
ent->initialized = 0;
|
|
||||||
ent->initcount = 0;
|
|
||||||
ent->magic = ENTROPY_MAGIC;
|
|
||||||
|
|
||||||
isc_entropypool_init(&ent->pool);
|
|
||||||
|
|
||||||
*entp = ent;
|
|
||||||
return (ISC_R_SUCCESS);
|
|
||||||
|
|
||||||
errout:
|
|
||||||
isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Requires "ent" be locked.
|
* Requires "ent" be locked.
|
||||||
@ -465,72 +227,6 @@ destroyfilesource(isc_entropyfilesource_t *source) {
|
|||||||
CryptReleaseContext(source->handle, 0);
|
CryptReleaseContext(source->handle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline isc_boolean_t
|
|
||||||
destroy_check(isc_entropy_t *ent) {
|
|
||||||
isc_entropysource_t *source;
|
|
||||||
|
|
||||||
if (ent->refcnt > 0)
|
|
||||||
return (ISC_FALSE);
|
|
||||||
|
|
||||||
source = ISC_LIST_HEAD(ent->sources);
|
|
||||||
while (source != NULL) {
|
|
||||||
switch (source->type) {
|
|
||||||
case ENTROPY_SOURCETYPE_FILE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return (ISC_FALSE);
|
|
||||||
}
|
|
||||||
source = ISC_LIST_NEXT(source, link);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ISC_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
destroy(isc_entropy_t **entp) {
|
|
||||||
isc_entropy_t *ent;
|
|
||||||
isc_entropysource_t *source;
|
|
||||||
isc_mem_t *mctx;
|
|
||||||
|
|
||||||
REQUIRE(entp != NULL && *entp != NULL);
|
|
||||||
ent = *entp;
|
|
||||||
*entp = NULL;
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
REQUIRE(ent->refcnt == 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Here, detach non-sample sources.
|
|
||||||
*/
|
|
||||||
source = ISC_LIST_HEAD(ent->sources);
|
|
||||||
while (source != NULL) {
|
|
||||||
switch(source->type) {
|
|
||||||
case ENTROPY_SOURCETYPE_FILE:
|
|
||||||
destroysource(&source);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
source = ISC_LIST_HEAD(ent->sources);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there are other types of sources, we've found a bug.
|
|
||||||
*/
|
|
||||||
REQUIRE(ISC_LIST_EMPTY(ent->sources));
|
|
||||||
|
|
||||||
mctx = ent->mctx;
|
|
||||||
|
|
||||||
isc_entropypool_invalidate(&ent->pool);
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
DESTROYLOCK(&ent->lock);
|
|
||||||
|
|
||||||
memset(ent, 0, sizeof(isc_entropy_t));
|
|
||||||
isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
|
|
||||||
isc_mem_detach(&mctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
|
isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
|
||||||
@ -597,404 +293,6 @@ isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
isc_entropy_destroysource(isc_entropysource_t **sourcep) {
|
|
||||||
isc_entropysource_t *source;
|
|
||||||
isc_entropy_t *ent;
|
|
||||||
isc_boolean_t killit;
|
|
||||||
|
|
||||||
REQUIRE(sourcep != NULL);
|
|
||||||
REQUIRE(VALID_SOURCE(*sourcep));
|
|
||||||
|
|
||||||
source = *sourcep;
|
|
||||||
*sourcep = NULL;
|
|
||||||
|
|
||||||
ent = source->ent;
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
destroysource(&source);
|
|
||||||
|
|
||||||
killit = destroy_check(ent);
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
if (killit)
|
|
||||||
destroy(&ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_result_t
|
|
||||||
isc_entropy_createcallbacksource(isc_entropy_t *ent,
|
|
||||||
isc_entropystart_t start,
|
|
||||||
isc_entropyget_t get,
|
|
||||||
isc_entropystop_t stop,
|
|
||||||
void *arg,
|
|
||||||
isc_entropysource_t **sourcep)
|
|
||||||
{
|
|
||||||
isc_result_t ret;
|
|
||||||
isc_entropysource_t *source;
|
|
||||||
isc_cbsource_t *cbs;
|
|
||||||
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
REQUIRE(get != NULL);
|
|
||||||
REQUIRE(sourcep != NULL && *sourcep == NULL);
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
|
|
||||||
if (source == NULL) {
|
|
||||||
ret = ISC_R_NOMEMORY;
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
source->bad = ISC_FALSE;
|
|
||||||
|
|
||||||
cbs = &source->sources.callback;
|
|
||||||
|
|
||||||
ret = samplesource_allocate(ent, &cbs->samplequeue);
|
|
||||||
if (ret != ISC_R_SUCCESS)
|
|
||||||
goto errout;
|
|
||||||
|
|
||||||
cbs->start_called = ISC_FALSE;
|
|
||||||
cbs->startfunc = start;
|
|
||||||
cbs->getfunc = get;
|
|
||||||
cbs->stopfunc = stop;
|
|
||||||
cbs->arg = arg;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* From here down, no failures can occur.
|
|
||||||
*/
|
|
||||||
source->magic = SOURCE_MAGIC;
|
|
||||||
source->type = ENTROPY_SOURCETYPE_CALLBACK;
|
|
||||||
source->ent = ent;
|
|
||||||
source->total = 0;
|
|
||||||
memset(source->name, 0, sizeof(source->name));
|
|
||||||
ISC_LINK_INIT(source, link);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hook it into the entropy system.
|
|
||||||
*/
|
|
||||||
ISC_LIST_APPEND(ent->sources, source, link);
|
|
||||||
ent->nsources++;
|
|
||||||
|
|
||||||
*sourcep = source;
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
return (ISC_R_SUCCESS);
|
|
||||||
|
|
||||||
errout:
|
|
||||||
if (source != NULL)
|
|
||||||
isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
|
|
||||||
isc_entropysource_t *source;
|
|
||||||
isc_cbsource_t *cbs;
|
|
||||||
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
source = ISC_LIST_HEAD(ent->sources);
|
|
||||||
while (source != NULL) {
|
|
||||||
if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
|
|
||||||
cbs = &source->sources.callback;
|
|
||||||
if (cbs->start_called && cbs->stopfunc != NULL) {
|
|
||||||
cbs->stopfunc(source, cbs->arg);
|
|
||||||
cbs->start_called = ISC_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
source = ISC_LIST_NEXT(source, link);
|
|
||||||
}
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_result_t
|
|
||||||
isc_entropy_createsamplesource(isc_entropy_t *ent,
|
|
||||||
isc_entropysource_t **sourcep)
|
|
||||||
{
|
|
||||||
isc_result_t ret;
|
|
||||||
isc_entropysource_t *source;
|
|
||||||
sample_queue_t *sq;
|
|
||||||
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
REQUIRE(sourcep != NULL && *sourcep == NULL);
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
|
|
||||||
if (source == NULL) {
|
|
||||||
ret = ISC_R_NOMEMORY;
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
sq = &source->sources.sample.samplequeue;
|
|
||||||
ret = samplesource_allocate(ent, sq);
|
|
||||||
if (ret != ISC_R_SUCCESS)
|
|
||||||
goto errout;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* From here down, no failures can occur.
|
|
||||||
*/
|
|
||||||
source->magic = SOURCE_MAGIC;
|
|
||||||
source->type = ENTROPY_SOURCETYPE_SAMPLE;
|
|
||||||
source->ent = ent;
|
|
||||||
source->total = 0;
|
|
||||||
memset(source->name, 0, sizeof(source->name));
|
|
||||||
ISC_LINK_INIT(source, link);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hook it into the entropy system.
|
|
||||||
*/
|
|
||||||
ISC_LIST_APPEND(ent->sources, source, link);
|
|
||||||
ent->nsources++;
|
|
||||||
|
|
||||||
*sourcep = source;
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
return (ISC_R_SUCCESS);
|
|
||||||
|
|
||||||
errout:
|
|
||||||
if (source != NULL)
|
|
||||||
isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
estimate_entropy(sample_queue_t *sq, isc_uint32_t t)
|
|
||||||
{
|
|
||||||
isc_int32_t delta;
|
|
||||||
isc_int32_t delta2;
|
|
||||||
isc_int32_t delta3;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the time counter has overflowed, calculate the real difference.
|
|
||||||
* If it has not, it is simplier.
|
|
||||||
*/
|
|
||||||
if (t < sq->last_time)
|
|
||||||
delta = UINT_MAX - sq->last_time + t;
|
|
||||||
else
|
|
||||||
delta = sq->last_time - t;
|
|
||||||
|
|
||||||
if (delta < 0)
|
|
||||||
delta = -delta;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate the second and third order differentials
|
|
||||||
*/
|
|
||||||
delta2 = sq->last_delta - delta;
|
|
||||||
if (delta2 < 0)
|
|
||||||
delta2 = -delta2;
|
|
||||||
|
|
||||||
delta3 = sq->last_delta2 - delta2;
|
|
||||||
if (delta3 < 0)
|
|
||||||
delta3 = -delta3;
|
|
||||||
|
|
||||||
sq->last_time = t;
|
|
||||||
sq->last_delta = delta;
|
|
||||||
sq->last_delta2 = delta2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If any delta is 0, we got no entropy. If all are non-zero, we
|
|
||||||
* might have something.
|
|
||||||
*/
|
|
||||||
if (delta == 0 || delta2 == 0 || delta3 == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We could find the smallest delta and claim we got log2(delta)
|
|
||||||
* bits, but for now return that we found 1 bit.
|
|
||||||
*/
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
|
|
||||||
unsigned int ns;
|
|
||||||
unsigned int added;
|
|
||||||
|
|
||||||
if (sq->nsamples < 6)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
added = 0;
|
|
||||||
sq->last_time = sq->samples[0];
|
|
||||||
sq->last_delta = 0;
|
|
||||||
sq->last_delta2 = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prime the values by adding in the first 4 samples in. This
|
|
||||||
* should completely initialize the delta calculations.
|
|
||||||
*/
|
|
||||||
for (ns = 0 ; ns < 4 ; ns++)
|
|
||||||
(void)estimate_entropy(sq, sq->samples[ns]);
|
|
||||||
|
|
||||||
for (ns = 4 ; ns < sq->nsamples ; ns++)
|
|
||||||
added += estimate_entropy(sq, sq->samples[ns]);
|
|
||||||
|
|
||||||
entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
|
|
||||||
entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Move the last 4 samples into the first 4 positions, and start
|
|
||||||
* adding new samples from that point.
|
|
||||||
*/
|
|
||||||
for (ns = 0 ; ns < 4 ; ns++) {
|
|
||||||
sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
|
|
||||||
sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
|
|
||||||
}
|
|
||||||
|
|
||||||
sq->nsamples = 4;
|
|
||||||
|
|
||||||
return (added);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add a sample, and return ISC_R_SUCCESS if the queue has become full,
|
|
||||||
* ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
|
|
||||||
* queue was full when this function was called.
|
|
||||||
*/
|
|
||||||
static isc_result_t
|
|
||||||
addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
|
|
||||||
if (sq->nsamples >= RND_EVENTQSIZE)
|
|
||||||
return (ISC_R_NOMORE);
|
|
||||||
|
|
||||||
sq->samples[sq->nsamples] = sample;
|
|
||||||
sq->extra[sq->nsamples] = extra;
|
|
||||||
sq->nsamples++;
|
|
||||||
|
|
||||||
if (sq->nsamples >= RND_EVENTQSIZE)
|
|
||||||
return (ISC_R_QUEUEFULL);
|
|
||||||
|
|
||||||
return (ISC_R_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_result_t
|
|
||||||
isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
|
|
||||||
isc_uint32_t extra)
|
|
||||||
{
|
|
||||||
isc_entropy_t *ent;
|
|
||||||
sample_queue_t *sq;
|
|
||||||
unsigned int entropy;
|
|
||||||
isc_result_t result;
|
|
||||||
|
|
||||||
REQUIRE(VALID_SOURCE(source));
|
|
||||||
|
|
||||||
ent = source->ent;
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
sq = &source->sources.sample.samplequeue;
|
|
||||||
result = addsample(sq, sample, extra);
|
|
||||||
if (result == ISC_R_QUEUEFULL) {
|
|
||||||
entropy = crunchsamples(ent, sq);
|
|
||||||
add_entropy(ent, entropy);
|
|
||||||
}
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
return (result);
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_result_t
|
|
||||||
isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
|
|
||||||
isc_uint32_t extra)
|
|
||||||
{
|
|
||||||
sample_queue_t *sq;
|
|
||||||
isc_result_t result;
|
|
||||||
|
|
||||||
REQUIRE(VALID_SOURCE(source));
|
|
||||||
REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
|
|
||||||
|
|
||||||
sq = &source->sources.callback.samplequeue;
|
|
||||||
result = addsample(sq, sample, extra);
|
|
||||||
|
|
||||||
return (result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
|
|
||||||
isc_uint32_t entropy)
|
|
||||||
{
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
entropypool_adddata(ent, data, length, entropy);
|
|
||||||
|
|
||||||
if (ent->initialized < THRESHOLD_BITS)
|
|
||||||
ent->initialized = THRESHOLD_BITS;
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dumpstats(isc_entropy_t *ent, FILE *out) {
|
|
||||||
fprintf(out,
|
|
||||||
isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
|
|
||||||
ISC_MSG_ENTROPYSTATS,
|
|
||||||
"Entropy pool %p: refcnt %u cursor %u,"
|
|
||||||
" rotate %u entropy %u pseudo %u nsources %u"
|
|
||||||
" nextsource %p initialized %u initcount %u\n"),
|
|
||||||
ent, ent->refcnt,
|
|
||||||
ent->pool.cursor, ent->pool.rotate,
|
|
||||||
ent->pool.entropy, ent->pool.pseudo,
|
|
||||||
ent->nsources, ent->nextsource, ent->initialized,
|
|
||||||
ent->initcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function ignores locking. Use at your own risk.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
dumpstats(ent, out);
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
|
|
||||||
REQUIRE(VALID_ENTROPY(ent));
|
|
||||||
REQUIRE(entp != NULL && *entp == NULL);
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
ent->refcnt++;
|
|
||||||
*entp = ent;
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
isc_entropy_detach(isc_entropy_t **entp) {
|
|
||||||
isc_entropy_t *ent;
|
|
||||||
isc_boolean_t killit;
|
|
||||||
|
|
||||||
REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
|
|
||||||
ent = *entp;
|
|
||||||
*entp = NULL;
|
|
||||||
|
|
||||||
LOCK(&ent->lock);
|
|
||||||
|
|
||||||
REQUIRE(ent->refcnt > 0);
|
|
||||||
ent->refcnt--;
|
|
||||||
|
|
||||||
killit = destroy_check(ent);
|
|
||||||
|
|
||||||
UNLOCK(&ent->lock);
|
|
||||||
|
|
||||||
if (killit)
|
|
||||||
destroy(&ent);
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user