📄 dev_sys.c
字号:
}
assert( totalLength >= 0 );
/* If everything went into the accumulator, we're done */
if( state->bufPos < state->bufSize )
return( CRYPT_OK );
assert( state->bufPos == state->bufSize );
/* The accumulator is full, send the data through to the system device */
setMessageData( &msgData, state->buffer, state->bufPos );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENTROPY );
if( cryptStatusError( status ) )
{
/* There was a problem moving the data through, make the error status
persistent */
state->updateStatus = status;
assert( NOTREACHED );
return( status );
}
state->bufPos = 0;
/* If there's uncopied data left, copy it in now */
if( totalLength > 0 )
{
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 */
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 ) );
/* 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 );
/* 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 a random pool */
static void initRandomPool( RANDOM_INFO *randomInfo )
{
memset( randomInfo, 0, sizeof( RANDOM_INFO ) );
}
static void endRandomPool( RANDOM_INFO *randomInfo )
{
memset( randomInfo, 0, sizeof( RANDOM_INFO ) );
}
/* Stir up the data in the random buffer. 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 ? 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 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,
however for FIPS 140 compliance 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
that 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 */
/* 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 *seed )
{
X917_3DES_KEY *des3Key = &randomInfo->x917Key;
int desStatus;
/* Make sure that the key and seed aren't taken from the same location */
assert( memcmp( key, seed, 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 seed value V(0) */
memcpy( randomInfo->x917Pool, seed, X917_POOLSIZE );
/* 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 timeBuffer[ X917_POOLSIZE ], *dataPtr = data;
int i;
/* 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 needed
in any cryptlib operation (which in this case is the size of a
maximum-length PKC key), the generator has been initialised, and the
cryptovariables aren't past their use-by date */
PRE( length >= 1 && length <= CRYPT_MAX_PKCSIZE );
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 */
for( i = 0; i < length; i += X917_POOLSIZE )
{
const int bytesToCopy = min( length - i, X917_POOLSIZE );
int j;
ORIGINAL_INT_VAR( x917Count, randomInfo->x917Count );
/* Precondition: We're processing from 1...X917_POOLSIZE bytes of
data */
PRE( bytesToCopy >= 1 && bytesToCopy <= X917_POOLSIZE );
/* Copy in as much timestamp (+ other assorted data) as we can from
the input */
memcpy( timeBuffer, dataPtr, bytesToCopy );
/* Inner precondition: The local buffer contains the input data */
FORALL( k, 0, bytesToCopy,
timeBuffer[ k ] == data[ i + k ] );
/* out = Enc( Enc( time ) ^ V(n) ); */
tdesEncrypt( timeBuffer, &randomInfo->x917Key );
for( j = 0; j < X917_POOLSIZE; j++ )
randomInfo->x917Pool[ j ] ^= timeBuffer[ j ];
tdesEncrypt( randomInfo->x917Pool, &randomInfo->x917Key );
memcpy( dataPtr, randomInfo->x917Pool, bytesToCopy );
/* Postcondition: The internal state has been copied to the output
(ick) */
FORALL( k, 0, bytesToCopy, \
data[ i + k ] == randomInfo->x917Pool[ k ] );
/* V(n+1) = Enc( Enc( time ) ^ out ); */
for( j = 0; j < X917_POOLSIZE; j++ )
randomInfo->x917Pool[ j ] ^= timeBuffer[ j ];
tdesEncrypt( randomInfo->x917Pool, &randomInfo->x917Key );
/* Move on to the next block */
dataPtr += bytesToCopy;
randomInfo->x917Count++;
/* Postcondition: We've processed one more block of data */
POST( dataPtr == data + i + bytesToCopy );
POST( randomInfo->x917Count == ORIGINAL_VALUE( x917Count ) + 1 );
}
/* Postcondition: We processed all of the data */
POST( dataPtr == data + length );
zeroise( timeBuffer, X917_POOLSIZE );
/* Postcondition: Nulla vestigia retrorsum */
FORALL( i, 0, X917_POOLSIZE,
timeBuffer[ i ] == 0 );
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -