📄 random.c
字号:
{
length = min( totalLength, state->bufSize );
memcpy( state->buffer, valuePtr, length );
state->bufPos += length;
}
return( CRYPT_OK );
}
int addRandomLong( void *statePtr, const long value )
{
return( addRandomData( statePtr, &value, sizeof( long ) ) );
}
int endRandomData( void *statePtr, const int quality )
{
RANDOM_STATE_INFO *state = ( RANDOM_STATE_INFO * ) statePtr;
int status = state->updateStatus;
assert( isWritePtr( state, sizeof( RANDOM_STATE_INFO ) ) );
/* If there's data still in the accumulator, send it through to the
system device. A failure at this point is a should-never-occur
error, however if cryptlib has been shut down from another thread
the kernel will fail all non shutdown-related calls with a permission
error. To avoid false alarms, we mask out failures due to permission
errors */
if( state->bufPos > 0 && state->bufPos <= state->bufSize && \
state->bufSize >= 16 )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, state->buffer, state->bufPos );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ENTROPY );
if( cryptStatusOK( status ) )
status = state->updateStatus;
}
assert( cryptStatusOK( status ) || ( status == CRYPT_ERROR_PERMISSION ) );
/* If everything went OK, set the quality estimate for the data that
we've added */
if( cryptStatusOK( status ) && quality > 0 )
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SETATTRIBUTE, ( void * ) &quality,
CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
assert( cryptStatusOK( status ) || ( status == CRYPT_ERROR_PERMISSION ) );
/* Clear the accumulator and exit */
zeroise( state->buffer, state->bufSize );
zeroise( state, sizeof( RANDOM_STATE_INFO ) );
return( status );
}
/****************************************************************************
* *
* Random Pool Management Routines *
* *
****************************************************************************/
/* Initialise and shut down the random pool */
static void initRandomPool( RANDOM_INFO *randomInfo )
{
memset( randomInfo, 0, sizeof( RANDOM_INFO ) );
}
static void endRandomPool( RANDOM_INFO *randomInfo )
{
zeroise( randomInfo, sizeof( RANDOM_INFO ) );
}
/* Stir up the data in the random pool. Given a circular buffer of length n
bytes, a buffer position p, and a hash output size of h bytes, we hash
bytes from p - h...p - 1 (to provide chaining across previous hashes) and
p...p + 64 (to have as much surrounding data as possible affect the
current data). Then we move on to the next h bytes until all n bytes have
been mixed */
static void mixRandomPool( RANDOM_INFO *randomInfo )
{
HASHFUNCTION hashFunction;
BYTE dataBuffer[ CRYPT_MAX_HASHSIZE + 64 ];
int hashSize, hashIndex;
ORIGINAL_INT_VAR( randomPoolMixes, randomInfo->randomPoolMixes );
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
/* Stir up the entire pool. We can't check the return value of the
hashing call because there isn't one, however the SHA-1 code has gone
through a self-test when the randomness subsystem was inited */
for( hashIndex = 0; hashIndex < RANDOMPOOL_SIZE; hashIndex += hashSize )
{
int dataBufIndex, poolIndex;
/* Precondition: We're processing hashSize bytes at a time */
PRE( hashIndex % hashSize == 0 );
/* If we're at the start of the pool then the first block that we hash
is at the end of the pool, otherwise it's the block immediately
preceding the current one */
poolIndex = ( hashIndex > 0 ) ? hashIndex - hashSize : \
RANDOMPOOL_SIZE - hashSize;
/* Copy hashSize bytes from position p - 19...p - 1 in the circular
pool into the hash data buffer. We do this manually rather than
using memcpy() in order for the assertion-based testing (which
checks the source and desitnation index values) to work */
for( dataBufIndex = 0; dataBufIndex < hashSize; dataBufIndex++ )
dataBuffer[ dataBufIndex ] = randomInfo->randomPool[ poolIndex++ ];
/* Postconditions for the chaining data copy: We got h bytes from
within the pool, and before the current pool position */
POST( dataBufIndex == hashSize );
POST( poolIndex >= hashSize && poolIndex <= RANDOMPOOL_SIZE );
POST( !hashIndex || hashIndex == poolIndex );
/* Copy 64 bytes from position p from the circular pool into the hash
data buffer */
poolIndex = hashIndex;
while( dataBufIndex < hashSize + 64 )
dataBuffer[ dataBufIndex++ ] = \
randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ];
/* Postconditions for the state data copy: We got 64 bytes after the
current pool position */
POST( dataBufIndex == hashSize + 64 );
POST( poolIndex == hashIndex + 64 );
/* Hash the data at position p...p + hashSize in the circular pool
using the surrounding data extracted previously */
hashFunction( NULL, randomInfo->randomPool + hashIndex,
dataBuffer, dataBufIndex, HASH_ALL );
}
zeroise( dataBuffer, sizeof( dataBuffer ) );
/* Postconditions for the pool mixing: The entire pool was mixed and
temporary storage was cleared */
POST( hashIndex >= RANDOMPOOL_SIZE );
FORALL( i, 0, sizeof( dataBuffer ),
dataBuffer[ i ] == 0 );
/* Increment the mix count and move the write position back to the start
of the pool */
if( randomInfo->randomPoolMixes < RANDOMPOOL_MIXES )
randomInfo->randomPoolMixes++;
randomInfo->randomPoolPos = 0;
/* Postconditions for the status update: We mixed the pool at least
once, and we're back at the start of the pool */
POST( randomInfo->randomPoolMixes == RANDOMPOOL_MIXES || \
randomInfo->randomPoolMixes == \
ORIGINAL_VALUE( randomPoolMixes ) + 1 );
POST( randomInfo->randomPoolPos == 0 );
}
/****************************************************************************
* *
* ANSI X9.17 Generator *
* *
****************************************************************************/
/* The ANSI X9.17 Annex C generator has a number of problems (besides just
being slow) including a tiny internal state, use of fixed keys, no
entropy update, revealing the internal state to an attacker whenever it
generates output, and a horrible vulnerability to state compromise. For
FIPS 140 compliance however we need to use an approved generator (even
though Annex C is informative rather than normative and contains only "an
example of a pseudorandom key and IV generator" so that it could be argued
that any generator based on X9.17 3DES is permitted), which is why this
generator appears here.
In order to minimise the potential for damage we employ it as a post-
processor for the pool (since X9.17 produces a 1-1 mapping, it can never
make the output any worse), using as our timestamp input the main RNG
output. This is perfectly valid since X9.17 requires the use of DT, "a
date/time vector which is updated on each key generation", a requirement
which is met by the fastPoll() which is performed before the main pool is
mixed. The cryptlib representation of the date and time vector is as a
hash of assorted incidental data and the date and time. The fact that
99.9999% of the value of the generator is coming from the, uhh, timestamp
is as coincidental as the side effect of the engine cooling fan in the
Brabham ground effect cars.
Some eval labs may not like this use of DT, in which case it's also
possible to inject the extra seed material into the generator by using
the X9.31 interpretation of X9.17, which makes the V value an externally-
modifiable value. In this interpretation the generator design has
degenerated to little more than a 3DES encryption of V, which can hardly
have been the intent of the X9.17 designers. In other words the X9.17
operation:
out = Enc( Enc( in ) ^ V(n) );
V(n+1) = Enc( Enc( in ) ^ out );
degenerates to:
out = Enc( Enc( DT ) ^ in );
since V is overwritten on each iteration. If the eval lab requires this
interpretation rather than the more sensible DT one then this can be
enabled by clearing the seedViaDT flag in setKeyX917((), although we
don't do it by default since it's so far removed from the real X9.17
generator */
/* A macro to make what's being done by the generator easier to follow */
#define tdesEncrypt( data, key ) \
des_ecb3_encrypt( ( C_Block * ) ( data ), ( C_Block * ) ( data ), \
( key )->desKey1, ( key )->desKey2, \
( key )->desKey3, DES_ENCRYPT )
/* Set the X9.17 generator key */
static int setKeyX917( RANDOM_INFO *randomInfo, const BYTE *key,
const BYTE *state, const BYTE *dateTime )
{
X917_3DES_KEY *des3Key = &randomInfo->x917Key;
int desStatus;
/* Make sure that the key and seed aren't being taken from the same
location */
assert( memcmp( key, state, X917_POOLSIZE ) );
/* Remember that we're about to reset the generator state */
randomInfo->x917Inited = FALSE;
/* Schedule the DES keys. Rather than performing the third key schedule,
we just copy the first scheduled key into the third one */
des_set_odd_parity( ( C_Block * ) key );
des_set_odd_parity( ( C_Block * ) ( key + bitsToBytes( 64 ) ) );
desStatus = des_key_sched( ( des_cblock * ) key, des3Key->desKey1 );
if( desStatus == 0 )
desStatus = des_key_sched( ( des_cblock * ) ( key + bitsToBytes( 64 ) ),
des3Key->desKey2 );
memcpy( des3Key->desKey3, des3Key->desKey1, DES_KEYSIZE );
if( desStatus )
{
/* There was a problem initialising the keys, don't try and go any
further */
assert( randomInfo->x917Inited == FALSE );
return( CRYPT_ERROR_RANDOM );
}
/* Set up the generator state value V(0) and DT if we're using the X9.31
interpretation */
memcpy( randomInfo->x917Pool, state, X917_POOLSIZE );
if( dateTime != NULL )
{
memcpy( randomInfo->x917DT, dateTime, X917_POOLSIZE );
randomInfo->x917x931 = TRUE;
}
/* We've initialised the generator and reset the cryptovariables, we're
ready to go */
randomInfo->x917Inited = TRUE;
randomInfo->x917Count = 0;
return( CRYPT_OK );
}
/* Run the X9.17 generator over a block of data */
static int generateX917( RANDOM_INFO *randomInfo, BYTE *data,
const int length )
{
BYTE encTime[ X917_POOLSIZE ], *dataPtr = data;
int dataBlockPos;
/* Sanity check to make sure that the generator has been initialised */
if( !randomInfo->x917Inited )
{
assert( NOTREACHED );
return( CRYPT_ERROR_RANDOM );
}
/* Precondition: We're not asking for more data than the maximum that
should be needed, the generator has been initialised, and the
cryptovariables aren't past their use-by date */
PRE( length >= 1 && length <= MAX_RANDOM_BYTES );
PRE( randomInfo->x917Inited == TRUE );
PRE( randomInfo->x917Count >= 0 && \
randomInfo->x917Count < X917_MAX_CYCLES );
/* Process as many blocks of output as needed. We can't check the
return value of the encryption call because there isn't one, however
the 3DES code has gone through a self-test when the randomness
subsystem was inited. This can run the generator for slightly more
than X917_MAX_CYCLES if we're already close to the limit before we
start, but this isn't a big problem, it's only an approximate reset-
count measure anyway */
for( dataBlockPos = 0; dataBlockPos < length;
dataBlockPos += X917_POOLSIZE )
{
const int bytesToCopy = min( length - dataBlockPos, X917_POOLSIZE );
int i;
ORIGINAL_INT_VAR( x917Count, randomInfo->x917Count );
/* Precondition: We're processing from 1...X917_POOLSIZE bytes of
data */
PRE( bytesToCopy >= 1 && bytesToCopy <= X917_POOLSIZE );
/* Set the seed from the user-supplied data. This varies depending
on whether we're using the X9.17 or X9.31 interpretation of
seeding */
if( randomInfo->x917x931 )
{
/* It's the X9.31 interpretation, there's no further user seed
input apart from the V and DT that we set initially */
memcpy( encTime, randomInfo->x917DT, X917_POOLSIZE );
}
else
{
/* It's the X9.17 seed-via-DT interpretation, the user input is
DT. Copy in as much timestamp (+ other assorted data) as we
can into the DT value */
memcpy( encTime, dataPtr, bytesToCopy );
/* Inner precondition: The DT buffer contains the input data */
FORALL( k, 0, bytesToCopy,
encTime[ k ] == data[ dataBlockPos + k ] );
}
/* out = Enc( Enc( DT ) ^ V(n) ); */
tdesEncrypt( encTime, &randomInfo->x917Key );
for( i = 0; i < X917_POOLSIZE; i++ )
randomInfo->x917Pool[ i ] ^= encTime[ i ];
tdesEncrypt( randomInfo->x917Pool, &randomInfo->x917Key );
memcpy( dataPtr, randomInfo->x917Pool, bytesToCopy );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -