⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 entropy.c

📁 bind 9.3结合mysql数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003  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 ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS.  IN NO EVENT SHALL ISC 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.3.2.2.2.7 2004/03/08 09:04:48 marka Exp $ *//* * This is the system independent part of the entropy module.  It is * compiled via inclusion from the relevant OS source file, ie, * unix/entropy.c or win32/entropy.c. */#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <isc/buffer.h>#include <isc/entropy.h>#include <isc/keyboard.h>#include <isc/list.h>#include <isc/magic.h>#include <isc/mem.h>#include <isc/msgs.h>#include <isc/mutex.h>#include <isc/platform.h>#include <isc/region.h>#include <isc/sha1.h>#include <isc/string.h>#include <isc/time.h>#include <isc/util.h>/* * Much of this code is modeled after the NetBSD /dev/random implementation, * written by Michael Graff <explorer@netbsd.org>. */#define ENTROPY_MAGIC		ISC_MAGIC('E', 'n', 't', 'e')#define SOURCE_MAGIC		ISC_MAGIC('E', 'n', 't', 's')#define VALID_ENTROPY(e)	ISC_MAGIC_VALID(e, ENTROPY_MAGIC)#define VALID_SOURCE(s)		ISC_MAGIC_VALID(s, SOURCE_MAGIC)/*** *** "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#define RND_POOLBYTES	(RND_POOLWORDS * 4)#define RND_POOLBITS	(RND_POOLWORDS * 32)/* * Number of bytes returned per hash.  This must be true: *	threshold * 2 <= digest_size_in_bytes */#define RND_ENTROPY_THRESHOLD	10#define THRESHOLD_BITS		(RND_ENTROPY_THRESHOLD * 8)/* * 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	128typedef struct {	isc_uint32_t	cursor;		/* current add point in the pool */	isc_uint32_t	entropy;	/* current entropy estimate in bits */	isc_uint32_t	pseudo;		/* bits extracted in pseudorandom */	isc_uint32_t	rotate;		/* how many bits to rotate by */	isc_uint32_t	pool[RND_POOLWORDS];	/* random pool data */} isc_entropypool_t;struct isc_entropy {	unsigned int			magic;	isc_mem_t		       *mctx;	isc_mutex_t			lock;	unsigned int			refcnt;	isc_uint32_t			initialized;	isc_uint32_t			initcount;	isc_entropypool_t		pool;	unsigned int			nsources;	isc_entropysource_t	       *nextsource;	ISC_LIST(isc_entropysource_t)	sources;};typedef struct {	isc_uint32_t	last_time;	/* last time recorded */	isc_uint32_t	last_delta;	/* last delta value */	isc_uint32_t	last_delta2;	/* last delta2 value */	isc_uint32_t	nsamples;	/* number of samples filled in */	isc_uint32_t   *samples;	/* the samples */	isc_uint32_t   *extra;		/* extra samples added in */} sample_queue_t;typedef struct {	sample_queue_t	samplequeue;} isc_entropysamplesource_t;typedef struct {	isc_boolean_t		start_called;	isc_entropystart_t	startfunc;	isc_entropyget_t	getfunc;	isc_entropystop_t	stopfunc;	void		       *arg;	sample_queue_t		samplequeue;} isc_cbsource_t;typedef struct {	FILESOURCE_HANDLE_TYPE handle;} isc_entropyfilesource_t;struct isc_entropysource {	unsigned int	magic;	unsigned int	type;	isc_entropy_t  *ent;	isc_uint32_t	total;		/* entropy from this source */	ISC_LINK(isc_entropysource_t)	link;	char		name[32];	isc_boolean_t	bad;	isc_boolean_t	warn_keyboard;	isc_keyboard_t	kbd;	union {		isc_entropysamplesource_t	sample;		isc_entropyfilesource_t		file;		isc_cbsource_t			callback;		isc_entropyusocketsource_t	usocket;	} sources;};#define ENTROPY_SOURCETYPE_SAMPLE	1	/* Type is a sample source */#define ENTROPY_SOURCETYPE_FILE		2	/* Type is a file source */#define ENTROPY_SOURCETYPE_CALLBACK	3	/* Type is a callback source */#define ENTROPY_SOURCETYPE_USOCKET	4	/* Type is a Unix socket source *//* * The random pool "taps" */#define TAP1	99#define TAP2	59#define TAP3	31#define TAP4	 9#define TAP5	 7/* * Declarations for function provided by the system dependent sources that * include this file. */static voidfillpool(isc_entropy_t *, unsigned int, isc_boolean_t);static intwait_for_sources(isc_entropy_t *);static voiddestroyfilesource(isc_entropyfilesource_t *source);static voiddestroyusocketsource(isc_entropyusocketsource_t *source);static voidsamplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {	REQUIRE(sq->samples != NULL);	REQUIRE(sq->extra != NULL);	isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);	isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);	sq->samples = NULL;	sq->extra = NULL;}static isc_result_tsamplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {	sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);	if (sq->samples == NULL)		return (ISC_R_NOMEMORY);	sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);	if (sq->extra == NULL) {		isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);		sq->samples = NULL;		return (ISC_R_NOMEMORY);	}	sq->nsamples = 0;	return (ISC_R_SUCCESS);}/* * Add in entropy, even when the value we're adding in could be * very large. */static inline voidadd_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {	/* clamp input.  Yes, this must be done. */	entropy = ISC_MIN(entropy, RND_POOLBITS);	/* Add in the entropy we already have. */	entropy += ent->pool.entropy;	/* Clamp. */	ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);}/* * Decrement the amount of entropy the pool has. */static inline voidsubtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {	entropy = ISC_MIN(entropy, ent->pool.entropy);	ent->pool.entropy -= entropy;}/* * Add in entropy, even when the value we're adding in could be * very large. */static inline voidadd_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {	/* clamp input.  Yes, this must be done. */	pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);	/* Add in the pseudo we already have. */	pseudo += ent->pool.pseudo;	/* Clamp. */	ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);}/* * Decrement the amount of pseudo the pool has. */static inline voidsubtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {	pseudo = ISC_MIN(pseudo, ent->pool.pseudo);	ent->pool.pseudo -= pseudo;}/* * Add one word to the pool, rotating the input as needed. */static inline voidentropypool_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. * * Requires that the lock is held on the entropy pool. */static voidentropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,		    isc_uint32_t entropy){	isc_uint32_t val;	unsigned long addr;	isc_uint8_t *buf;	addr = (unsigned long)p;	buf = p;	if ((addr & 0x03U) != 0U) {		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(&ent->pool, val);	}	for (; len > 3; len -= 4) {		val = *((isc_uint32_t *)buf);		entropypool_add_word(&ent->pool, 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(&ent->pool, val);	}	add_entropy(ent, entropy);	subtract_pseudo(ent, entropy);}static inline voidreseed(isc_entropy_t *ent) {	isc_time_t t;	pid_t pid;	if (ent->initcount == 0) {		pid = getpid();		entropypool_adddata(ent, &pid, sizeof(pid), 0);		pid = getppid();		entropypool_adddata(ent, &pid, sizeof(pid), 0);	}	/*	 * 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.	 */	if (ent->initcount > 100)		if ((ent->initcount % 50) != 0)			return;	TIME_NOW(&t);	entropypool_adddata(ent, &t, sizeof(t), 0);	ent->initcount++;}static inline unsigned intestimate_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 simpler.	 */	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 intcrunchsamples(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);}static unsigned intget_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);}/* * 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_tisc_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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -