mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-08 19:02:05 -04:00
add stirring functions and other bits. Snapshot.
This commit is contained in:
parent
db06b81059
commit
016742f7d8
2 changed files with 288 additions and 16 deletions
|
|
@ -105,7 +105,7 @@ isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp);
|
|||
* Create a new entropy object.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
isc_entropy_destroy(isc_entropy_t **entp);
|
||||
/*
|
||||
* Destroys an entropy source.
|
||||
|
|
@ -134,7 +134,7 @@ isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname,
|
|||
* The file will never be opened/read again once EOF is reached.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
isc_entropy_destroysource(isc_entropysource_t **sourcep);
|
||||
/*
|
||||
* Removes an entropy source from the entropy system.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@
|
|||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/entropy.h>
|
||||
#include <isc/list.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/sha1.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
|
|
@ -42,21 +46,29 @@
|
|||
#define RND_POOLBITS (RND_POOLWORDS * 32)
|
||||
|
||||
/*
|
||||
* Number of bytes returned per hash.
|
||||
* Number of bytes returned per hash. This must be true:
|
||||
* threshold * 2 <= digest_size_in_bytes
|
||||
*/
|
||||
#define RND_ENTROPY_THRESHOLD 12
|
||||
#define RND_ENTROPY_THRESHOLD 10
|
||||
|
||||
/*
|
||||
* Size of the input event queue.
|
||||
* Size of the input event queue in samples.
|
||||
*/
|
||||
#define RND_EVENTQSIZE 128
|
||||
#define RND_EVENTQSIZE 32
|
||||
|
||||
typedef struct {
|
||||
isc_uint32_t cursor; /* current add point in the pool */
|
||||
isc_uint32_t entropy; /* current entropy estimate in bits */
|
||||
isc_uint32_t rotate; /* how many bits to rotate by */
|
||||
isc_uint32_t pool[RND_POOLWORDS]; /* random pool data */
|
||||
} isc_rndpool_t;
|
||||
} isc_entropypool_t;
|
||||
|
||||
struct isc_entropy {
|
||||
isc_mutex_t lock;
|
||||
isc_mem_t *mctx;
|
||||
isc_entropypool_t pool;
|
||||
ISC_LIST(isc_entropysource_t) sources;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
isc_uint32_t last_time; /* last time recorded */
|
||||
|
|
@ -66,32 +78,286 @@ typedef struct {
|
|||
isc_uint32_t nsamples; /* number of samples filled in */
|
||||
isc_uint32_t *samples; /* the samples */
|
||||
isc_uint32_t *extra; /* extra samples added in */
|
||||
} isc_rndsamplesource_t;
|
||||
} isc_entropysamplesource_t ;
|
||||
|
||||
typedef struct {
|
||||
int fd; /* fd for the file, or -1 if closed */
|
||||
} isc_rndfilesource_t;
|
||||
} isc_entropyfilesource_t;
|
||||
|
||||
typedef struct {
|
||||
struct isc_entropysource {
|
||||
unsigned int type;
|
||||
unsigned int flags; /* flags */
|
||||
isc_uint32_t total; /* entropy from this source */
|
||||
char name[32];
|
||||
union {
|
||||
isc_rndsamplesource_t samplesource;
|
||||
isc_rndfilesource_t filesource;
|
||||
isc_entropysamplesource_t samplesource;
|
||||
isc_entropyfilesource_t filesource;
|
||||
} sources;
|
||||
} isc_rndsource_t;
|
||||
};
|
||||
|
||||
#define RND_TYPE_SAMPLE 1 /* Type is a sample source */
|
||||
#define RND_TYPE_FILE 2 /* Type is a file source */
|
||||
|
||||
isc_result_t
|
||||
isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
|
||||
/*
|
||||
* The random pool "taps"
|
||||
*/
|
||||
#define TAP1 99
|
||||
#define TAP2 59
|
||||
#define TAP3 31
|
||||
#define TAP4 9
|
||||
#define TAP5 7
|
||||
|
||||
static inline void
|
||||
entropypool_add_word(isc_entropypool_t *, isc_uint32_t);
|
||||
|
||||
/*
|
||||
* Add one word to the pool, rotating the input as needed.
|
||||
*/
|
||||
static inline void
|
||||
entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val)
|
||||
{
|
||||
/*
|
||||
* Steal some values out of the pool, and xor them into the
|
||||
* word we were given.
|
||||
*
|
||||
* Mix the new value into the pool using xor. This will
|
||||
* prevent the actual values from being known to the caller
|
||||
* since the previous values are assumed to be unknown as well.
|
||||
*/
|
||||
val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
|
||||
val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
|
||||
val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
|
||||
val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
|
||||
val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
|
||||
rp->pool[rp->cursor++] ^=
|
||||
((val << rp->rotate) | (val >> (32 - rp->rotate)));
|
||||
|
||||
/*
|
||||
* If we have looped around the pool, increment the rotate
|
||||
* variable so the next value will get xored in rotated to
|
||||
* a different position.
|
||||
* Increment by a value that is relativly prime to the word size
|
||||
* to try to spread the bits throughout the pool quickly when the
|
||||
* pool is empty.
|
||||
*/
|
||||
if (rp->cursor == RND_POOLWORDS) {
|
||||
rp->cursor = 0;
|
||||
rp->rotate = (rp->rotate + 7) & 31;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* add a buffer's worth of data to the pool.
|
||||
*/
|
||||
void
|
||||
entropypool_adddata(isc_entropypool_t *rp, void *p, unsigned int len,
|
||||
isc_uint32_t entropy)
|
||||
{
|
||||
isc_uint32_t val;
|
||||
isc_uint32_t addr;
|
||||
isc_uint8_t *buf;
|
||||
|
||||
addr = (isc_uint32_t)p;
|
||||
buf = p;
|
||||
|
||||
if ((addr & 0x03) != 0) {
|
||||
val = 0;
|
||||
switch (len) {
|
||||
case 3:
|
||||
val = *buf++;
|
||||
len--;
|
||||
case 2:
|
||||
val = val << 8 | *buf++;
|
||||
len--;
|
||||
case 1:
|
||||
val = val << 8 | *buf++;
|
||||
len--;
|
||||
}
|
||||
|
||||
entropypool_add_word(rp, val);
|
||||
}
|
||||
|
||||
for (; len > 3 ; len -= 4) {
|
||||
val = *((isc_uint32_t *)buf);
|
||||
|
||||
entropypool_add_word(rp, val);
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
if (len != 0) {
|
||||
val = 0;
|
||||
switch (len) {
|
||||
case 3:
|
||||
val = *buf++;
|
||||
case 2:
|
||||
val = val << 8 | *buf++;
|
||||
case 1:
|
||||
val = val << 8 | *buf++;
|
||||
}
|
||||
|
||||
entropypool_add_word(rp, val);
|
||||
}
|
||||
|
||||
rp->entropy += entropy;
|
||||
|
||||
if (rp->entropy > RND_POOLBITS)
|
||||
rp->entropy = RND_POOLBITS;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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. Note that we must have at least 80 bits of entropy in the pool
|
||||
* before we return anything in the high-quality modes.
|
||||
*/
|
||||
int
|
||||
entropypool_extract(isc_entropypool_t *rp, void *p, unsigned int len,
|
||||
unsigned int mode)
|
||||
{
|
||||
unsigned int i;
|
||||
isc_sha1_t hash;
|
||||
unsigned char digest[ISC_SHA1_DIGESTLENGTH];
|
||||
isc_uint32_t remain, deltae, count;
|
||||
isc_uint8_t *buf;
|
||||
int good;
|
||||
|
||||
buf = p;
|
||||
remain = len;
|
||||
|
||||
if ((mode & ISC_ENTROPY_GOODONLY) == 0)
|
||||
good = 1;
|
||||
else
|
||||
good = (rp->entropy >= (8 * RND_ENTROPY_THRESHOLD));
|
||||
|
||||
while (good && (remain != 0)) {
|
||||
/*
|
||||
* While bytes are requested, compute the hash of the pool,
|
||||
* and then "fold" the hash in half with XOR, keeping the
|
||||
* exact hash value secret, as it will be stirred back into
|
||||
* the pool.
|
||||
*
|
||||
* XXX this approach needs examination by competant
|
||||
* cryptographers! It's rather expensive per bit but
|
||||
* also involves every bit of the pool in the
|
||||
* computation of every output bit..
|
||||
*/
|
||||
isc_sha1_init(&hash);
|
||||
isc_sha1_update(&hash, (unsigned char *)rp->pool,
|
||||
RND_POOLWORDS * 4);
|
||||
isc_sha1_final(&hash, digest);
|
||||
|
||||
/*
|
||||
* Stir the hash back into the pool. This guarantees
|
||||
* that the next hash will generate a different value
|
||||
* if no new values were added to the pool.
|
||||
*/
|
||||
for (i = 0 ; i < 5 ; i++) {
|
||||
isc_uint32_t word;
|
||||
memcpy(&word, &digest[i * 4], 4);
|
||||
entropypool_add_word(rp, word);
|
||||
}
|
||||
|
||||
count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
buf[i] = digest[i] ^ digest[ i +RND_ENTROPY_THRESHOLD];
|
||||
|
||||
buf += count;
|
||||
deltae = count * 8;
|
||||
remain -= count;
|
||||
|
||||
deltae = ISC_MIN(deltae, rp->entropy);
|
||||
|
||||
rp->entropy -= deltae;
|
||||
|
||||
if ((mode & ISC_ENTROPY_GOODONLY) == 0)
|
||||
good = (rp->entropy >= (8 * RND_ENTROPY_THRESHOLD));
|
||||
}
|
||||
|
||||
bzero(&hash, sizeof(hash));
|
||||
bzero(digest, sizeof(digest));
|
||||
|
||||
return (len - remain);
|
||||
}
|
||||
|
||||
static void
|
||||
isc_entropypool_init(isc_entropypool_t *pool) {
|
||||
pool->cursor = RND_POOLWORDS - 1;
|
||||
pool->entropy = 0;
|
||||
pool->rotate = 0;
|
||||
memset(pool->pool, 0, RND_POOLWORDS);
|
||||
}
|
||||
|
||||
static void
|
||||
isc_entropypool_invalidate(isc_entropypool_t *pool) {
|
||||
pool->cursor = 0;
|
||||
pool->entropy = 0;
|
||||
pool->rotate = 0;
|
||||
memset(pool->pool, 0, RND_POOLWORDS);
|
||||
}
|
||||
|
||||
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->mctx = mctx;
|
||||
|
||||
isc_entropypool_init(&ent->pool);
|
||||
|
||||
*entp = ent;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
errout:
|
||||
isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
isc_entropy_destroy(isc_entropy_t **entp) {
|
||||
isc_entropy_t *ent;
|
||||
|
||||
REQUIRE(entp != NULL && *entp != NULL);
|
||||
|
||||
ent = *entp;
|
||||
*entp = NULL;
|
||||
|
||||
LOCK(&ent->lock);
|
||||
REQUIRE(ISC_LIST_EMPTY(ent->sources));
|
||||
|
||||
isc_entropypool_invalidate(&ent->pool);
|
||||
|
||||
UNLOCK(&ent->lock);
|
||||
|
||||
isc_mutex_destroy(&ent->lock);
|
||||
|
||||
memset(ent, 0, sizeof(isc_entropy_t));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
|
@ -99,9 +365,11 @@ isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname,
|
|||
unsigned int flags,
|
||||
isc_entropysource_t **sourcep)
|
||||
{
|
||||
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
isc_entropy_destroysource(isc_entropysource_t **sourcep) {
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +377,8 @@ isc_result_t
|
|||
isc_entropy_createsamplesource(isc_entropy_t *ent,
|
||||
isc_entropysource_t **sourcep)
|
||||
{
|
||||
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -121,4 +391,6 @@ isc_result_t
|
|||
isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
|
||||
unsigned int *returned, unsigned int flags)
|
||||
{
|
||||
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue