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

📄 random.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	   threat involved.  Being able to cause a change in the data being 
	   signed after the random DSA k value is generated would be a problem, 
	   but k is only generated after the data has already been hashed and 
	   the signature is about to be generated.

	   In general this type of attack would require cooperation between the 
	   VM and a hostile external party to, for example, ignore the fact 
	   that the VM has rolled back to an earlier point in the protocol so a 
	   repeat of a previous handshake message will be seen.  In other words 
	   it more or less requires control over the VM by an external party, and 
	   anyone faced with this level of attack has bigger things to worry 
	   about than RNG state rollback */
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 */
	for( iterationCount = 0; iterationCount < FAILSAFE_ITERATIONS_LARGE; 
		 iterationCount++ )
		{
		DECLARE_ORIGINAL_INT( randomPoolMixes );

		fastPoll();

		/* Mix the pool after the fast poll.  The poll itself can result in 
		   multiple sets of mixing, this final mix ensures that there's no
		   unmixed data left */
		STORE_ORIGINAL_INT( randomPoolMixes, randomInfo->randomPoolMixes );
		status = mixRandomPool( randomInfo );
		if( cryptStatusError( status ) )
			{
			krnlExitMutex( MUTEX_RANDOM );
			return( status );
			}
		POST( randomInfo->randomPoolMixes == RANDOMPOOL_MIXES || \
			  randomInfo->randomPoolMixes == ORIGINAL_VALUE( randomPoolMixes ) + 1 );

		/* If the pool is sufficiently mixed, we're done */
		if( randomInfo->randomPoolMixes >= RANDOMPOOL_MIXES )
			break;
		}
	ENSURES_MUTEX( iterationCount < FAILSAFE_ITERATIONS_LARGE );

	/* 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 );
		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 */
		REQUIRES_MUTEX( length - count < RANDOM_OUTPUTSIZE || \
						outputBytes == RANDOM_OUTPUTSIZE );
		REQUIRES_MUTEX( outputBytes <= RANDOMPOOL_SIZE / 2 );

		status = getRandomOutput( randomInfo, bufPtr, outputBytes );
		if( cryptStatusError( status ) )
			{
			krnlExitMutex( MUTEX_RANDOM );
			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 */
	ENSURES_MUTEX( 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;
		}

	krnlExitMutex( MUTEX_RANDOM );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Init/Shutdown Routines							*
*																			*
****************************************************************************/

/* Initialise the randomness subsystem */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int initRandomInfo( OUT_PTR TYPECAST( RANDOM_INFO ** ) void **randomInfoPtrPtr )
	{
	RANDOM_INFO testRandomInfo, *randomInfoPtr;
	BYTE buffer[ 16 + 8 ];
	int status;

	assert( isWritePtr( randomInfoPtrPtr, sizeof( void * ) ) );

	/* Clear return value */
	*randomInfoPtrPtr = NULL;

	/* Make sure that the crypto that we need is functioning as required */
	status = randomAlgorithmSelfTest();
	ENSURES( cryptStatusOK( status ) );

	/* The underlying crypto is OK, check that the cryptlib PRNG is working
	   correctly */
	initRandomPool( &testRandomInfo );
	status = mixRandomPool( &testRandomInfo );
	if( cryptStatusOK( status ) && \
		memcmp( testRandomInfo.randomPool,
				"\xF6\x8F\x30\xEE\x52\x13\x3E\x40\x06\x06\xA6\xBE\x91\xD2\xD9\x82", 16 ) )
		status = CRYPT_ERROR_FAILED;
	if( cryptStatusOK( status ) )
		status = mixRandomPool( &testRandomInfo );
	if( cryptStatusOK( status ) && \
		memcmp( testRandomInfo.randomPool,
				"\xAE\x94\x3B\xF2\x86\x5F\xCF\x76\x36\x2B\x80\xD5\x73\x86\x9B\x69", 16 ) )
		status = CRYPT_ERROR_FAILED;
	if( cryptStatusOK( status ) )
		status = mixRandomPool( &testRandomInfo );
	if( cryptStatusOK( status ) && \
		memcmp( testRandomInfo.randomPool,
				"\xBC\x2D\xC1\x03\x8C\x78\x6D\x04\xA8\xBD\xD5\x51\x80\xCA\x42\xF4", 16 ) )
		status = CRYPT_ERROR_FAILED;
	if( cryptStatusError( status ) )
		{
		endRandomPool( &testRandomInfo );
		retIntError();
		}

	/* Check that the ANSI X9.17 PRNG is working correctly */
	status = selfTestX917( &testRandomInfo, testRandomInfo.randomPool );
	if( cryptStatusError( status ) )
		{
		endRandomPool( &testRandomInfo );
		retIntError();
		}

	/* The underlying PRNGs are OK, check the overall random number
	   generation system.  Since we started with an all-zero seed we have
	   to fake the entropy-quality values for the artificial test pool */
	testRandomInfo.randomQuality = 100;
	testRandomInfo.randomPoolMixes = RANDOMPOOL_MIXES;
	status = getRandomOutput( &testRandomInfo, buffer, 16 );
	if( cryptStatusOK( status ) && \
		memcmp( buffer, "\x6B\x59\x1D\xCD\xE1\xB3\xA8\x50\x32\x84\x8C\x8D\x93\xB0\x74\xD7", 16 ) )
		status = CRYPT_ERROR_FAILED;
	if( cryptStatusError( status ) )
		{
		endRandomPool( &testRandomInfo );
		retIntError();
		}
	endRandomPool( &testRandomInfo );

	/* Check the ANSI X9.17 PRNG again, this time using FIPS test vectors */
	status = fipsTestX917( &testRandomInfo );
	if( cryptStatusError( status ) )
		{
		endRandomPool( &testRandomInfo );
		retIntError();
		}

	/* Allocate and initialise the random pool */
	if( ( status = krnlMemalloc( ( void ** ) &randomInfoPtr, \
								 sizeof( RANDOM_INFO ) ) ) != CRYPT_OK )
		return( status );
	initRandomPool( randomInfoPtr );

	/* Initialise any helper routines that may be needed */
	initRandomPolling();

	*randomInfoPtrPtr = randomInfoPtr;
	return( CRYPT_OK );
	}

/* Shut down the randomness subsystem.  Exactly what to do if we can't 
   exit the polling thread or acquire the mutex is a bit complicated, this 
   is a shouldn't-occur exception condition condition so it's not even 
   possible to plan for this since it's uncertain under which conditions (if 
   ever) this situation would occur.  We can't even perform a failsafe 
   zeroise of the pool data because it could lead to the other thread using 
   an all-zero key from the unexpectedly-cleared pool.  For now we play it 
   by the book and don't do anything if we can't exit the thread or acquire 
   the mutex, which avoids a segfault from pulling the random data out from 
   underneath the other thread */

STDC_NONNULL_ARG( ( 1 ) ) \
void endRandomInfo( INOUT TYPECAST( RANDOM_INFO ** ) void **randomInfoPtrPtr )
	{
	RANDOM_INFO *randomInfoPtr = *randomInfoPtrPtr;
	int status;

	assert( isWritePtr( randomInfoPtrPtr, sizeof( void * ) ) );
	assert( isWritePtr( *randomInfoPtrPtr, sizeof( RANDOM_INFO ) ) );

	/* Make sure that there are no background threads/processes still trying
	   to send us data */
	status = waitforRandomCompletion( TRUE );
	ENSURES_V( cryptStatusOK( status ) );	/* See comment above */

	/* Call any special-case shutdown functions */
	endRandomPolling();

	/* Shut down the random data pool.  We acquire the randomness mutex 
	   while we're doing this to ensure that any threads still using the
	   randomness info have exited before we destroy it */
	status = krnlEnterMutex( MUTEX_RANDOM );
	ENSURES_V( cryptStatusOK( status ) );	/* See comment above */
	endRandomPool( randomInfoPtr );
	krnlExitMutex( MUTEX_RANDOM );
	krnlMemfree( randomInfoPtrPtr );
	}

/****************************************************************************
*																			*
*							Add Random (Entropy) Data						*
*																			*
****************************************************************************/

/* Add new entropy data and an entropy quality estimate to the random pool */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int addEntropyData( INOUT TYPECAST( RANDOM_INFO * ) void *randomInfoPtr, 
					IN_BUFFER( length ) const void *buffer, 
					IN_LENGTH const int length )
	{
	RANDOM_INFO *randomInfo = ( RANDOM_INFO * ) randomInfoPtr;
	const BYTE *bufPtr = ( BYTE * ) buffer;
	int count, status;
#if 0	/* See comment in addEntropyQuality */
	DECLARE_ORIGINAL_INT( entropyByteCount );
#endif /* 0 */

	assert( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );
	assert( isReadPtr( buffer, length ) );

	REQUIRES( length > 0 && length < MAX_INTLENGTH );

	status = krnlEnterMutex( MUTEX_RANDOM );
	if( cryptStatusError( status ) )
		return( status );
	REQUIRES_MUTEX( sanityCheck( randomInfo ) );

#if 0	/* See comment in addEntropyQuality */
	STORE_ORIGINAL_INT( entropyByteCount, randomInfo->entropyByteCount );
#endif /* 0 */

	/* Mix the incoming data into the pool.  This operation is resistant to
	   chosen- and known-input attacks because the pool contents are unknown
	   to an attacker so XORing in known data won't help them.  If an
	   attacker could determine pool contents by observing the generator
	   output (which is defeated by the postprocessing) we'd have to perform 
	   an extra input mixing operation to defeat these attacks */
	for( count = 0; count < length; count++ )
		{
		ORIGINAL_INT_VAR( bufVal, bufPtr[ count ] );
		DECLARE_ORIGINAL_INT( poolVal );
		DECLARE_ORIGINAL_INT( newPoolVal );
		DECLARE_ORIGINAL_INT( poolPos );

		/* If the pool write position has reached the end of the pool, mix
		   the pool */
		if( randomInfo->randomPoolPos >= RANDOMPOOL_SIZE )
			{
			status = mixRandomPool( randomInfo );
			if( cryptStatusError( status ) )
				{
				krnlExitMutex( MUTEX_RANDOM );
				return( status );
				}
			ENSURES_MUTEX( randomInfo->randomPoolPos == 0 );
			}

		STORE_ORIGINAL_INT( poolVal,
							randomInfo->randomPool[ randomInfo->randomPoolPos ] );
		STORE_ORIGINAL_INT( poolPos, randomInfo->randomPoolPos );

		/* Precondition: We're adding data inside the pool */
		REQUIRES_MUTEX( randomInfo->randomPoolPos >= 0 && \
						randomInfo->randomPoolPos < RANDOMPOOL_SIZE );

		randomInfo->randomPool[ randomInfo->randomPoolPos++ ] ^= bufPtr[ count ];

		STORE_ORIGINAL_INT( newPoolVal,
							randomInfo->randomPool[ randomInfo->randomPoolPos - 1 ] );

		/* Postcondition: We've updated the byte at the current pool
		   position, and the value really was XORed into the pool rather
		   than (for example) overwriting it as with PGP/xorbytes or
		   GPG/add_randomness.  Note that in this case we can use a non-XOR
		   operation to check that the XOR succeeded, unlike the pool mixing
		   code which requires an XOR to check the original XOR */
		POST( randomInfo->randomPoolPos == \
			  ORIGINAL_VALUE( poolPos ) + 1 );
		POST( ( ( ORIGINAL_VALUE( newPoolVal ) == \
				  ORIGINAL_VALUE( bufVal ) ) && \
				( ORIGINAL_VALUE( poolVal ) == 0 ) ) || \
			  ( ORIGINAL_VALUE( newPoolVal ) != \
			    ORIGINAL_VALUE( bufVal ) ) );
		}

#if 0	/* See comment in addEntropyQuality */
	/* Remember how many bytes of entropy we added on this update */
	randomInfo->entropyByteCount += length;
#endif /* 0 */

	/* Postcondition: We processed all of the data */
	POST( count == length );
#if 0	/* See comment in addEntropyQuality */
	POST( randomInfo->entropyByteCount == \
		  ORIGINAL_VALUE( entropyByteCount ) + length );
#endif /* 0 */

	ENSURES_MUTEX( sanityCheck( randomInfo ) );

	krnlExitMutex( MUTEX_RANDOM );

	return( CRYPT_OK );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -