📄 pgprandompool.c
字号:
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.)
*/
#if ! PGPSDK_DRIVER
static PGPUInt32
pgpGlobalRandomPoolAddKeystroke_internal( PGPInt32 event)
#else /* PGPSDK_DRIVER */
PGPUInt32
PGPGlobalRandomPoolAddKeystroke( PGPInt32 event)
#endif /* PGPSDK_DRIVER */
{
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;
pgpEnterZeroFunction();
#if (PGP_WIN32 || PGP_MACINTOSH) && ! PGPSDK_DRIVER
/*
** If the SDK driver is installed, do not count keystrokes added by
** SDK clients because the keystroke has already been accounted
** for in the driver.
*/
if( pgpSDKKeyboardEntropyDriverIsWorking() )
return 0;
#endif
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 );
}
#if ! PGPSDK_DRIVER
PGPUInt32
PGPGlobalRandomPoolAddKeystroke( PGPInt32 event)
{
pgpEnterZeroFunction();
#if (PGP_WIN32 || PGP_MACINTOSH) && ! PGPSDK_DRIVER
/*
** If the SDK driver is installed, do not count keystrokes added by
** SDK clients because the keystroke has already been accounted
** for in the driver.
*/
if( pgpSDKKeyboardEntropyDriverIsWorking() )
return 0;
#endif
return pgpGlobalRandomPoolAddState_back( TRUE, event, FALSE, FALSE );
}
#endif /* not PGPSDK_DRIVER */
/*
* 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.
*/
#if ! PGPSDK_DRIVER
static PGPUInt32
pgpGlobalRandomPoolMouseMoved_internal(void)
#else /* PGPSDK_DRIVER */
PGPUInt32
PGPGlobalRandomPoolMouseMoved(void)
#endif /* PGPSDK_DRIVER */
{
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;
pgpEnterZeroFunction();
#if PGP_WIN32 && ! PGPSDK_DRIVER
/*
** If the SDK driver is installed, do not count keystrokes added by
** SDK clients because the keystroke has already been accounted
** for in the driver. We don't cancel this out for the Mac because
** our Mac driver's granularity only measures the mouse once a second
** which can be too little when collecting random data.
*/
if( pgpSDKMouseEntropyDriverIsWorking() )
return 0;
#endif
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 );
}
#if ! PGPSDK_DRIVER
PGPUInt32
PGPGlobalRandomPoolMouseMoved(void)
{
pgpEnterZeroFunction();
#if PGP_WIN32 && ! PGPSDK_DRIVER
/*
** If the SDK driver is installed, do not count keystrokes added by
** SDK clients because the keystroke has already been accounted
** for in the driver. We don't cancel this out for the Mac because
** our Mac driver's granularity only measures the mouse once a second
** which can be too little when collecting random data.
*/
if( pgpSDKMouseEntropyDriverIsWorking() )
return 0;
#endif
return pgpGlobalRandomPoolAddState_back( FALSE, 0, TRUE, FALSE );
}
#endif /* not PGPSDK_DRIVER */
/*
* 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;
pgpEnterZeroFunction();
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 );
}
#if ! PGPSDK_DRIVER
static PGPError
pgpGlobalRandomPoolAddSystemState_internal()
#else /* PGPSDK_DRIVER */
PGPError
PGPGlobalRandomPoolAddSystemState()
#endif /* PGPSDK_DRIVER */
{
PGPRandomContext rc;
pgpEnterPGPErrorFunction();
pgpInitGlobalRandomPoolContext( &rc );
if (pgpRandomCollectOsData( &rc, TRUE )) {
pgpSetIsSeeded();
return kPGPError_NoErr;
}
else {
return kPGPError_UnknownError;
}
}
#if ! PGPSDK_DRIVER
/* This is always called from the front end */
PGPError
PGPGlobalRandomPoolAddSystemState()
{
pgpEnterPGPErrorFunction();
return pgpGlobalRandomPoolAddState_back( FALSE, 0, FALSE, TRUE );
}
/* Entry point for back end (or if no back end is running */
PGPError
pgpGlobalRandomPoolAddState_internal( PGPBoolean addKeyState,
PGPInt32 keyEvent, PGPBoolean addMouseState, PGPBoolean addSystemState )
{
if( addKeyState )
(void) pgpGlobalRandomPoolAddKeystroke_internal( keyEvent );
else if( addMouseState )
(void) pgpGlobalRandomPoolMouseMoved_internal( );
else if( addSystemState )
return pgpGlobalRandomPoolAddSystemState_internal( );
return kPGPError_NoErr;
}
#endif /* not PGPSDK_DRIVER */
#if ! PGPSDK_DRIVER
/* This is always called from the front end */
PGPBoolean
PGPGlobalRandomPoolHasIntelRNG( )
{
PGPBoolean hasIntelRNG = FALSE;
pgpEnterPGPErrorFunction();
(void)pgpGlobalRandomPoolGetInfo_back( NULL, NULL, NULL, NULL,
&hasIntelRNG );
return hasIntelRNG;
}
#endif /* not 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;
}
/*__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 + -