📄 random.c
字号:
randomInfo->randomPool[ 16 ] != \
( exportedRandomInfo->randomPool[ 16 ] ^ 0xFF ) ||
randomInfo->randomPool[ 24 ] != \
( exportedRandomInfo->randomPool[ 24 ] ^ 0xFF ) ||
randomInfo->randomPool[ 32 ] != \
( exportedRandomInfo->randomPool[ 32 ] ^ 0xFF ) );
/* Precondition for sampling the output: It's a sample from the start of
the pool */
PRE( samplePtr == randomInfo->randomPool );
PRE( x917SamplePtr == exportedRandomInfo->randomPool );
/* Check for stuck-at faults by comparing a short sample from the current
output with samples from the previous RANDOMPOOL_SAMPLES outputs */
sample = mgetLong( samplePtr );
for( i = 0; i < RANDOMPOOL_SAMPLES; i++ )
if( randomInfo->prevOutput[ i ] == sample )
/* We're repeating previous output, tell the caller to try
again */
return( OK_SPECIAL );
/* Postcondition: There are no values seen during a previous run present
in the output */
FORALL( i, 0, RANDOMPOOL_SAMPLES, \
randomInfo->prevOutput[ i ] != sample );
/* Process the exported pool with the X9.17 generator */
status = generateX917( randomInfo, exportedRandomInfo->randomPool,
RANDOMPOOL_ALLOCSIZE );
if( cryptStatusError( status ) )
return( status );
/* Check for stuck-at faults in the X9.17 generator by comparing a short
sample from the current output with samples from the previous
RANDOMPOOL_SAMPLES outputs */
sample = mgetLong( x917SamplePtr );
for( i = 0; i < RANDOMPOOL_SAMPLES; i++ )
if( randomInfo->x917PrevOutput[ i ] == sample )
/* We're repeating previous output, tell the caller to try
again */
return( OK_SPECIAL );
/* Postcondition: There are no values seen during a previous run present
in the output */
FORALL( i, 0, RANDOMPOOL_SAMPLES, \
randomInfo->x917PrevOutput[ i ] != sample );
return( CRYPT_OK );
}
static int getRandomOutput( RANDOM_INFO *randomInfo, BYTE *buffer,
const int length )
{
RANDOM_INFO exportedRandomInfo;
BYTE *samplePtr;
int noRandomRetries, i, status;
/* Precondition for output quantity: We're being asked for a valid output
length and we're not trying to use more than half the pool contents */
PRE( length > 0 && length <= RANDOM_OUTPUTSIZE );
PRE( length <= RANDOMPOOL_SIZE / 2 );
PRE( RANDOM_OUTPUTSIZE == RANDOMPOOL_SIZE / 2 );
/* If the X9.17 generator cryptovariables haven't been initialised yet
or have reached their use-by date, set the generator key and seed from
the pool contents, then mix the pool and crank the generator twice to
obscure the data that was used */
if( !randomInfo->x917Inited || \
randomInfo->x917Count >= X917_MAX_CYCLES )
{
mixRandomPool( randomInfo );
status = setKeyX917( randomInfo, randomInfo->randomPool,
randomInfo->randomPool + X917_KEYSIZE, NULL );
if( cryptStatusOK( status ) )
{
mixRandomPool( randomInfo );
status = generateX917( randomInfo, randomInfo->randomPool,
RANDOMPOOL_ALLOCSIZE );
}
if( cryptStatusOK( status ) )
{
mixRandomPool( randomInfo );
status = generateX917( randomInfo, randomInfo->randomPool,
RANDOMPOOL_ALLOCSIZE );
}
if( cryptStatusError( status ) )
return( status );
}
/* Precondition for drawing output from the generator: The pool is
sufficiently mixed, there's enough entropy present, and the X9.17
post-processor is ready for use */
PRE( randomInfo->randomPoolMixes == RANDOMPOOL_MIXES );
PRE( randomInfo->randomQuality >= 100 );
PRE( randomInfo->x917Inited );
/* Initialise the pool to contain the exported random data */
initRandomPool( &exportedRandomInfo );
/* Try to obtain random data from the pool */
for( noRandomRetries = 0; noRandomRetries < RANDOMPOOL_RETRIES;
noRandomRetries++ )
{
status = tryGetRandomOutput( randomInfo, &exportedRandomInfo );
if( status != OK_SPECIAL )
break;
}
/* If we ran out of retries so that we're repeating the same output
data or there was an error, fail */
if( cryptStatusError( status ) )
{
endRandomPool( &exportedRandomInfo );
/* Postcondition: Nulla vestigia retrorsum */
FORALL( i, 0, RANDOMPOOL_ALLOCSIZE, \
exportedRandomInfo.randomPool[ i ] == 0 );
/* We can't trust the pool data any more so we set its content
value to zero. Ideally we should flash lights and sound
klaxons as well, this is a catastrophic failure */
randomInfo->randomQuality = randomInfo->randomPoolMixes = 0;
randomInfo->x917Inited = FALSE;
assert( NOTREACHED );
return( CRYPT_ERROR_RANDOM );
}
/* Postcondition: We produced output without running out of retries */
POST( noRandomRetries < RANDOMPOOL_RETRIES );
/* Save a short sample from the current output for future checks */
PRE( randomInfo->prevOutputIndex >= 0 && \
randomInfo->prevOutputIndex < RANDOMPOOL_SAMPLES );
samplePtr = randomInfo->randomPool;
randomInfo->prevOutput[ randomInfo->prevOutputIndex ] = mgetLong( samplePtr );
samplePtr = exportedRandomInfo.randomPool;
randomInfo->x917PrevOutput[ randomInfo->prevOutputIndex++ ] = mgetLong( samplePtr );
randomInfo->prevOutputIndex %= RANDOMPOOL_SAMPLES;
POST( randomInfo->prevOutputIndex >= 0 && \
randomInfo->prevOutputIndex < RANDOMPOOL_SAMPLES );
/* Copy the transformed data to the output buffer, folding it in half as
we go to mask the original content */
for( i = 0; i < length; i++ )
buffer[ i ] = exportedRandomInfo.randomPool[ i ] ^ \
exportedRandomInfo.randomPool[ RANDOM_OUTPUTSIZE + i ];
/* Postcondition: We drew at most half of the transformed output from the
export pool */
POST( i <= RANDOMPOOL_SIZE / 2 );
/* Clean up */
endRandomPool( &exportedRandomInfo );
/* Postcondition: Nulla vestigia retrorsum */
FORALL( i, 0, RANDOMPOOL_ALLOCSIZE, \
exportedRandomInfo.randomPool[ i ] == 0 );
return( CRYPT_OK );
}
int getRandomData( RANDOM_INFO *randomInfo, void *buffer, const int length )
{
BYTE *bufPtr = buffer;
int count;
/* Preconditions: The input data is valid */
PRE( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );
PRE( length > 0 && isReadPtr( buffer, length ) );
/* Clear the return value and by extension make sure that we fail the
FIPS 140 tests on the output if there's a problem */
zeroise( buffer, length );
/* Precondition: We're not asking for more data than the maximum that
should be needed */
PRE( length >= 1 && length <= MAX_RANDOM_BYTES );
/* If we're using a stored random seed, add it to the entropy pool if
necessary. Note that we do this here rather than when we initialise
the randomness subsystem both because at that point the stream
subsystem may not be ready for use yet and because there may be a
requirement to periodically re-read the seed data if it's changed
by another process/task */
#ifdef CONFIG_RANDSEED
if( !randomInfo->seedProcessed )
addStoredSeedData( randomInfo );
#endif /* CONFIG_RANDSEED */
/* Perform a failsafe check to make sure that there's data available.
This should only ever be called once per app because after the first
blocking poll the programmer of the calling app will make sure that
there's a slow poll done earlier on */
if( randomInfo->randomQuality < 100 )
slowPoll();
/* Make sure that any background randomness-gathering process has
finished */
waitforRandomCompletion( FALSE );
/* If we still can't get any random information, let the user know */
if( randomInfo->randomQuality < 100 )
return( CRYPT_ERROR_RANDOM );
/* If the process has forked, we need to restart the generator output
process, but we can't determine this until after we've already
produced the output. If we do need to restart, we do it from this
point */
restartPoint:
/* Prepare to get data from the randomness pool. Before we do this, we
perform a final quick poll of the system to get any last bit of
entropy, and mix the entire pool. If the pool hasn't been sufficiently
mixed, we iterate until we've reached the minimum mix count */
do
{
fastPoll();
mixRandomPool( randomInfo );
}
while( randomInfo->randomPoolMixes < RANDOMPOOL_MIXES );
/* Keep producing RANDOMPOOL_OUTPUTSIZE bytes of output until the request
is satisfied */
for( count = 0; count < length; count += RANDOM_OUTPUTSIZE )
{
const int outputBytes = min( length - count, RANDOM_OUTPUTSIZE );
int status;
ORIGINAL_PTR( bufPtr );
/* Precondition for output quantity: Either we're on the last output
block or we're producing the maximum-size output quantity, and
we're never trying to use more than half the pool contents */
PRE( length - count < RANDOM_OUTPUTSIZE || \
outputBytes == RANDOM_OUTPUTSIZE );
PRE( outputBytes <= RANDOMPOOL_SIZE / 2 );
status = getRandomOutput( randomInfo, bufPtr, outputBytes );
if( cryptStatusError( status ) )
return( status );
bufPtr += outputBytes;
/* Postcondition: We're filling the output buffer and we wrote the
output to the correct portion of the output buffer */
POST( ( bufPtr > ( BYTE * ) buffer ) && \
( bufPtr <= ( BYTE * ) buffer + length ) );
POST( bufPtr == ORIGINAL_VALUE( bufPtr ) + outputBytes );
}
/* Postcondition: We filled the output buffer with the required amount
of output */
POST( bufPtr == ( BYTE * ) buffer + length );
/* Check whether the process forked while we were generating output. If
it did, force a complete remix of the pool and restart the output
generation process (the fast poll will ensure that the pools in the
parent and child differ) */
if( checkForked() )
{
randomInfo->randomPoolMixes = 0;
bufPtr = buffer;
goto restartPoint;
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Init/Shutdown Routines *
* *
****************************************************************************/
/* X9.17/X9.31 generator test vectors. The first set of values used are
from the NIST publication "The Random Number Generator Validation System
(RNGVS)" (unfortunately the MCT values for this are wrong so they can't
be used), the second set are from test data used by an eval lab, and the
third set are the values used for cryptlib's FIPS evaluation */
#define RNG_TEST_NIST 0
#define RNG_TEST_INFOGARD 1
#define RNG_TEST_FIPSEVAL 2
#define RNG_TEST_VALUES RNG_TEST_INFOGARD
#if ( RNG_TEST_VALUES == RNG_TEST_NIST )
#define VST_ITERATIONS 5
#elif ( RNG_TEST_VALUES == RNG_TEST_INFOGARD )
#define VST_ITERATIONS 64
#elif ( RNG_TEST_VALUES == RNG_TEST_FIPSEVAL )
#define VST_ITERATIONS 64
#endif /* VST iterations */
typedef struct {
const BYTE key[ X917_KEYSIZE ];
const BYTE DT[ X917_POOLSIZE ], V[ X917_POOLSIZE ];
const BYTE R[ X917_POOLSIZE ];
} X917_MCT_TESTDATA;
typedef struct {
const BYTE key[ X917_KEYSIZE ];
const BYTE initDT[ X917_POOLSIZE ], initV[ X917_POOLSIZE ];
const BYTE R[ VST_ITERATIONS ][ X917_POOLSIZE ];
} X917_VST_TESTDATA;
static const X917_MCT_TESTDATA x917MCTdata = { /* Monte Carlo Test */
#if ( RNG_TEST_VALUES == RNG_TEST_NIST ) /* These values are wrong */
/* Key1 = 75C71AE5A11A232C
Key2 = 40256DCD94F767B0
DT = C89A1D888ED12F3C
V = D5538F9CF450F53C
R = 77C695C33E51C8C0 */
"\x75\xC7\x1A\xE5\xA1\x1A\x23\x2C\x40\x25\x6D\xCD\x94\xF7\x67\xB0",
"\xC8\x9A\x1D\x88\x8E\xD1\x2F\x3C",
"\xD5\x53\x8F\x9C\xF4\x50\xF5\x3C",
"\x77\xC6\x95\xC3\x3E\x51\xC8\xC0"
#elif ( RNG_TEST_VALUES == RNG_TEST_INFOGARD )
/* Key1 = 625BB5131A45F492
Key2 = 70971C9E0D4C9792
DT = 5F328264B787B098
V = A24F6E0EE43204CD
R = C7AC1E8F100CC30A */
"\x62\x5B\xB5\x13\x1A\x45\xF4\x92\x70\x97\x1C\x9E\x0D\x4C\x97\x92",
"\x5F\x32\x82\x64\xB7\x87\xB0\x98",
"\xA2\x4F\x6E\x0E\xE4\x32\x04\xCD",
"\xC7\xAC\x1E\x8F\x10\x0C\xC3\x0A"
#elif ( RNG_TEST_VALUES == RNG_TEST_FIPSEVAL )
/* Key1 = A45BF2E50D153710
Key2 = 79832F38A89B2AB0
DT = 8219E01B2A6958BB
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -