entropy.c revision 499b34cea04a46823d003d4c0520c8b03e8513cb
/*
* Copyright (C) 2000, 2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: entropy.c,v 1.55 2001/01/09 21:58:13 bwelling Exp $ */
#include <config.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
/*
* written by Michael Graff <explorer@netbsd.org>.
*/
/***
*** "constants." Do not change these unless you _really_ know what
*** you are doing.
***/
/*
* size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
*/
#define RND_POOLWORDS 128
/*
* Number of bytes returned per hash. This must be true:
* threshold * 2 <= digest_size_in_bytes
*/
#define RND_ENTROPY_THRESHOLD 10
/*
* Size of the input event queue in samples.
*/
#define RND_EVENTQSIZE 32
/*
* The number of times we'll "reseed" for pseudorandom seeds. This is an
* extremely weak pseudorandom seed. If the caller is using lots of
* pseudorandom data and they cannot provide a stronger random source,
* there is little we can do other than hope they're smart enough to
* call _adddata() with something better than we can come up with.
*/
#define RND_INITIALIZE 128
typedef struct {
struct isc_entropy {
unsigned int refcnt;
unsigned int nsources;
};
typedef struct {
typedef struct {
typedef struct {
void *arg;
typedef struct {
int fd; /* fd for the file, or -1 if closed */
struct isc_entropysource {
unsigned int type;
char name[32];
union {
} sources;
};
/*
* The random pool "taps"
*/
#define TAP1 99
#define TAP2 59
#define TAP3 31
#define TAP4 9
#define TAP5 7
static inline void
static void
static int
static unsigned int
static inline void
static void
}
static isc_result_t
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
}
return (ISC_R_SUCCESS);
}
/*
* Add in entropy, even when the value we're adding in could be
* very large.
*/
static inline void
/* clamp input. Yes, this must be done. */
/* Add in the entropy we already have. */
/* Clamp. */
}
/*
* Decrement the amount of entropy the pool has.
*/
static inline void
}
/*
* Add in entropy, even when the value we're adding in could be
* very large.
*/
static inline void
/* clamp input. Yes, this must be done. */
/* Add in the pseudo we already have. */
/* Clamp. */
}
/*
* Decrement the amount of pseudo the pool has.
*/
static inline void
}
/*
* Add one word to the pool, rotating the input as needed.
*/
static inline void
/*
* 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.
*/
/*
* 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.
*/
}
}
/*
* Add a buffer's worth of data to the pool.
*
* Requires that the lock is held on the entropy pool.
*/
static void
{
unsigned long addr;
addr = (unsigned long)p;
buf = p;
if ((addr & 0x03) != 0) {
val = 0;
switch (len) {
case 3:
len--;
case 2:
len--;
case 1:
len--;
}
}
buf += 4;
}
if (len != 0) {
val = 0;
switch (len) {
case 3:
case 2:
case 1:
}
}
}
static inline void
isc_time_t t;
}
/*
* After we've reseeded 100 times, only add new timing info every
* 50 requests. This will keep us from using lots and lots of
* CPU just to return bad pseudorandom data anyway.
*/
return;
result = isc_time_now(&t);
if (result == ISC_R_SUCCESS) {
entropypool_adddata(ent, &t, sizeof t, 0);
}
}
static unsigned int
unsigned char buf[128];
unsigned int added;
return (0);
added = 0;
while (desired > 0) {
if (n < 0) {
goto out;
goto out;
}
if (n == 0) {
goto out;
}
added += n * 8;
desired -= n;
}
out:
return (added);
}
static unsigned int
{
unsigned int added;
unsigned int got;
if (desired == 0)
return (0);
return (0);
if (result != ISC_R_SUCCESS)
return (0);
}
added = 0;
if (result == ISC_R_QUEUEFULL) {
} else if (result != ISC_R_SUCCESS &&
}
return (added);
}
/*
* Poll each source, trying to get data from it to stuff into the entropy
* pool.
*/
static void
unsigned int added;
unsigned int remaining;
unsigned int needed;
unsigned int nsource;
/*
* This logic is a little strange, so an explanation is in order.
*
* If needed is 0, it means we are being asked to "fill to whatever
* we think is best." This means that if we have at least a
* partially full pool (say, > 1/4th of the pool) we probably don't
* need to add anything.
*
* Also, we will check to see if the "pseudo" count is too high.
* If it is, try to mix in better data. Too high is currently
* defined as 1/4th of the pool.
*
* Next, if we are asked to add a specific bit of entropy, make
* certain that we will do so. Clamp how much we try to add to
* (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
*
* Note that if we are in a blocking mode, we will only try to
* get as much data as we need, not as much as we might want
* to build up.
*/
if (needed == 0) {
return;
} else {
}
/*
* In any case, clamp how much we need to how much we can add.
*/
/*
* But wait! If we're not yet initialized, we need at least
* THRESHOLD_BITS
* of randomness.
*/
/*
* Poll each file source to see if we can read anything useful from
* it. XXXMLG When where are multiple sources, we should keep a
* record of which one we last used so we can start from it (or the
* next one) to avoid letting some sources build up entropy while
* others are always drained.
*/
added = 0;
return;
}
unsigned int got;
if (remaining == 0)
break;
got = 0;
#if 0
break;
#endif
}
int fds;
if (fds > 0)
goto again_file;
}
/*
* Here, if there are bits remaining to be had and we can block,
* check to see if we have a callback source. If so, call them.
*/
unsigned int got;
got = 0;
break;
}
/*
* Mark as initialized if we've added enough data.
*/
}
static int
int cc;
maxfd = -1;
if (fd >= 0) {
}
}
}
if (maxfd < 0)
return (-1);
if (cc < 0)
return (-1);
return (cc);
}
/*
* 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.
*/
{
unsigned int i;
unsigned char digest[ISC_SHA1_DIGESTLENGTH];
total = 0;
while (remain != 0) {
/*
* 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;
/*
* 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.
*/
else
/*
* Verify that we got enough entropy to do one
* extraction. If we didn't, bail.
*/
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.
*/
else
/*
* If we've not initialized with enough good random
* data, seed with our crappy code.
*/
}
RND_POOLWORDS * 4);
/*
* Stir the extracted data (all of it) back into the pool.
*/
for (i = 0; i < count; i++)
}
return (ISC_R_SUCCESS);
/* put the entropy we almost extracted back */
*returned = 0;
return (ISC_R_NOENTROPY);
}
static void
}
static void
}
return (ISC_R_NOMEMORY);
/*
* We need a lock.
*/
goto errout;
}
/*
*/
ent->initialized = 0;
return (ISC_R_SUCCESS);
return (ret);
}
/*
* Requires "ent" be locked.
*/
static void
int fd;
case ENTROPY_SOURCETYPE_FILE:
break;
break;
}
break;
}
}
static inline isc_boolean_t
return (ISC_FALSE);
case ENTROPY_SOURCETYPE_FILE:
break;
default:
return (ISC_FALSE);
}
}
return (ISC_TRUE);
}
static void
/*
* Here, detach non-sample sources.
*/
case ENTROPY_SOURCETYPE_FILE:
break;
}
}
/*
* If there are other types of sources, we've found a bug.
*/
}
/*
* Make a fd non-blocking
*/
static isc_result_t
make_nonblock(int fd) {
int ret;
int flags;
flags |= O_NONBLOCK;
if (ret == -1) {
"fcntl(%d, F_SETFL, %d): %s",
return (ISC_R_UNEXPECTED);
}
return (ISC_R_SUCCESS);
}
int fd;
if (fd < 0) {
ret = ISC_R_IOERROR;
goto errout;
}
if (ret != ISC_R_SUCCESS)
goto closefd;
goto closefd;
}
/*
* From here down, no failures can occur.
*/
/*
* Hook it into the entropy system.
*/
return (ISC_R_SUCCESS);
return (ret);
}
void
if (killit)
}
void *arg,
{
goto errout;
}
if (ret != ISC_R_SUCCESS)
goto errout;
/*
* From here down, no failures can occur.
*/
/*
* Hook it into the entropy system.
*/
return (ISC_R_SUCCESS);
return (ret);
}
void
}
}
}
}
{
goto errout;
}
if (ret != ISC_R_SUCCESS)
goto errout;
/*
* From here down, no failures can occur.
*/
/*
* Hook it into the entropy system.
*/
return (ISC_R_SUCCESS);
return (ret);
}
static inline unsigned int
{
/*
* If the time counter has overflowed, calculate the real difference.
* If it has not, it is simplier.
*/
else
if (delta < 0)
/*
* Calculate the second and third order differentials
*/
if (delta2 < 0)
if (delta3 < 0)
/*
* If any delta is 0, we got no entropy. If all are non-zero, we
* might have something.
*/
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
unsigned int ns;
unsigned int added;
return (0);
added = 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.
*/
/*
* Move the last 4 samples into the first 4 positions, and start
* adding new samples from that point.
*/
}
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
return (ISC_R_NOMORE);
return (ISC_R_QUEUEFULL);
return (ISC_R_SUCCESS);
}
{
unsigned int entropy;
if (result == ISC_R_QUEUEFULL) {
}
return (result);
}
{
return (result);
}
void
{
}
static void
"Entropy pool %p: refcnt %u cursor %u,"
" rotate %u entropy %u pseudo %u nsources %u"
" nextsource %p initialized %u initcount %u\n"),
}
/*
* This function ignores locking. Use at your own risk.
*/
void
}
void
}
void
if (killit)
}