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

📄 pgprandompool.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
📖 第 1 页 / 共 3 页
字号:
 * expressed in bits.)
 *
 * The internal amount-of-entropy accumulator is maintained in two
 * halves: a counter of bits, and a fraction of a bit, expressed
 * in the form of a normalized delta.  If 0 <= f < 1 is a fraction
 * of a bit, then 1 <= 2^f < 2, so it's remembered as
 * 0 <= x = 2^f - 1 < 1, a fixed-point number.
 *
 * Given a new fractional-bit delta, 1+y in similar form (obtained
 * by normalizing the delta into the desired form), the output
 * fractional bit delta 1+z = (1+x) * (1+y).  If this exceeds 2,
 * divide it by 2 and add a full bit to the bit counter.
 *
 * The implementation, of course, actually computes z = x + y + x*y,
 * where 0 <= z < 3.  This can be done by adding each of the three terms
 * (each of which is less than 1) and noticing the overflow.  If the
 * addition does not overflow, z < 1 and nothing needs to be done.
 *
 * If one addition overflows, 1 <= z < 2, but after overflow we get
 * z-1.  We want (1+z)/2-1 = (z-1)/2, so just divide the result of
 * the wrapped addition by 2.
 *
 * If both additions overflow, the addition wraps to z-2, but we
 * still want (z-1)/2 = (z-2)/2 + 1/2, so divide the wrapped result
 * by 2 and add 1/2.
 *
 * Due to the way that the fixed-point numbers are stored, the x*y part is
 * the high half of the 32-bit unsigned product of x and y.  This can be
 * safely underestimated if desired, if a 64-bit product is difficult to
 * compute.
 *
 * The simplest snd safest definition is
 * #define UMULH_32(r,a,b) (r) = 0
 */
#ifndef UMULH_32

/* It appears that gcc 2.95+ doesn't like this */
#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ <= 2) && (__GNUC_MINOR__ < 95)
/* Inline asm goodies */
#define UMULH_32(r,a,b) __asm__("mull %2" : "=d"(r) : "%a"(a), "mr"(b) : "ax")
#elif HAVE64
#define UMULH_32(r,a,b) ((r) = (PGPUInt32)((word64)(a) * (b) >> 32))
#else
/* Underestimate the product */
#define UMULH_32(r,a,b) ((r) = ((a) >> 16) * ((b) >> 16))
#endif
#endif /* !UMULH_32 */

#define DERATING 2	/* # of bits to underestimate */

	static PGPUInt32
pgpGlobalRandomPoolEntropyWasAdded(
	PGPUInt32		delta )
{
	PGPUInt32		frac,
					t;
	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;
}

/*
 * PGPGlobalRandomPoolGetEntropy
 *	- Returns the amount of entropy currently in the random pool.
 *	- Modified to fill the pool with SDK driver random pool entropy when we can.
 *	- Modified to fill the pool with Intel-RNG randomness when we can.
 */
#if ! PGPSDK_DRIVER
	static PGPUInt32
pgpGlobalRandomPoolGetEntropy_internal()
#else /* PGPSDK_DRIVER */
	PGPUInt32
PGPGlobalRandomPoolGetEntropy()
#endif /* PGPSDK_DRIVER */
{
	PGPUInt32	randBits;
	RandomPool	*pool = GetPool();

	PGPRMWOLockStartWriting( &pool->criticalLock );
	randBits = pool->randBits;

#if (PGP_WIN32 || PGP_MACINTOSH) && ! PGPSDK_DRIVER
	if( randBits < RANDPOOLBITS && pgpSDKEntropyDriverIsRunning() )
	{
		PGPUInt32	getBits;
		PGPUInt32	getBytes;
		PGPError	err;
		
		/* Add bits from entropy driver, if present */
		
		getBits = pgpDriverRandomPoolGetEntropy();
		if( randBits + getBits > RANDPOOLBITS )
		{
			getBits = RANDPOOLBITS - randBits;
		}
		
		getBytes = getBits / 8;
		while( getBytes != 0 )
		{
			PGPByte	buffer[32];
			PGPSize	readCount;
			
			readCount = getBytes;
			if( readCount > sizeof( buffer ) )
				readCount = sizeof( buffer );
				
			err = pgpDriverRandomPoolGetBytesEntropy(buffer, readCount);
			pgpAssert( err == kPGPError_NoErr );
			if (err != kPGPError_NoErr) break;

			pgpGlobalRandomPoolAddEntropyBits( readCount * 8 );
			sRandPoolAddBytes( NULL, &buffer[0], readCount );
			
			getBytes -= readCount;
		}

		randBits = pool->randBits;
	}
#endif

#if PGP_INTEL_RNG_SUPPORT
	/*
	 * If the pool isn't full and we have Intel RNG,
	 * add RNG bits into the pool.
	 */
	if (randBits < RANDPOOLBITS && pgpIntelRngEnabled()) {
		while (randBits < RANDPOOLBITS) {
			uint32 uiRandom;
			if (IsdGetRandomNumber(&uiRandom) != ISD_EOK)
				break;
			pgpGlobalRandomPoolAddEntropyBits(INTEL_RNG_ENTROPY_BITS);
			sRandPoolAddBytes(NULL, (PGPByte *)&uiRandom, sizeof(uiRandom));
			randBits = pool->randBits;
		}
	}
#endif

	PGPRMWOLockStopWriting( &pool->criticalLock );

	return( randBits );
}


/*
 * This is used for the case where we do a calculation that uses up some
 * entropy, then we abort it and discard the result.  Before doing the calc,
 * call PGPGlobalRandomPoolGetEntropy.  Then, after the abort, call
 * pgpGlobalRandomPoolSetEntropy to set randBits back to what it was.
 * This should only be done within a single thread so that we don't miscount
 * by having another thread drain entropy in between the calls.
 */
	void
pgpGlobalRandomPoolSetEntropy( PGPUInt32 randBits )
{
	RandomPool	*pool = GetPool();

	PGPRMWOLockStartWriting( &pool->criticalLock );
	pool->randBits = pgpMax( randBits, pool->randBits );

	PGPRMWOLockStopWriting( &pool->criticalLock );
}


#if ! PGPSDK_DRIVER
	PGPUInt32
PGPGlobalRandomPoolGetEntropy()
{
	PGPUInt32 entropy;

	pgpEnterZeroFunction();
	pgpGlobalRandomPoolGetInfo_back( &entropy, NULL, NULL, NULL, NULL );
	return entropy;
}
#endif /* not PGPSDK_DRIVER */

void
pgpGlobalRandomPoolAddEntropyBits(PGPInt32 num)
{
	RandomPool *pool = GetPool();
	if ((pool->randKeyBits += num) >= RANDKEYBITS) {
		pool->randKeyBits = RANDKEYBITS;
		pool->randKeyFrac = 0;
	}
}

void
pgpGlobalRandomPoolAddEntropy(
	void *			priv,
	PGPByte const *	p,
	unsigned		len)	/* in bytes */
{
	RandomPool *pool	= GetPool();

	PGPRMWOLockStartWriting( &pool->criticalLock );

	pgpGlobalRandomPoolAddEntropyBits( len * 8 );
	sRandPoolAddBytes( priv, p, len );

	PGPRMWOLockStopWriting( &pool->criticalLock );
}

#if ! PGPSDK_DRIVER
	static PGPUInt32
pgpGlobalRandomPoolGetSize_internal()
{
	return RANDPOOLBITS;
}
#endif /* not PGPSDK_DRIVER */

	PGPUInt32
PGPGlobalRandomPoolGetSize()
{
#if ! PGPSDK_DRIVER
	PGPUInt32 size;
	pgpGlobalRandomPoolGetInfo_back( NULL, &size, NULL, NULL, NULL );
	return size;
#else /* PGPSDK_DRIVER */
	return RANDPOOLBITS;
#endif /* PGPSDK_DRIVER */
}



	static 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.
 */
#if ! PGPSDK_DRIVER
	static PGPBoolean
pgpGlobalRandomPoolHasMinimumEntropy_internal( void )
{
	PGPUInt32 poolbits;

	pgpEnterBooleanFunction( FALSE );

	if( pgpGlobalRandomPoolIsSeeded( ) )
		return TRUE;
	poolbits = pgpGlobalRandomPoolGetInflow( );
	if( poolbits >= kMinimumSeedBits )
		return TRUE;
#if (PGP_WIN32 || PGP_MACINTOSH) && ! PGPSDK_DRIVER
	if( pgpSDKEntropyDriverIsRunning( ) )
		poolbits += pgpDriverRandomPoolGetEntropy( );
	if( poolbits >= kMinimumSeedBits )
		return TRUE;
#endif
	return FALSE;
}
#endif /* not PGPSDK_DRIVER */


	PGPBoolean
PGPGlobalRandomPoolHasMinimumEntropy( void )
{
#if ! PGPSDK_DRIVER
	PGPBoolean hasMinEntropy;
#endif /* not PGPSDK_DRIVER */

	pgpEnterBooleanFunction( FALSE );

#if ! PGPSDK_DRIVER
	pgpGlobalRandomPoolGetInfo_back( NULL, NULL, NULL, &hasMinEntropy, NULL );
	return hasMinEntropy;
#else /* PGPSDK_DRIVER */
	return  pgpGlobalRandomPoolIsSeeded() ||
		    pgpGlobalRandomPoolGetInflow() >= kMinimumSeedBits ;
#endif /* PGPSDK_DRIVER */
}

/*
 * 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.
 */
#if ! PGPSDK_DRIVER
	static PGPUInt32
pgpGlobalRandomPoolGetMinimumEntropy_internal( void )
{
	return kMinimumSeedBits;
}
#endif /* not PGPSDK_DRIVER */

	PGPUInt32
PGPGlobalRandomPoolGetMinimumEntropy( void )
{
#if ! PGPSDK_DRIVER
	PGPUInt32 minEntropy;
	pgpGlobalRandomPoolGetInfo_back( NULL, NULL, &minEntropy, NULL, NULL );
	return minEntropy;
#else /* PGPSDK_DRIVER */
	return kMinimumSeedBits;
#endif /* PGPSDK_DRIVER */
}

#if ! PGPSDK_DRIVER
	PGPError
pgpGlobalRandomPoolGetInfo_internal( PGPUInt32 *entropy, PGPUInt32 *size,
	PGPUInt32 *minEntropy, PGPBoolean *hasMinEntropy,
	PGPBoolean *hasIntelRNG )
{
	if( IsntNull( entropy ) )
		*entropy = pgpGlobalRandomPoolGetEntropy_internal( );
	if( IsntNull( size ) )
		*size = pgpGlobalRandomPoolGetSize_internal( );
	if( IsntNull( minEntropy ) )
		*minEntropy = pgpGlobalRandomPoolGetMinimumEntropy_internal( );
	if( IsntNull( hasMinEntropy ) )
		*hasMinEntropy = pgpGlobalRandomPoolHasMinimumEntropy_internal( );
	if( IsntNull( hasIntelRNG ) )
	{
		*hasIntelRNG = FALSE;
#if PGP_INTEL_RNG_SUPPORT
		*hasIntelRNG = pgpIntelRngEnabled();
#endif
	}
	return kPGPError_NoErr;
}
#endif /* PGPSDK_DRIVER */


/* 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;

⌨️ 快捷键说明

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