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

📄 random.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
		{
		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 + -