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

📄 pgputilrandompool.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 ;
}
#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.
 */
	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;
}


#if !PGPSDK_DRIVER

	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;
	}
}

#endif //!PGPSDK_DRIVER


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



#if PGPSDK_DRIVER


/*
 * 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.)
 *
 * If bAddToPool is TRUE, the entropy is always added to the pool.  
 * Otherwise, it is added only if the pool is not full.
 */
	PGPUInt32
PGPWin32DriverRandomPoolAddKeystroke(
	PGPUInt32	bAddToPool,
	PGPUInt32 	timerval_lo,
	PGPUInt32 	keyscan )
{
	static PGPUInt32	oldtimerval;
	static PGPUInt32	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;
	PGPUInt32			result = 0;

	delta = timerval_lo - oldtimerval;
	oldtimerval = timerval_lo;
	delta = randEstimate(delta, hist, elemsof(hist));

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

	if (histcount > 0) {
		/* Not yet filled hist array */
		--histcount;
		bAddToPool = TRUE;
	}
	else if( n == 0 )
	{
		RandomPool	*pool = GetPool();

		if (pool->randBits < RANDPOOLBITS)
		{
			bAddToPool = TRUE;
			result =  pgpGlobalRandomPoolEntropyWasAdded(delta);
		}
	}

	if (bAddToPool)
	{
		sRandPoolAddBytes(NULL, (PGPByte *)&timerval_lo, sizeof(timerval_lo));
		sRandPoolAddBytes(NULL, (PGPByte *)&keyscan, sizeof(keyscan));
	}

	return( result );
}

/*
 * Generate entropy from mouse motion.  This simply measures entropy
 * in both directions independently.  Also includes entropy of timing,
 * although that may be pretty low due to OS synchrony.
 *
 * In essence, we try to predict the mouse position from past positions,
 * using three predictors: constant position, constant velocity, and
 * constant acceleration.  The minimum misprediction distance is used
 * to extimate entropy from.
 *
 * We incorporate entropy from the first 3 samples, but don't count them
 * since only after that many do the predictors start working.
 * (Note that the timing history array is one shorter, because one extra
 * level of delta computation is buried in ranGetEntropy().)
 *
 * If bAddToPool is TRUE, the entropy is always added to the pool.  
 * Otherwise, it is added only if the pool is not full.
 */
	PGPUInt32
PGPWin32DriverRandomPoolMouseMoved(
	PGPUInt32		bAddToPool,
	PGPUInt32 		timerval_lo)
{
	static PGPUInt32	oldtimerval;
	static PGPUInt32	hist[2];			/* Timing history */
	static unsigned		histcount=elemsof(hist);
						/* # invalid entries in hist array */
	PGPUInt32			delta;				/* Timing delta */
	PGPUInt32			result = 0;

	delta = timerval_lo - oldtimerval;
	oldtimerval = timerval_lo;
	delta = randEstimate(delta, hist, elemsof(hist));

	/* Wait until we have filled our arrays to start counting entropy */
	if (histcount > 0)
	{
		--histcount;
		bAddToPool = TRUE;
	}
	else
	{
		RandomPool	*pool = GetPool();

		if (pool->randBits < RANDPOOLBITS)
		{
			bAddToPool = TRUE;
			result =  pgpGlobalRandomPoolEntropyWasAdded(delta);
		}
	}

	if (bAddToPool)
	{
		sRandPoolAddBytes(NULL, (PGPByte *)&timerval_lo, sizeof(timerval_lo));
	}

	return( result );
}


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

	randBits = pool->randBits;

	return( randBits );
}


	void
PGPWin32DriverRandomPoolGetBytesEntropy(
	PGPByte *		buf,
	unsigned		len,
	unsigned		bitsRequested,
	unsigned *		pbitsProvided)
{
	RandomPool *pool	= GetPool();

	if (bitsRequested <= pool->randBits)
		*pbitsProvided = bitsRequested;
	else
		*pbitsProvided = pool->randBits;

	sRandPoolGetBytesEntropy( NULL, buf, len, bitsRequested );
}


#endif //PGPSDK_DRIVER




/*__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 + -