📄 int_api.c
字号:
/****************************************************************************
* *
* cryptlib Internal API *
* Copyright Peter Gutmann 1992-2005 *
* *
****************************************************************************/
/* A generic module that implements a rug under which all problems not
solved elsewhere are swept */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "md2.h"
#include "md5.h"
#include "ripemd.h"
#include "sha.h"
#ifdef USE_SHA2
#include "sha2.h"
#endif /* USE_SHA2 */
#include "stream.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../crypt/md2.h"
#include "../crypt/md5.h"
#include "../crypt/ripemd.h"
#include "../crypt/sha.h"
#ifdef USE_SHA2
#include "../crypt/sha2.h"
#endif /* USE_SHA2 */
#include "../io/stream.h"
#else
#include "crypt.h"
#include "crypt/md2.h"
#include "crypt/md5.h"
#include "crypt/ripemd.h"
#include "crypt/sha.h"
#ifdef USE_SHA2
#include "crypt/sha2.h"
#endif /* USE_SHA2 */
#include "io/stream.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Internal API Functions *
* *
****************************************************************************/
/* Get the system time safely. The first function implements hard failures,
converting invalid time values to zero, which yield a warning date of
1/1/1970 rather than an out-of-bounds value or garbage value. The second
function implements soft failures, returning an estimate of the
approximate current date. The third function is used for operations such
as signing certs and timestamping and tries to get the time from a
hardware time source if one is available */
time_t getTime( void )
{
const time_t theTime = time( NULL );
return( ( theTime < MIN_TIME_VALUE ) ? 0 : theTime );
}
time_t getApproxTime( void )
{
const time_t theTime = time( NULL );
return( ( theTime < MIN_TIME_VALUE ) ? CURRENT_TIME_VALUE : theTime );
}
time_t getReliableTime( const CRYPT_HANDLE cryptHandle )
{
CRYPT_DEVICE cryptDevice;
RESOURCE_DATA msgData;
time_t theTime;
int status;
/* Get the dependent device for the object that needs the time */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
&cryptDevice, OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
cryptDevice = SYSTEM_OBJECT_HANDLE;
/* Try and get the time from the device */
setMessageData( &msgData, &theTime, sizeof( time_t ) );
status = krnlSendMessage( cryptDevice, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_TIME );
if( cryptStatusError( status ) && cryptDevice != SYSTEM_OBJECT_HANDLE )
/* We couldn't get the time from a crypto token, fall back to the
system device */
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_TIME );
if( cryptStatusError( status ) )
return( 0 );
return( ( theTime < MIN_TIME_VALUE ) ? 0 : theTime );
}
/* Calculate a 16-bit Fletcher-like checksum of a block of data. This isn't
quite a pure Fletcher checksum because we don't bother keeping the
accumulators at 8 bits, and also don't need to set the initial value to
nonzero since we'll never see a sequence of zero bytes. This isn't a big
deal since all we need is a consistent result. In addition we don't
bother with masking to 16 bits during the calculation since it's not
being used as a true checksum */
int checksumData( const void *data, const int dataLength )
{
const BYTE *dataPtr = data;
int sum1 = 0, sum2 = 0, i;
assert( isReadPtr( data, dataLength ) );
for( i = 0; i < dataLength; i++ )
{
sum1 += dataPtr[ i ];
sum2 += sum1;
}
return( sum2 & 0xFFFF );
}
/* Determine the parameters for a particular hash algorithm */
void md2HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void md5HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void ripemd160HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void shaHashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void sha2HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void getHashParameters( const CRYPT_ALGO_TYPE hashAlgorithm,
HASHFUNCTION *hashFunction, int *hashSize )
{
assert( isWritePtr( hashFunction, sizeof( HASHFUNCTION ) ) );
assert( ( hashSize == NULL ) || isWritePtr( hashSize, sizeof( int ) ) );
switch( hashAlgorithm )
{
#ifdef USE_MD2
case CRYPT_ALGO_MD2:
*hashFunction = md2HashBuffer;
if( hashSize != NULL )
*hashSize = MD2_DIGEST_LENGTH;
return;
#endif /* USE_MD2 */
case CRYPT_ALGO_MD5:
*hashFunction = md5HashBuffer;
if( hashSize != NULL )
*hashSize = MD5_DIGEST_LENGTH;
return;
#ifdef USE_RIPEMD160
case CRYPT_ALGO_RIPEMD160:
*hashFunction = ripemd160HashBuffer;
if( hashSize != NULL )
*hashSize = RIPEMD160_DIGEST_LENGTH;
return;
#endif /* USE_RIPEMD160 */
case CRYPT_ALGO_SHA:
*hashFunction = shaHashBuffer;
if( hashSize != NULL )
*hashSize = SHA_DIGEST_LENGTH;
return;
#ifdef USE_SHA2
case CRYPT_ALGO_SHA2:
*hashFunction = sha2HashBuffer;
if( hashSize != NULL )
*hashSize = SHA256_DIGEST_SIZE;
return;
#endif /* USE_SHA2 */
}
/* Make sure that we always get some sort of hash function rather than
just dying. This code always works because the internal self-test
has confirmed the availability and functioning of SHA-1 on startup */
*hashFunction = shaHashBuffer;
if( hashSize != NULL )
*hashSize = SHA_DIGEST_LENGTH;
assert( NOTREACHED );
}
/* Perform the FIPS-140 statistical checks that are feasible on a byte
string. The full suite of tests assumes that an infinite source of
values (and time) is available, the following is a scaled-down version
used to sanity-check keys and other short random data blocks. Note that
this check requires at least 64 bits of data in order to produce useful
results */
BOOLEAN checkEntropy( const BYTE *data, const int dataLength )
{
const int delta = ( dataLength < 16 ) ? 1 : 0;
int bitCount[ 4 ] = { 0 }, noOnes, i;
assert( isReadPtr( data, dataLength ) );
assert( dataLength >= 8 );
for( i = 0; i < dataLength; i++ )
{
const int value = data[ i ];
bitCount[ value & 3 ]++;
bitCount[ ( value >> 2 ) & 3 ]++;
bitCount[ ( value >> 4 ) & 3 ]++;
bitCount[ value >> 6 ]++;
}
/* Monobit test: Make sure that at least 1/4 of the bits are ones and 1/4
are zeroes */
noOnes = bitCount[ 1 ] + bitCount[ 2 ] + ( 2 * bitCount[ 3 ] );
if( noOnes < dataLength * 2 || noOnes > dataLength * 6 )
return( FALSE );
/* Poker test (almost): Make sure that each bit pair is present at least
1/16 of the time. The FIPS 140 version uses 4-bit values, but the
numer of samples available from the keys is far too small for this.
This isn't precisely 1/16, for short samples (< 128 bits) we adjust
the count by one because of the small sample size, and for odd-length
data we're getting four more samples so the actual figure is slightly
less than 1/16 */
if( ( bitCount[ 0 ] + delta < dataLength / 2 ) || \
( bitCount[ 1 ] + delta < dataLength / 2 ) || \
( bitCount[ 2 ] + delta < dataLength / 2 ) || \
( bitCount[ 3 ] + delta < dataLength / 2 ) )
return( FALSE );
return( TRUE );
}
/* Copy a string attribute to external storage, with various range checks
to follow the cryptlib semantics (these will already have been done by
the caller, this is just a backup check) */
int attributeCopy( RESOURCE_DATA *msgData, const void *attribute,
const int attributeLength )
{
assert( isWritePtr( msgData, sizeof( RESOURCE_DATA ) ) );
if( attributeLength <= 0 )
{
msgData->length = 0;
return( CRYPT_ERROR_NOTFOUND );
}
if( msgData->data != NULL )
{
assert( isReadPtr( attribute, attributeLength ) );
if( attributeLength > msgData->length || \
!isWritePtr( msgData->data, attributeLength ) )
return( CRYPT_ARGERROR_STR1 );
memcpy( msgData->data, attribute, attributeLength );
}
msgData->length = attributeLength;
return( CRYPT_OK );
}
/* Check whether a given algorithm is available */
BOOLEAN algoAvailable( const CRYPT_ALGO_TYPE cryptAlgo )
{
CRYPT_QUERY_INFO queryInfo;
return( cryptStatusOK( krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_QUERYCAPABILITY, &queryInfo,
cryptAlgo ) ) ? TRUE : FALSE );
}
/* For a given algorithm pair, check whether the first is stronger than the
second. For hashes the order is:
SHA2 > RIPEMD160 > SHA-1 > all others */
BOOLEAN isStrongerHash( const CRYPT_ALGO_TYPE algorithm1,
const CRYPT_ALGO_TYPE algorithm2 )
{
static const CRYPT_ALGO_TYPE algoPrecedence[] = {
CRYPT_ALGO_SHA2, CRYPT_ALGO_RIPEMD160, CRYPT_ALGO_SHA,
CRYPT_ALGO_NONE };
int algo1index, algo2index;
/* Find the relative positions on the scale of the two algorithms */
for( algo1index = 0; algoPrecedence[ algo1index ] != algorithm1;
algo1index++ )
if( algoPrecedence[ algo1index ] == CRYPT_ALGO_NONE )
/* We've reached an unrated algorithm, it can't be stronger
than the other one */
return( FALSE );
for( algo2index = 0; algoPrecedence[ algo2index ] != algorithm2;
algo2index++ )
if( algoPrecedence[ algo2index ] == CRYPT_ALGO_NONE )
/* We've reached an unrated algorithm, it's weaker than the
other one */
return( TRUE );
/* If the first algorithm has a smaller index than the second, it's a
stronger algorithm */
return( ( algo1index < algo2index ) ? TRUE : FALSE );
}
/* Sanitise a string before passing it back to the user. This is used to
clear potential problem characters (for example control characters)
from strings passed back from untrusted sources */
char *sanitiseString( char *string )
{
int i;
assert( isWritePtr( string, strlen( string ) ) );
/* Remove any potentially unsafe characters from the string */
for( i = 0; string[ i ] != '\0'; i++ )
if( !isPrint( string[ i ] ) )
string[ i ] = '.';
return( string );
}
/****************************************************************************
* *
* Dynamic Buffer Management Routines *
* *
****************************************************************************/
/* Dynamic buffer management functions. When reading variable-length
attribute data we can usually fit the data in a small, fixed-length
buffer, but occasionally we have to cope with larger data amounts that
require a dynamically-allocated buffer. The following routines manage
this process, dynamically allocating and freeing a larger buffer if
required */
int dynCreate( DYNBUF *dynBuf, const CRYPT_HANDLE cryptHandle,
const CRYPT_ATTRIBUTE_TYPE attributeType )
{
RESOURCE_DATA msgData;
const MESSAGE_TYPE message = \
( attributeType == CRYPT_CERTFORMAT_CERTIFICATE ) ? \
IMESSAGE_CRT_EXPORT : IMESSAGE_GETATTRIBUTE_S;
void *dataPtr = NULL;
int status;
assert( isWritePtr( dynBuf, sizeof( DYNBUF ) ) );
assert( ( cryptHandle == CRYPT_UNUSED && \
attributeType == CRYPT_UNUSED ) || \
( isHandleRangeValid( cryptHandle ) && \
( isAttribute( attributeType ) || \
isInternalAttribute( attributeType ) ) ) );
/* Clear return value */
dynBuf->data = dynBuf->dataBuffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -