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

📄 rand_x917.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						cryptlib X9.17 Generator Routines					*
*						Copyright Peter Gutmann 1995-2007					*
*																			*
****************************************************************************/

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

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

/* Sanity-check the X9.17 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 X9.17 generator accounting information is within
	   bounds.  See the comment in generateX917() for the high-range check */
	if( randomInfo->x917Count < 0 || \
		randomInfo->x917Count > X917_MAX_CYCLES + \
								( MAX_RANDOM_BYTES / X917_POOLSIZE ) )
		return( FALSE );

	return( TRUE );
	}

/****************************************************************************
*																			*
*								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" 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 supplying a dateTime value to 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 */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int setKeyX917( INOUT RANDOM_INFO *randomInfo, 
				IN_BUFFER( X917_KEYSIZE ) const BYTE *key,
				IN_BUFFER( X917_POOLSIZE ) const BYTE *state, 
				IN_BUFFER_OPT( X917_POOLSIZE ) const BYTE *dateTime )
	{
	X917_3DES_KEY *des3Key = &randomInfo->x917Key;
	int desStatus;

	assert( isWritePtr( randomInfo, sizeof( RANDOM_INFO ) ) );
	assert( isReadPtr( key, sizeof( X917_KEYSIZE ) ) );
	assert( isReadPtr( state, sizeof( X917_KEYSIZE ) ) );
	assert( dateTime == NULL || \
			isReadPtr( dateTime, sizeof( X917_KEYSIZE ) ) );

	/* Precondition: the key and seed aren't being taken from the same 
	   location */
	REQUIRES( sanityCheck( randomInfo ) );
	REQUIRES( 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, since it's 
	   the same key in EDE mode */
	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 */
		ENSURES( 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->useX931 = TRUE;
		}

	/* We've initialised the generator and reset the cryptovariables, we're
	   ready to go */
	randomInfo->x917Inited = TRUE;
	randomInfo->x917Count = 0;

	ENSURES( sanityCheck( randomInfo ) );

	return( CRYPT_OK );
	}

/* Run the X9.17 generator over a block of data */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int generateX917( INOUT RANDOM_INFO *randomInfo, 
				  OUT_BUFFER_FIXED( length ) BYTE *data, 
				  IN_RANGE( 1, MAX_RANDOM_BYTES ) const int length )
	{
	BYTE encTime[ X917_POOLSIZE + 8 ], *dataPtr = data;
	int dataBlockPos;

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

	/* Precondition: The generator has been initialised, we're not asking 
	   for more data than the maximum that should be needed, and the
	   cryptovariables aren't past their use-by date */
	REQUIRES( sanityCheck( randomInfo ) );
	REQUIRES( randomInfo->x917Inited == TRUE );
	REQUIRES( length > 0 && length <= MAX_RANDOM_BYTES );
	REQUIRES( 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 initialised.  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 */
		REQUIRES( 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->useX931 )
			{
			/* 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 );

		/* Postcondition: The internal state has been copied to the output
		   (ick) */
		FORALL( k, 0, bytesToCopy, \
				data[ dataBlockPos + k ] == randomInfo->x917Pool[ k ] );

		/* V(n+1) = Enc( Enc( DT ) ^ out ); */
		for( i = 0; i < X917_POOLSIZE; i++ )
			randomInfo->x917Pool[ i ] ^= encTime[ i ];
		tdesEncrypt( randomInfo->x917Pool, &randomInfo->x917Key );

		/* If we're using the X9.31 interpretation, update DT to meet the
		   monotonically increasing time value requirement.  Although the
		   spec doesn't explicitly state this, the published test vectors
		   increment the rightmost byte so the value is treated as big-
		   endian */
		if( randomInfo->useX931 )
			{
			ORIGINAL_INT_VAR( lsb1, randomInfo->x917DT[ X917_POOLSIZE - 1 ] );
			ORIGINAL_INT_VAR( lsb2, randomInfo->x917DT[ X917_POOLSIZE - 2 ] );
			ORIGINAL_INT_VAR( lsb3, randomInfo->x917DT[ X917_POOLSIZE - 3 ] );

			for( i = X917_POOLSIZE - 1; i >= 0; i-- )
				{
				randomInfo->x917DT[ i ]++;
				if( randomInfo->x917DT[ i ] != 0 )
					break;
				i = i;
				}

			/* Postcondition: The value has been incremented by one */
			POST( ( randomInfo->x917DT[ X917_POOLSIZE - 1 ] == \
					ORIGINAL_VALUE( lsb1 ) + 1 ) || \
				  ( randomInfo->x917DT[ X917_POOLSIZE - 1 ] == 0 && \
					randomInfo->x917DT[ X917_POOLSIZE - 2 ] == \
					ORIGINAL_VALUE( lsb2 ) + 1 ) || \
				  ( randomInfo->x917DT[ X917_POOLSIZE - 1 ] == 0 && \
					randomInfo->x917DT[ X917_POOLSIZE - 2 ] == 0 && \
					randomInfo->x917DT[ X917_POOLSIZE - 3 ] == \
					ORIGINAL_VALUE( lsb3 ) + 1 ) );
			}

		/* Move on to the next block */
		dataPtr += bytesToCopy;
		randomInfo->x917Count++;

		/* Postcondition: We've processed one more block of data */
		ENSURES( dataPtr == data + dataBlockPos + bytesToCopy );
		POST( randomInfo->x917Count == ORIGINAL_VALUE( x917Count ) + 1 );
		}

	/* Postcondition: We processed all of the data */
	ENSURES( dataPtr == data + length );

	zeroise( encTime, X917_POOLSIZE );

	/* Postcondition: Nulla vestigia retrorsum */
	FORALL( i, 0, X917_POOLSIZE,
			encTime[ i ] == 0 );

	ENSURES( sanityCheck( randomInfo ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						X9.17 Generator Self-test Routines					*
*																			*
****************************************************************************/

/* X9.17/X9.31 generator test vectors.  The first set of values used are
   from the NIST publication "The Random Number Generator Validation System
   (RNGVS)" (unfortunately the MCT values for this are wrong so they can't
   be used), the second set are from test data used by an eval lab, and the
   third set are the values used for cryptlib's FIPS evaluation */

#define RNG_TEST_NIST		0
#define RNG_TEST_INFOGARD	1
#define RNG_TEST_FIPSEVAL	2

#define RNG_TEST_VALUES		RNG_TEST_INFOGARD

#if ( RNG_TEST_VALUES == RNG_TEST_NIST )
  #define VST_ITERATIONS	5
#elif ( RNG_TEST_VALUES == RNG_TEST_INFOGARD )
  #define VST_ITERATIONS	64
#elif ( RNG_TEST_VALUES == RNG_TEST_FIPSEVAL )
  #define VST_ITERATIONS	64
#endif /* VST iterations */

typedef struct {
	/* The values are declared with an extra byte of storage since they're
	   initialised from strings, which have an implicit '\0' at the end */
	const BYTE key[ X917_KEYSIZE + 1 ];
	const BYTE DT[ X917_BLOCKSIZE + 1 ], V[ X917_BLOCKSIZE + 1 ];
	const BYTE R[ X917_BLOCKSIZE + 1 ];
	} X917_MCT_TESTDATA;

typedef struct {
	const BYTE key[ X917_KEYSIZE + 1 ];
	const BYTE initDT[ X917_BLOCKSIZE + 1 ], initV[ X917_BLOCKSIZE + 1 ];
	const BYTE R[ VST_ITERATIONS ][ X917_BLOCKSIZE + 1 ];
	} X917_VST_TESTDATA;

static const X917_MCT_TESTDATA FAR_BSS x917MCTdata = {	/* Monte Carlo Test */
#if ( RNG_TEST_VALUES == RNG_TEST_NIST )	/* These values are wrong */
	/* Key1 = 75C71AE5A11A232C
	   Key2 = 40256DCD94F767B0
	   DT = C89A1D888ED12F3C
	   V = D5538F9CF450F53C
	   R = 77C695C33E51C8C0 */
	"\x75\xC7\x1A\xE5\xA1\x1A\x23\x2C\x40\x25\x6D\xCD\x94\xF7\x67\xB0",
	"\xC8\x9A\x1D\x88\x8E\xD1\x2F\x3C",
	"\xD5\x53\x8F\x9C\xF4\x50\xF5\x3C",
	"\x77\xC6\x95\xC3\x3E\x51\xC8\xC0"
#elif ( RNG_TEST_VALUES == RNG_TEST_INFOGARD )
	/* Key1 = 625BB5131A45F492
	   Key2 = 70971C9E0D4C9792
	   DT = 5F328264B787B098
	   V = A24F6E0EE43204CD
	   R = C7AC1E8F100CC30A */
	"\x62\x5B\xB5\x13\x1A\x45\xF4\x92\x70\x97\x1C\x9E\x0D\x4C\x97\x92",
	"\x5F\x32\x82\x64\xB7\x87\xB0\x98",
	"\xA2\x4F\x6E\x0E\xE4\x32\x04\xCD",
	"\xC7\xAC\x1E\x8F\x10\x0C\xC3\x0A"
#elif ( RNG_TEST_VALUES == RNG_TEST_FIPSEVAL )
	/* Key1 = A45BF2E50D153710
	   Key2 = 79832F38A89B2AB0
	   DT = 8219E01B2A6958BB
	   V = 283176BA23FA3181
	   R = ? */
	"\xA4\x5B\xF2\xE5\x0D\x15\x37\x10\x79\x83\x2F\x38\xA8\x9B\x2A\xB0",
	"\x82\x19\xE0\x1B\x2A\x69\x58\xBB",
	"\x28\x31\x76\xBA\x23\xFA\x31\x81",
	0
#endif /* Different test vectors */
	};

static const X917_VST_TESTDATA FAR_BSS x917VSTdata = {	/* Variable Seed Test (VST) */
#if ( RNG_TEST_VALUES == RNG_TEST_NIST )
	/* Count = 0
	   Key1 = 75C71AE5A11A232C
	   Key2 = 40256DCD94F767B0
	   DT = C89A1D888ED12F3C

⌨️ 快捷键说明

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