📄 rand_x917.c
字号:
/****************************************************************************
* *
* 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 + -