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

📄 dev_sys.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* 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 );
	}

static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
							  const int length )
	{
	RANDOM_INFO *randomInfo = deviceInfo->randomInfo;
	BYTE *bufPtr = buffer;
	int count;

	/* Clear the return value and 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 needed
	   in any cryptlib operation, which in this case is the size of a
	   maximum-length PKC key */
	PRE( length >= 1 && length <= CRYPT_MAX_PKCSIZE );

	/* 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 );
	}

/****************************************************************************
*																			*
*					Device Init/Shutdown/Device Control Routines			*
*																			*
****************************************************************************/

/* Initialise and shut down the system device */

static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
						 const int nameLength )
	{
	STATIC_FN void initCapabilities( void );
	int status;

	UNUSED( name );

	/* Set up the randomness info */
	status = initRandomInfo( deviceInfo );
	if( cryptStatusError( status ) )
		return( status );

	/* Set up the capability information for this device and mark it as
	   active */
	initCapabilities();
	deviceInfo->label = "cryptlib system device";
	deviceInfo->flags = DEVICE_ACTIVE | DEVICE_LOGGEDIN | DEVICE_TIME;
	return( CRYPT_OK );
	}

static void shutdownFunction( DEVICE_INFO *deviceInfo )
	{
	endRandomInfo( deviceInfo );
	}

/* Handle device control functions */

static int controlFunction( DEVICE_INFO *deviceInfo,
							const CRYPT_ATTRIBUTE_TYPE type,
							const void *data, const int dataLength )
	{
	assert( type == CRYPT_IATTRIBUTE_ENTROPY || \
			type == CRYPT_IATTRIBUTE_ENTROPY_QUALITY || \
			type == CRYPT_IATTRIBUTE_RANDOM_NONCE || \
			type == CRYPT_IATTRIBUTE_SELFTEST || \
			type == CRYPT_IATTRIBUTE_TIME );

	/* Handle entropy addition */
	if( type == CRYPT_IATTRIBUTE_ENTROPY )
		{
		RANDOM_INFO *randomInfo = deviceInfo->randomInfo;
		BYTE *bufPtr = ( BYTE * ) data;
		int count = dataLength;
		ORIGINAL_INT_VAR( entropyByteCount, randomInfo->entropyByteCount );
		ORIGINAL_PTR( data );

		/* Precondition: The current entropy byte count has a sensible 
		   value */
		PRE( randomInfo->entropyByteCount >= 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 */
		while( count-- )
			{
			ORIGINAL_INT_VAR( bufVal, *bufPtr );
			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 )
				mixRandomPool( randomInfo );

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

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

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

			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 ) ) );
			}

		/* Remember how many bytes of entropy we added on this update */
		randomInfo->entropyByteCount += dataLength;

		/* Postcondition: We processed all of the data */
		POST( bufPtr == ORIGINAL_VALUE( data ) + dataLength );
		POST( randomInfo->entropyByteCount == \
			  ORIGINAL_VALUE( entropyByteCount ) + dataLength );

		return( CRYPT_OK );
		}
	if( type == CRYPT_IATTRIBUTE_ENTROPY_QUALITY )
		{
		RANDOM_INFO *randomInfo = deviceInfo->randomInfo;

		/* If there's not enough entropy data present to justify the claimed 
		   entropy quality level, signal an error */
		if( randomInfo->entropyByteCount <= 0 || \
			dataLength / 2 > randomInfo->entropyByteCount )
			{
			assert( NOTREACHED );
			return( CRYPT_ERROR_RANDOM );
			}
		randomInfo->entropyByteCount = 0;

		/* If we haven't reached the minimum quality level for generating
		   keys yet, update the quality level */
		if( randomInfo->randomQuality < 100 )
			randomInfo->randomQuality += dataLength;
		return( CRYPT_OK );
		}

	/* Handle nonces */
	if( type == CRYPT_IATTRIBUTE_RANDOM_NONCE )
		{
		static BOOLEAN nonceDataInitialised = FALSE;
		static BYTE nonceData[ CRYPT_MAX_HASHSIZE + 8 ];
		static HASHFUNCTION hashFunction;
		static int hashSize;
		BYTE *noncePtr = ( BYTE * ) data;
		int nonceLength = dataLength;

		/* Get a random (but not necessarily cryptographically strong random) 
		   nonce.  Some nonces can simply be fresh (for which a monotonically 
		   increasing sequence will do), some should be random (for which a 
		   hash of the sequence is adequate), and some need to be 
		   unpredictable.  In order to avoid problems arising from the
		   inadvertent use of a nonce with the wrong properties, we use 
		   unpredictable nonces in all cases, even where it isn't strictly 
		   necessary.
   
		   This simple generator divides the nonce state up into a public 
		   section of the same size as the hash output, and a private section 
		   which contains 64 bits of data from the crypto RNG which 
		   influences the public section.  The public and private sections 
		   are repeatedly hashed to produce the required amount of output.  
		   Note that this leaks a small amount of information about the 
		   crypto RNG output since an attacker knows that 
		   public_state_n = hash( public_state_n - 1, private_state ), but 
		   this isn't a major weakness.

		   If the nonce generator hasn't been initialised yet, we set up the 
		   hashing and get 64 bits of private nonce state.  What to do if 
		   the attempt to initialise the state fails is somewhat debatable.  
		   Since nonces are only ever used in protocols alongside crypto 
		   keys, and an RNG failure will be detected when the key is 
		   generated, we can generally ignore a failure at this point.
		   However, nonces are sometimes also used in non-crypto contexts 
		   (for example to generate cert serial numbers) where this 
		   detection in the RNG won't happen.  On the other hand we 
		   shouldn't really abort processing just because we can't get some 
		   no-value nonce data, so what we do is retry the fetch of nonce 
		   data (in case the system object was busy and the first attempt 
		   timed out), and if that fails too fall back to the system time.  
		   This is no longer unpredictable, but the only location where 
		   unpredictability matters is when used in combination with crypto 
		   operations, for which the absence of random data will be detected 
		   during key generation */
		if( !nonceDataInitialised )
			{
			RESOURCE_DATA msgData;
			int status;

			getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
			setMessageData( &msgData, nonceData + hashSize, 8 );
			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
									  IMESSAGE_GETATTRIBUTE_S, &msgData, 
									  CRYPT_IATTRIBUTE_RANDOM );
			if( cryptStatusError( status ) )
				status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
										  IMESSAGE_GETATTRIBUTE_S, &msgData, 
										  CRYPT_IATTRIBUTE_RANDOM );
			if( cryptStatusError( status ) )
				{
				const time_t theTime = getTime();

				memcpy( nonceData + hashSize, &theTime, sizeof( time_t ) );
				}
			nonceDataInitialised = TRUE;
			}

		/* Shuffle the public state and copy it to the output buffer until 
		   it's full */
		while( nonceLength > 0 )
			{

⌨️ 快捷键说明

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