📄 ctx_misc.c
字号:
/* Finally, if the caller has supplied a maximum-range bignum value,
make sure that the value that we've read is less than this */
if( maxRange != NULL && BN_cmp( bignum, maxRange ) >= 0 )
return( CRYPT_ERROR_BADDATA );
return( CRYPT_OK );
}
/* Convert a BIGNUM value into a byte string */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int getBignumData( IN TYPECAST( BIGNUM * ) const void *bignumPtr,
OUT_BUFFER( dataMaxLength, *dataLength ) void *data,
IN_LENGTH_SHORT_MIN( 16 ) const int dataMaxLength,
OUT_LENGTH_SHORT_Z int *dataLength )
{
BIGNUM *bignum = ( BIGNUM * ) bignumPtr;
int length;
assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );
assert( isWritePtr( data, dataMaxLength ) );
assert( isWritePtr( dataLength, sizeof( int ) ) );
REQUIRES( dataMaxLength > 16 && dataMaxLength < MAX_INTLENGTH_SHORT );
/* Clear return values */
memset( data, 0, min( 16, dataMaxLength ) );
*dataLength = 0;
/* Make sure that the result will fit into the output buffer */
length = BN_num_bytes( bignum );
ENSURES( length > 0 && length <= CRYPT_MAX_PKCSIZE );
length = BN_bn2bin( bignum, data );
ENSURES( length > 0 && length <= CRYPT_MAX_PKCSIZE );
*dataLength = length;
return( CRYPT_OK );
}
#else
STDC_NONNULL_ARG( ( 1 ) ) \
void clearTempBignums( INOUT PKC_INFO *pkcInfo )
{
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int initContextBignums( INOUT PKC_INFO *pkcInfo,
IN_RANGE( 0, 3 ) const int sideChannelProtectionLevel )
{
}
STDC_NONNULL_ARG( ( 1 ) ) \
void freeContextBignums( INOUT PKC_INFO *pkcInfo,
IN_FLAGS( CONTEXT ) const int contextFlags )
{
}
#endif /* USE_PKC */
/****************************************************************************
* *
* Self-test Support Functions *
* *
****************************************************************************/
/* Statically initialised a context used for the internal self-test */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int staticInitContext( INOUT CONTEXT_INFO *contextInfoPtr,
IN_ENUM( CONTEXT_TYPE ) const CONTEXT_TYPE type,
const CAPABILITY_INFO *capabilityInfoPtr,
INOUT_BUFFER_FIXED( contextDataSize ) void *contextData,
IN_LENGTH_SHORT_MIN( 32 ) const int contextDataSize,
IN_OPT void *keyData )
{
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );
assert( isReadPtr( contextData, contextDataSize ) );
REQUIRES( type > CONTEXT_NONE && type < CONTEXT_LAST );
REQUIRES( contextDataSize >= 32 && \
contextDataSize < MAX_INTLENGTH_SHORT );
memset( contextInfoPtr, 0, sizeof( CONTEXT_INFO ) );
memset( contextData, 0, contextDataSize );
contextInfoPtr->type = type;
contextInfoPtr->capabilityInfo = capabilityInfoPtr;
switch( type )
{
case CONTEXT_CONV:
contextInfoPtr->ctxConv = ( CONV_INFO * ) contextData;
contextInfoPtr->ctxConv->key = keyData;
break;
case CONTEXT_HASH:
contextInfoPtr->ctxHash = ( HASH_INFO * ) contextData;
contextInfoPtr->ctxHash->hashInfo = keyData;
break;
case CONTEXT_MAC:
contextInfoPtr->ctxMAC = ( MAC_INFO * ) contextData;
contextInfoPtr->ctxMAC->macInfo = keyData;
break;
case CONTEXT_PKC:
/* PKC context initialisation is a bit more complex because we
have to set up all of the bignum values as well */
contextInfoPtr->ctxPKC = ( PKC_INFO * ) contextData;
status = initContextBignums( contextData,
( capabilityInfoPtr->cryptAlgo == CRYPT_ALGO_RSA ) ? \
TRUE : FALSE );
if( cryptStatusError( status ) )
return( status );
initKeyRead( contextInfoPtr );
initKeyWrite( contextInfoPtr ); /* For calcKeyID() */
break;
default:
retIntError();
}
return( CRYPT_OK );
}
STDC_NONNULL_ARG( ( 1 ) ) \
void staticDestroyContext( INOUT CONTEXT_INFO *contextInfoPtr )
{
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
if( contextInfoPtr->type == CONTEXT_PKC )
{
freeContextBignums( contextInfoPtr->ctxPKC,
( contextInfoPtr->capabilityInfo->cryptAlgo == \
CRYPT_ALGO_RSA ) ? CONTEXT_FLAG_SIDECHANNELPROTECTION : 0 );
}
memset( contextInfoPtr, 0, sizeof( CONTEXT_INFO ) );
}
/* Perform a self-test of a cipher, encrypting and decrypting one block of
data and comparing it to a fixed test value */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5, 6 ) ) \
int testCipher( const CAPABILITY_INFO *capabilityInfo,
INOUT void *keyDataStorage,
IN_BUFFER( keySize ) const void *key,
IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) const int keySize,
const void *plaintext,
const void *ciphertext )
{
CONTEXT_INFO contextInfo;
CONV_INFO contextData;
BYTE temp[ CRYPT_MAX_IVSIZE + 8 ];
int status;
assert( isReadPtr( capabilityInfo, sizeof( CAPABILITY_INFO ) ) );
assert( isWritePtr( keyDataStorage, 16 ) );
assert( isReadPtr( key, keySize ) );
assert( isReadPtr( plaintext, capabilityInfo->blockSize ) );
assert( isReadPtr( ciphertext, capabilityInfo->blockSize ) );
REQUIRES( keySize >= MIN_KEYSIZE && keySize <= CRYPT_MAX_KEYSIZE );
memcpy( temp, plaintext, capabilityInfo->blockSize );
status = staticInitContext( &contextInfo, CONTEXT_CONV, capabilityInfo,
&contextData, sizeof( CONV_INFO ),
keyDataStorage );
if( cryptStatusError( status ) )
return( status );
status = capabilityInfo->initKeyFunction( &contextInfo, key, keySize );
if( cryptStatusOK( status ) )
status = capabilityInfo->encryptFunction( &contextInfo, temp,
capabilityInfo->blockSize );
if( cryptStatusOK( status ) && \
memcmp( ciphertext, temp, capabilityInfo->blockSize ) )
status = CRYPT_ERROR_FAILED;
if( cryptStatusOK( status ) )
status = capabilityInfo->decryptFunction( &contextInfo, temp,
capabilityInfo->blockSize );
staticDestroyContext( &contextInfo );
if( cryptStatusError( status ) || \
memcmp( plaintext, temp, capabilityInfo->blockSize ) )
return( CRYPT_ERROR_FAILED );
return( CRYPT_OK );
}
/* Perform a self-test of a hash or MAC */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
int testHash( const CAPABILITY_INFO *capabilityInfo,
INOUT void *hashDataStorage,
IN_BUFFER_OPT( dataLength ) const void *data,
IN_LENGTH_SHORT_Z const int dataLength,
const void *hashValue )
{
CONTEXT_INFO contextInfo;
HASH_INFO contextData;
int status;
assert( isReadPtr( capabilityInfo, sizeof( CAPABILITY_INFO ) ) );
assert( isWritePtr( hashDataStorage, 16 ) );
assert( ( data == NULL && dataLength == 0 ) || \
isReadPtr( data, dataLength ) );
assert( isReadPtr( hashValue, capabilityInfo->blockSize ) );
REQUIRES( ( data == NULL && dataLength == 0 ) || \
( data != NULL && \
dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT ) );
status = staticInitContext( &contextInfo, CONTEXT_HASH, capabilityInfo,
&contextData, sizeof( HASH_INFO ),
hashDataStorage );
if( cryptStatusError( status ) )
return( status );
if( data != NULL )
{
/* Some of the test vector sets start out with empty strings so we
only call the hash function if we've actually been fed data to
hash */
status = capabilityInfo->encryptFunction( &contextInfo,
( void * ) data,
dataLength );
contextInfo.flags |= CONTEXT_FLAG_HASH_INITED;
}
if( cryptStatusOK( status ) )
status = capabilityInfo->encryptFunction( &contextInfo, "", 0 );
if( cryptStatusOK( status ) && \
memcmp( contextInfo.ctxHash->hash, hashValue,
capabilityInfo->blockSize ) )
status = CRYPT_ERROR_FAILED;
staticDestroyContext( &contextInfo );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5, 7 ) ) \
int testMAC( const CAPABILITY_INFO *capabilityInfo,
INOUT void *macDataStorage,
IN_BUFFER( keySize ) const void *key,
IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) const int keySize,
IN_BUFFER( dataLength ) const void *data,
IN_LENGTH_SHORT_MIN( 8 ) const int dataLength,
const void *hashValue )
{
CONTEXT_INFO contextInfo;
MAC_INFO contextData;
int status;
assert( isReadPtr( capabilityInfo, sizeof( CAPABILITY_INFO ) ) );
assert( isWritePtr( macDataStorage, 16 ) );
assert( isReadPtr( key, keySize ) );
assert( isReadPtr( data, dataLength ) );
assert( isReadPtr( hashValue, capabilityInfo->blockSize ) );
REQUIRES( keySize >= 4 && keySize < MAX_INTLENGTH_SHORT );
REQUIRES( dataLength >= 8 && dataLength < MAX_INTLENGTH_SHORT );
status = staticInitContext( &contextInfo, CONTEXT_MAC, capabilityInfo,
&contextData, sizeof( MAC_INFO ),
macDataStorage );
if( cryptStatusError( status ) )
return( status );
status = capabilityInfo->initKeyFunction( &contextInfo, key, keySize );
if( cryptStatusOK( status ) )
{
status = capabilityInfo->encryptFunction( &contextInfo,
( void * ) data,
dataLength );
contextInfo.flags |= CONTEXT_FLAG_HASH_INITED;
}
if( cryptStatusOK( status ) )
status = capabilityInfo->encryptFunction( &contextInfo, "", 0 );
if( cryptStatusOK( status ) && \
memcmp( contextInfo.ctxMAC->mac, hashValue,
capabilityInfo->blockSize ) )
status = CRYPT_ERROR_FAILED;
staticDestroyContext( &contextInfo );
return( status );
}
/****************************************************************************
* *
* Hash External Access Functions *
* *
****************************************************************************/
/* Determine the parameters for a particular hash algorithm */
typedef struct {
const CRYPT_ALGO_TYPE cryptAlgo;
const int hashSize;
const HASHFUNCTION function;
} HASHFUNCTION_INFO;
typedef struct {
const CRYPT_ALGO_TYPE cryptAlgo;
const int hashSize;
const HASHFUNCTION_ATOMIC function;
} HASHFUNCTION_ATOMIC_INFO;
STDC_NONNULL_ARG( ( 2 ) ) \
void getHashParameters( IN_ALGO const CRYPT_ALGO_TYPE hashAlgorithm,
OUT_PTR HASHFUNCTION *hashFunction,
OUT_OPT_LENGTH_SHORT_Z int *hashOutputSize )
{
static const HASHFUNCTION_INFO FAR_BSS hashFunctions[] = {
#ifdef USE_MD5
{ CRYPT_ALGO_MD5, MD5_DIGEST_LENGTH, md5HashBuffer },
#endif /* USE_MD5 */
#ifdef USE_RIPEMD160
{ CRYPT_ALGO_RIPEMD160, RIPEMD160_DIGEST_LENGTH, ripemd160HashBuffer },
#endif /* USE_RIPEMD160 */
{ CRYPT_ALGO_SHA1, SHA_DIGEST_LENGTH, shaHashBuffer },
#ifdef USE_SHA2
{ CRYPT_ALGO_SHA2, SHA256_DIGEST_SIZE, sha2HashBuffer },
#ifdef USE_SHA2_512
/* SHA2-512 is only available on systems with 64-bit data type
support, at the moment this is only used internally for some PRFs
so we have to handle it via a kludge on SHA2 */
{ CRYPT_ALGO_SHA2 + 1, SHA512_DIGEST_SIZE, sha2_512HashBuffer },
#endif /* USE_SHA2_512 */
#endif /* USE_SHA2 */
{ CRYPT_ALGO_NONE, SHA_DIGEST_LENGTH, shaHashBuffer },
{ CRYPT_ALGO_NONE, SHA_DIGEST_LENGTH, shaHashBuffer }
};
int i;
assert( hashAlgorithm >= CRYPT_ALGO_FIRST_HASH && \
hashAlgorithm <= CRYPT_ALGO_LAST_HASH );
/* We don't use REQUIRES() for this for the reason given in the
comments below */
assert( isWritePtr( hashFunction, sizeof( HASHFUNCTION ) ) );
assert( ( hashOutputSize == NULL ) || \
isWritePtr( hashOutputSize, sizeof( int ) ) );
/* Find the info for the requested hash algorithm */
for( i = 0;
hashFunctions[ i ].cryptAlgo != hashAlgorithm && \
hashFunctions[ i ].cryptAlgo != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( hashFunctions, HASHFUNCTION_INFO );
i++ );
if( i >= FAILSAFE_ARRAYSIZE( hashFunctions, HASHFUNCTION_INFO ) || \
hashFunctions[ i ].cryptAlgo == CRYPT_ALGO_NONE )
{
/* 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( hashOutputSize != NULL )
*hashOutputSize = SHA_DIGEST_LENGTH;
retIntError_Void();
}
*hashFunction = hashFunctions[ i ].function;
if( hashOutputSize != NULL )
*hashOutputSize = hashFunctions[ i ].hashSize;
}
STDC_NONNULL_ARG( ( 2 ) ) \
void getHashAtomicParameters( IN_ALGO const CRYPT_ALGO_TYPE hashAlgorithm,
OUT_PTR HASHFUNCTION_ATOMIC *hashFunctionAtomic,
OUT_OPT_LENGTH_SHORT_Z int *hashOutputSize )
{
static const HASHFUNCTION_ATOMIC_INFO FAR_BSS hashFunctions[] = {
#ifdef USE_MD5
{ CRYPT_ALGO_MD5, MD5_DIGEST_LENGTH, md5HashBufferAtomic },
#endif /* USE_MD5 */
#ifdef USE_RIPEMD160
{ CRYPT_ALGO_RIPEMD160, RIPEMD160_DIGEST_LENGTH, ripemd160HashBufferAtomic },
#endif /* USE_RIPEMD160 */
{ CRYPT_ALGO_SHA1, SHA_DIGEST_LENGTH, shaHashBufferAtomic },
#ifdef USE_SHA2
{ CRYPT_ALGO_SHA2, SHA256_DIGEST_SIZE, sha2HashBufferAtomic },
#ifdef USE_SHA2_512
/* SHA2-512 is only available on systems with 64-bit data type
support, at the moment this is only used internally for some PRFs
so we have to handle it via a kludge on SHA2 */
{ CRYPT_ALGO_SHA2 + 1, SHA512_DIGEST_SIZE, sha2_512HashBufferAtomic },
#endif /* USE_SHA2_512 */
#endif /* USE_SHA2 */
{ CRYPT_ALGO_NONE, SHA_DIGEST_LENGTH, shaHashBufferAtomic },
{ CRYPT_ALGO_NONE, SHA_DIGEST_LENGTH, shaHashBufferAtomic }
};
int i;
assert( hashAlgorithm >= CRYPT_ALGO_FIRST_HASH && \
hashAlgorithm <= CRYPT_ALGO_LAST_HASH );
/* We don't use REQUIRES() for this for the reason given in the
comments below */
assert( isWritePtr( hashFunctionAtomic, sizeof( HASHFUNCTION_ATOMIC ) ) );
assert( ( hashOutputSize == NULL ) || \
isWritePtr( hashOutputSize, sizeof( int ) ) );
/* Find the info for the requested hash algorithm */
for( i = 0;
hashFunctions[ i ].cryptAlgo != hashAlgorithm && \
hashFunctions[ i ].cryptAlgo != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( hashFunctions, HASHFUNCTION_INFO );
i++ );
if( i >= FAILSAFE_ARRAYSIZE( hashFunctions, HASHFUNCTION_INFO ) || \
hashFunctions[ i ].cryptAlgo == CRYPT_ALGO_NONE )
{
/* 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 */
*hashFunctionAtomic = shaHashBufferAtomic;
if( hashOutputSize != NULL )
*hashOutputSize = SHA_DIGEST_LENGTH;
retIntError_Void();
}
*hashFunctionAtomic = hashFunctions[ i ].function;
if( hashOutputSize != NULL )
*hashOutputSize = hashFunctions[ i ].hashSize;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -