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

📄 pgprandompool.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	unsigned		n;
	RandomPool	*	pool	= GetPool();

	if (delta < 1 << DERATING)
		return 0;
	
	n = 31-DERATING;
	if (!(delta & 0xffff0000))
		delta <<= 16, n -= 16;
	if (!(delta & 0xff000000))
		delta <<= 8, n -= 8;
	if (!(delta & 0xf0000000))
		delta <<= 4, n -= 4;
	if (!(delta & 0xc0000000))
		delta <<= 2, n -= 2;
	if (!(delta & 0x80000000))
		delta <<= 1, n -= 1;
	pgpAssert(n < 32);

	/* Lose high-order bit of delta */
	pgpAssert(delta & 0x80000000);
	delta <<= 1;

	frac = pool->randKeyFrac;
	UMULH_32(t,delta,frac);
	if ((frac += t) < t) {
		if ((frac += delta) < delta)
			frac = (frac >> 1) + 0x80000000ul;
		else
			frac >>= 1;
		n++;
	} else if ((frac += delta) < delta) {
		frac >>= 1;
		n++;
	}

	/* The timers used are very high-resolution. Be
	** conservative with our estimates. No more than
	** 10 bits per sample.
	*/

	if( n > 10 )
		n = 10;

	/* Store back updated fractional bits */
	pool->randKeyFrac = frac;

	/* n is now the count of whole bits */
	if ((pool->randKeyBits += n) >= RANDKEYBITS) {
		/* Overflow - saturate at RANDKEYBITS */
		pool->randKeyBits = RANDKEYBITS;
		pool->randKeyFrac = 0;
	}
	
	return n;
}

	PGPUInt32
PGPGlobalRandomPoolGetEntropy()
{
	PGPUInt32	randBits;
	RandomPool	*pool = GetPool();

	PGPRMWOLockStartReading( &pool->criticalLock );
	randBits = pool->randBits;
	PGPRMWOLockStopReading( &pool->criticalLock );
	
	return( randBits );
}

	PGPUInt32
PGPGlobalRandomPoolGetSize()
{
	return RANDPOOLBITS;
}



	PGPUInt32
pgpGlobalRandomPoolGetInflow()
{
	PGPUInt32	randInBits;
	RandomPool	*pool = GetPool();

	PGPRMWOLockStartReading( &pool->criticalLock );
		randInBits = pool->randInBits;
	PGPRMWOLockStopReading( &pool->criticalLock );
	
	return( randInBits );
}


/*
 * Returns true if we have enough entropy to proceed with signature or
 * encryption functions.  We go ahead if we have either seeded the RNG
 * successfully from the disk, or if we have acquired a certain
 * minimum of bits from the environment during our run.
 */
	PGPBoolean
PGPGlobalRandomPoolHasMinimumEntropy( void )
{
	return  pgpGlobalRandomPoolIsSeeded() ||
		    pgpGlobalRandomPoolGetInflow() >= kMinimumSeedBits ;
}

/*
 * Returns the minimum amount of entropy we would like to see in the random
 * pool before signing or encryption.  Before doing one of those functions,
 * we first use PGPGlobalRandomPoolHasMinimumEntropy to determine whether
 * to proceed.  If that returns FALSE, we should acquire entropy until the
 * amount in the random pool is at least equal to what this function returns.
 * Note that PGPGlobalRandomPoolHasMinimumEntropy uses the inflow value,
 * while if that returns false we will use the actual amount of randomness
 * in the pool, which is always <= the inflow value.  Using the inflow value
 * is safe enough as it indicates that we are seeded, but once we decide we
 * need to go to the effort of acquiring more entropy from the environment,
 * we might as well use the GetEntropy() value, which is more conservative.
 */
	PGPUInt32
PGPGlobalRandomPoolGetMinimumEntropy( void )
{
	return kMinimumSeedBits;
}


/* Number of elements in the given array */
#define elemsof(x) ( (PGPUInt32)( sizeof(x) / sizeof(*x) ) )

/*
 * Estimate the amount of entropy in an input value x by seeing how
 * different it is from what has come before.
 *
 * This is based on computing the delta from the previous value, and the
 * second-order delta from the previous delta, and so on, for h orders.
 * The minimum of any of those deltas is returned as the entropy estimate.
 * (Which must, of course, have a logarithm taken to produce a "number
 * of bits" output.)
 *
 * This requires a pointer to a h-word history table of previous deltas.
 * A value of h = 3 is generally good, but some things (like keystroke
 * timings) feed deltas and not input values into this, so that removes
 * the first level.
 */
static PGPUInt32
randEstimate(PGPUInt32 x, PGPUInt32 *history, unsigned h)
{
	PGPUInt32		t,
					min = x;

	while (h--) {
		t = history[h];			/* Last delta */
		t = (x > t) ? x - t : t - x;	/* |x - history[h]| */
		history[h] = x;
		x = t;
		if (min > x)
			min = x;
	}
	return min;
}


	static PGPUInt32
sCollectEntropy()
{
	PGPUInt32			delta;
	PGPRandomContext	rc;
	
	/* call machine specific routine to get some entropy */
	pgpInitGlobalRandomPoolContext( &rc );
	delta	= pgpRandomCollectEntropy( &rc );
	
	return( delta );
}


/*
 * Gather and estimate entropy from keyboard timings.  Double letters
 * are allowed, but triples and more are considered suspiscious and
 * entropy is not counted.  (The actual criterion is that the current
 * letter has appeared more than once in the previous four letters,
 * which rejects aaaa... and ababa...)
 *
 * The "letter" can be generalized to mouse-clicks, button-pushes, menu
 * selections, or anything else that can be categorized into a finite
 * number of events.
 *
 * Question: is there a way to achieve this effect without remembering
 * the recent keystrokes so explicitly?  It seems like a possible
 * security hole.
 *
 * We incorporate entropy from the first 3 samples, but don't count them
 * since only after that many do we get reliable per-sample entropy estimates.
 * (This is time for the two entries in teh hist array to get initialized,
 * plus the one level of delta history implicitly included in the
 * ranGetEntropy timing.  It has to be there unless we want to export
 * knowledge about the modulus at which the timer it uses wraps.)
 */
	PGPUInt32
PGPGlobalRandomPoolAddKeystroke( PGPInt32 event)
{
	static PGPInt32		pastevent[4];	/* Last 4 events */
	static PGPUInt32	hist[2];
	static unsigned		histcount=elemsof(hist)+1;
						/* # invalid entries in hist array */
	PGPUInt32			delta;
	unsigned			n = 0;
	int					i;
	RandomPool			*pool = GetPool();
	PGPUInt32			result;
	

	delta = sCollectEntropy();
	delta = randEstimate(delta, hist, elemsof(hist));
    
	PGPRMWOLockStartWriting( &pool->criticalLock );

	sRandPoolAddBytes(NULL, (PGPByte *)&event, sizeof(event));

	/* Check for repetitive keystroke patterns */
	i = elemsof(pastevent) - 1;
	n = (event == pastevent[i]);
	do {
		n += (event == (pastevent[i] = pastevent[i-1]));
	} while (--i);
	pastevent[0] = event;

	if (histcount > 0) {
		/* Not yet filled hist array */
		--histcount;
		result = 0;
	}
	else if( n > 1 )
	{
		result = 0;
	}
	else
	{
		result = pgpGlobalRandomPoolEntropyWasAdded(delta);
	}
	
	PGPRMWOLockStopWriting( &pool->criticalLock );

	return( result );
}

/*
 * Generate entropy from mouse motion.  This simply measures entropy
 * of timing, although that may be pretty low due to OS synchrony.
 *
 * We incorporate entropy from the first 2 samples, but don't count them
 * since only after that many do the predictors start working.
 */
 
	PGPUInt32
PGPGlobalRandomPoolMouseMoved(void)
{
	static PGPUInt32	hist[2];			/* Timing history */
	static unsigned		histcount=elemsof(hist);
						/* # invalid entries in histx array */
	PGPUInt32			delta;				/* Timing delta */
	RandomPool			*pool = GetPool();
	PGPUInt32			result;
	
	delta = sCollectEntropy();
	delta = randEstimate(delta, hist, elemsof(hist));

	PGPRMWOLockStartWriting( &pool->criticalLock );

	/* Wait until we have filled our arrays to start counting entropy */
	if (histcount > 0)
	{
		--histcount;
		result = 0;
	}
	else
	{
		result = pgpGlobalRandomPoolEntropyWasAdded(delta);
	}
	
	PGPRMWOLockStopWriting( &pool->criticalLock );
	
	return( result );
}

/*
 * Generate entropy from mouse motion. This all is provided for backwards
 * compatability. Mouse coordinates are no longer used.
 */
 
	PGPUInt32
PGPGlobalRandomPoolAddMouse(
	PGPUInt32		x,
	PGPUInt32		y)
{
	(void) x;
	(void) y;
	
	return( PGPGlobalRandomPoolMouseMoved() );
}


/*
 *	DUMMY POOL
 *
 *	The dummy pool is a pluggable replacement for the RandPool to be used
 *	for generating values which we want to be unique but don't have to be
 *	cryptographically strong: such as the p and q values used in discrete
 *	log keys.  We prefer not to use the regular RandPool for such values
 *	so that we don't leak information about the secret values which are
 *	calculated in close proximity.
 *
 *	The dummy pool should be used as the "base" paramater for
 *	pgpRandomCreateX9_17.  It always returns 0 values, and the X9.17 RNG
 *	will then produce non-cryptographically-strong pseudo-random numbers.
 *
 *	Use pgpRandomAddBytes on the X9.17 RandomContext to seed it.
 */

/* Dummy pool always returns zeros */
	static void
sDummyPoolGetBytesEntropy(
	void *			priv,
	PGPByte *		buf,
	unsigned		len,
	unsigned		bits)
{
	(void)priv;
	(void)bits;
	
	pgpClearMemory( buf, len );
}

	static void
sDummyPoolAddBytes(
	void *			priv,
	PGPByte const *	p,
	unsigned		len)
{
	(void)priv;
	(void)p;
	(void)len;
}
	static void
sDummyPoolStir(void *priv)
{
	(void)priv;
}

static const PGPRandomVTBL sDummyRandomPoolVTBL =
{
	"Dummy random-number pool",
	sDummyPoolAddBytes,
	sDummyPoolGetBytesEntropy,
	sDummyPoolStir
};


	PGPRandomVTBL const *
pgpGetGlobalDummyRandomPoolVTBL( void )
{
	return( &sDummyRandomPoolVTBL );
}

PGPError
PGPGlobalRandomPoolAddSystemState()
{
	PGPRandomContext rc;
	
	pgpInitGlobalRandomPoolContext( &rc );
	if (pgpRandomCollectOsData( &rc )) {
		pgpSetIsSeeded();
		return kPGPError_NoErr;
	}
	else {
		return kPGPError_UnknownError;
	}
}


/*
 * Accumulate entropy from key into pool.
 * See comments with pgpGlobalRandomPoolEntropyWasAdded for how
 * the arithmetic works.
 */
static void
sRandAddKeyEntropy( RandomPool *pool )
{
	PGPUInt32		frac,		/* Fractional bits to add */
					keyfrac,
					t;
	PGPUInt32		n;			/* Number of whole bits to add */

	/* Add entropy from randKey into randPool */
	keyfrac = pool->randKeyFrac;
	frac = pool->randFrac;
	n = pool->randKeyBits;
	UMULH_32(t,keyfrac,frac);

	/* The comparison idiom used here detects overflow on addition */
	if ((frac += t) < t) {
		if ((frac += keyfrac) < keyfrac)
			frac = (frac >> 1) + 0x80000000ul;
		else
			frac >>= 1;
		n++;
	} else if ((frac += keyfrac) < keyfrac) {
		frac >>= 1;
		n++;
	}

	pool->randFrac = frac;
	if ((pool->randBits += n) >= RANDPOOLBITS) {
		/* Overflow - saturate at RANDPOOLBITS */
		pool->randBits = RANDPOOLBITS;
		pool->randFrac = 0;
	}
	/* Also count the inflow without regard to outflow */
	if ((pool->randInBits += n) >= RANDPOOLBITS) {
		pool->randInBits = RANDPOOLBITS;
	}
	pool->randKeyBits = pool->randKeyFrac = 0;
}


/*__Editor_settings____

	Local Variables:
	tab-width: 4
	End:
	vi: ts=4 sw=4
	vim: si
_____________________*/

⌨️ 快捷键说明

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