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

📄 random.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					cryptlib Randomness Management Routines					*
*						Copyright Peter Gutmann 1995-2007					*
*																			*
****************************************************************************/

/* The random pool handling code in this module and the other modules in the
   /random subdirectory represent the cryptlib continuously seeded
   pseudorandom number generator (CSPRNG) as described in my 1998 Usenix
   Security Symposium paper "The generation of practically strong random
   numbers".

   The CSPRNG code is copyright Peter Gutmann (and various others) 1995-2004
   all rights reserved.  Redistribution of the CSPRNG modules and use in
   source and binary forms, with or without modification, are permitted
   provided that the following BSD-style license conditions are met:

   1. Redistributions of source code must retain the above copyright notice
	  and this permission notice in its entirety.

   2. Redistributions in binary form must reproduce the copyright notice in
	  the documentation and/or other materials provided with the distribution.

   3. A copy of any bugfixes or enhancements made must be provided to the
	  author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
	  baseline version of the code.

   ALTERNATIVELY, the code may be distributed under the terms of the GNU
   General Public License, version 2 or any later version published by the
   Free Software Foundation, in which case the provisions of the GNU GPL are
   required INSTEAD OF the above restrictions.

   ALTERNATIVELY ALTERNATIVELY, the code may be distributed under the terms 
   of the GNU Library/Lesser General Public License, version 2 or any later 
   version published by the Free Software Foundation, in which case the 
   provisions of the GNU LGPL are required INSTEAD OF the above restrictions.

   Although not required under the terms of the GPL or LGPL, it would still 
   be nice if you could make any changes available to the author to allow a
   consistent code base to be maintained */

#if defined( INC_ALL )
  #include "crypt.h"
  #ifdef CONFIG_RANDSEED
	#include "stream.h"
  #endif /* CONFIG_RANDSEED */
  #include "random_int.h"
#else
  #include "crypt.h"
  #ifdef CONFIG_RANDSEED
	#include "io/stream.h"
  #endif /* CONFIG_RANDSEED */
  #include "random/random_int.h"
#endif /* Compiler-specific includes */

/* If we don't have a defined randomness interface, complain */

#if !( defined( __BEOS__ ) || defined( __IBM4758__ ) || \
	   defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __MVS__ ) || \
	   defined( __OS2__ ) || defined( __PALMOS__ ) || \
	   defined( __TANDEM_NSK__ ) || defined( __TANDEM_OSS__ ) || \
	   defined( __UNIX__ ) || defined( __VMCMS__ ) || \
	   defined( __WIN16__ ) || defined( __WIN32__ ) || \
	   defined( __WINCE__ ) || defined( __XMK__ ) )
  #error You need to create OS-specific randomness-gathering functions in random/<os-name>.c
#endif /* Various OS-specific defines */

/* If we're using stored seed data, make sure that the seed quality setting
   is in order */

#ifdef CONFIG_RANDSEED
  #ifndef CONFIG_RANDSEED_QUALITY
	/* If the user hasn't provided a quality estimate, default to 80 */
	#define CONFIG_RANDSEED_QUALITY		80
  #endif /* !CONFIG_RANDSEED_QUALITY */
  #if ( CONFIG_RANDSEED_QUALITY < 10 ) || ( CONFIG_RANDSEED_QUALITY > 100 )
	#error CONFIG_RANDSEED_QUALITY must be between 10 and 100
  #endif /* CONFIG_RANDSEED_QUALITY check */
#endif /* CONFIG_RANDSEED */

/* A custom form of REQUIRES()/ENSURES() that takes care of unlocking the
   randomness mutex on the way out */

#define REQUIRES_MUTEX( x )	\
		if( !( x ) ) { krnlExitMutex( MUTEX_RANDOM ); retIntError(); }
#define ENSURES_MUTEX	REQUIRES_MUTEX

/****************************************************************************
*																			*
*						Randomness Interface Definitions					*
*																			*
****************************************************************************/

/* In order to avoid the pool startup problem (where initial pool data may
   consist of minimally-mixed entropy samples) we require that the pool be
   mixed at least the following number of times before we can draw data from
   it.  This usually happens automatically because a slow poll adds enough
   data to cause many mixing iterations, however if this doesn't happen we
   manually mix it the appropriate number of times to get it up to the
   correct level */

#define RANDOMPOOL_MIXES		10

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Sanity-check the randomness state */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheck( const RANDOM_INFO *randomInfo )
	{
	assert( isReadPtr( randomInfo, sizeof( RANDOM_INFO ) ) );

	/* Make sure that the pool index information is within bounds.  The pool
	   index can briefly become the same as RANDOMPOOL_SIZE if we've filled
	   the pool and we've about to mix it */
	if( randomInfo->randomPoolPos < 0 || \
		randomInfo->randomPoolPos > RANDOMPOOL_SIZE )
		return( FALSE );

	/* Make sure that the pool accounting information is within bounds */
	if( randomInfo->randomQuality < 0 || randomInfo->randomQuality > 100 )
		return( FALSE );
	if( randomInfo->randomPoolMixes < 0 || \
		randomInfo->randomPoolMixes > RANDOMPOOL_MIXES )
		return( FALSE );

	return( TRUE );
	}

/****************************************************************************
*																			*
*						Random Pool Management Routines						*
*																			*
****************************************************************************/

/* Initialise and shut down the random pool */

STDC_NONNULL_ARG( ( 1 ) ) \
void initRandomPool( INOUT RANDOM_INFO *randomInfo )
	{
	assert( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );

	memset( randomInfo, 0, sizeof( RANDOM_INFO ) );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void endRandomPool( INOUT RANDOM_INFO *randomInfo )
	{
	assert( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );

	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.  See "Cryptographic Security Architecture Design and 
   Implementation" for the full details of the PRNG design */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int mixRandomPool( INOUT RANDOM_INFO *randomInfo )
	{
	HASHFUNCTION_ATOMIC hashFunctionAtomic;
	BYTE dataBuffer[ CRYPT_MAX_HASHSIZE + 64 + 8 ];
	int hashSize, hashIndex;
	ORIGINAL_INT_VAR( randomPoolMixes, randomInfo->randomPoolMixes );

	assert( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );

	REQUIRES( sanityCheck( randomInfo ) );

	getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, &hashSize );

	/* Stir up the entire pool.  We can't check the return value of the
	   hashing call because there isn't one, however the hashing code has 
	   gone through a self-test when the randomness subsystem was 
	   initialised */
	for( hashIndex = 0; hashIndex < RANDOMPOOL_SIZE; hashIndex += hashSize )
		{
		int dataBufIndex, poolIndex;

		/* Precondition: We're processing hashSize bytes at a time */
		REQUIRES( 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 >= hashSize ) ? \
					hashIndex - hashSize : RANDOMPOOL_SIZE - hashSize;
		ENSURES( poolIndex >= 0 && poolIndex <= RANDOMPOOL_SIZE - hashSize );

		/* Copy hashSize bytes from position p - hashSize... p + 64 in the
		   circular pool into the hash data buffer:

				poolIndex
					| hashIndex
					v	v
			--------+---+-----------------------+---------
					| 20|			64			|			Pool
			--------+---+-----------------------+---------
					|							|
					+---------------------------+
					|							|			Buffer
					+---------------------------+
					 \							/
					  \	Hash  ------------------	
					   \	 /
			------------+---+-----------------------------
						| 20|								Pool'
			------------+---+----------------------------- 
					^	^						^
					|	|						|
				   p-h	p					  p+64 */
		for( dataBufIndex = 0; dataBufIndex < hashSize + 64; dataBufIndex++ )
			{
			dataBuffer[ dataBufIndex ] = randomInfo->randomPool[ poolIndex ];
			poolIndex = ( poolIndex + 1 ) % RANDOMPOOL_SIZE;
			}

		/* Postconditions for the state data copy: We got hashSize + 64 bytes 
		   surrounding the current pool position */
		ENSURES( dataBufIndex == hashSize + 64 );

		/* Hash the data in the circular pool, depositing the result at position 
		   p...p + hashSize */
		hashFunctionAtomic( randomInfo->randomPool + hashIndex,
							RANDOMPOOL_ALLOCSIZE - hashIndex, 
							dataBuffer, dataBufIndex );
		}
	zeroise( dataBuffer, CRYPT_MAX_HASHSIZE + 64 );

	/* Postconditions for the pool mixing: The entire pool was mixed and
	   temporary storage was cleared */
	ENSURES( hashIndex >= RANDOMPOOL_SIZE );
	FORALL( i, 0, CRYPT_MAX_HASHSIZE + 64,
			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 );
	ENSURES( randomInfo->randomPoolPos == 0 );

	ENSURES( sanityCheck( randomInfo ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Get Random Data								*
*																			*
****************************************************************************/

/* Get a block of random data from the randomness pool in such a way that
   compromise of the data doesn't compromise the pool and vice versa.  This 
   is done by performing the (one-way) pool mixing operation on the pool and
   on a transformed version of the pool that becomes the key.  This 
   corresponds to the Barak-Halevi construction:

	r || s' = next( s );
	s' = refresh( s ^ new_state );

   where 'r' is the generator output and 's' is the generator state (the RNG
   design here predates Barak-Halevi by about 10 years but the principle is
   the same).
   
   The transformed version of the pool from which the key data will be drawn 
   is then further processed by running each 64-bit block through the X9.17
   generator.  As an additional precaution the key data is folded in half to
   ensure that not even a hashed or encrypted form of the previous contents
   is available.  No pool data ever leaves the pool.

   This function performs a more paranoid version of the FIPS 140 continuous
   tests on both the main pool contents and the X9.17 generator output to
   detect stuck-at faults and short cycles in the output.  In addition the
   higher-level message handler applies FIPS 140-like statistical tests to
   the output and will retry the fetch if the output fails the tests.  This
   additional step is performed at a higher level because it's then applied
   to all randomness sources used by cryptlib and not just the built-in one.

   Because the pool output is folded to mask the PRNG output, the output from 
   each round of mixing is only half the pool size, as defined below */

#define RANDOM_OUTPUTSIZE	( RANDOMPOOL_SIZE / 2 )

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int tryGetRandomOutput( INOUT RANDOM_INFO *randomInfo,
							   INOUT RANDOM_INFO *exportedRandomInfo )
	{
	const BYTE *samplePtr = randomInfo->randomPool;
	const BYTE *x917SamplePtr = exportedRandomInfo->randomPool;
	unsigned long sample;
	int i, status;

	assert( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );
	assert( isWritePtr( exportedRandomInfo, sizeof( RANDOM_INFO ) ) );

	/* Precondition: The pool is ready to go.  This check isn't so much to
	   confirm that this really is the case (it's already been checked
	   elsewhere) but to ensure that the two pool parameters haven't been
	   reversed.  The use of generic pools for all types of random output is
	   useful in terms of providing a nice abstraction, but less useful for
	   type safety */
	REQUIRES( sanityCheck( randomInfo ) );
	REQUIRES( randomInfo->randomQuality >= 100 && \
			  randomInfo->randomPoolMixes >= RANDOMPOOL_MIXES && \
			  randomInfo->x917Inited == TRUE );
	REQUIRES( exportedRandomInfo->randomQuality == 0 && \
			  exportedRandomInfo->randomPoolMixes == 0 && \
			  exportedRandomInfo->x917Inited == FALSE );

	/* Copy the contents of the main pool across to the export pool,
	   transforming it as we go by flipping all of the bits */
	for( i = 0; i < RANDOMPOOL_ALLOCSIZE; i++ )
		exportedRandomInfo->randomPool[ i ] = randomInfo->randomPool[ i ] ^ 0xFF;

⌨️ 快捷键说明

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