📄 mech_drv.c
字号:
REQUIRES_V( outLen > 0 && outLen < MAX_INTLENGTH_SHORT );
REQUIRES_V( inLen > 0 && inLen < MAX_INTLENGTH_SHORT );
/* Clear return value */
memset( outPtr, 0, min( 16, outLen ) );
for( remainder = outLen, iterationCount = 0;
remainder > 0 && iterationCount < FAILSAFE_ITERATIONS_SMALL;
iterationCount++ )
{
const int bytesToCopy = min( inLen, remainder );
memcpy( outPtr, inPtr, bytesToCopy );
outPtr += bytesToCopy;
remainder -= bytesToCopy;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_SMALL );
}
/* Perform PKCS #12 derivation. This code is disabled by default with
warnings against enabling it, it's only present here for completeness.
Note that it needs more evaluation as to its safety before it's ever
enabled and used, the PKCS #12 derivation operations are extremely
awkward and complex to audit */
#define P12_BLOCKSIZE 64
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int derivePKCS12( STDC_UNUSED void *dummy,
INOUT MECHANISM_DERIVE_INFO *mechanismInfo )
{
HASHFUNCTION_ATOMIC hashFunctionAtomic;
BYTE p12_DSP[ P12_BLOCKSIZE + P12_BLOCKSIZE + \
( ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ) + 8 ];
BYTE p12_Ai[ P12_BLOCKSIZE + 8 ], p12_B[ P12_BLOCKSIZE + 8 ];
BYTE *bmpPtr = p12_DSP + P12_BLOCKSIZE + P12_BLOCKSIZE;
BYTE *dataOutPtr = mechanismInfo->dataOut;
const BYTE *dataInPtr = mechanismInfo->dataIn;
const BYTE *saltPtr = mechanismInfo->salt;
const int bmpLen = ( mechanismInfo->dataInLength * 2 ) + 2;
const int p12_PLen = ( mechanismInfo->dataInLength <= 30 ) ? \
P12_BLOCKSIZE : \
( mechanismInfo->dataInLength <= 62 ) ? \
( P12_BLOCKSIZE * 2 ) : ( P12_BLOCKSIZE * 3 );
int hashSize, keyIndex, i, iterationCount, status;
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_DERIVE_INFO ) ) );
/* Clear return value */
memset( mechanismInfo->dataOut, 0, mechanismInfo->dataOutLength );
getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, &hashSize );
/* Set up the diversifier in the first P12_BLOCKSIZE bytes, the salt in
the next P12_BLOCKSIZE bytes, and the password as a Unicode null-
terminated string in the final bytes */
for( i = 0; i < P12_BLOCKSIZE; i++ )
p12_DSP[ i ] = saltPtr[ 0 ];
status = expandData( p12_DSP + P12_BLOCKSIZE, P12_BLOCKSIZE,
saltPtr + 1, mechanismInfo->saltLength - 1 );
if( cryptStatusError( status ) )
return( status );
for( i = 0; i < mechanismInfo->dataInLength && \
i < CRYPT_MAX_TEXTSIZE; i++ )
{
*bmpPtr++ = '\0';
*bmpPtr++ = dataInPtr[ i ];
}
ENSURES( i < CRYPT_MAX_TEXTSIZE );
*bmpPtr++ = '\0';
*bmpPtr++ = '\0';
status = expandData( p12_DSP + ( P12_BLOCKSIZE * 2 ) + bmpLen,
p12_PLen - bmpLen, p12_DSP + ( P12_BLOCKSIZE * 2 ),
bmpLen );
if( cryptStatusError( status ) )
return( status );
/* Produce enough blocks of output to fill the key */
for( keyIndex = 0, iterationCount = 0;
keyIndex < mechanismInfo->dataOutLength && \
iterationCount < FAILSAFE_ITERATIONS_MED;
keyIndex += hashSize, dataOutPtr += hashSize, iterationCount++ )
{
const int noKeyBytes = \
( mechanismInfo->dataOutLength - keyIndex > hashSize ) ? \
hashSize : mechanismInfo->dataOutLength - keyIndex;
BYTE *p12_DSPj;
/* Hash the keying material the required number of times to obtain the
output value */
hashFunctionAtomic( p12_Ai, P12_BLOCKSIZE, p12_DSP,
P12_BLOCKSIZE + P12_BLOCKSIZE + p12_PLen );
for( i = 1; i < mechanismInfo->iterations && \
i < FAILSAFE_ITERATIONS_MAX; i++ )
hashFunctionAtomic( p12_Ai, P12_BLOCKSIZE, p12_Ai, hashSize );
ENSURES( i < FAILSAFE_ITERATIONS_MAX );
memcpy( dataOutPtr, p12_Ai, noKeyBytes );
if( noKeyBytes <= hashSize)
break;
/* Update the input keying material for the next iteration */
status = expandData( p12_B, P12_BLOCKSIZE, p12_Ai, hashSize );
if( cryptStatusError( status ) )
return( status );
for( p12_DSPj = p12_DSP + P12_BLOCKSIZE;
p12_DSPj < p12_DSP + ( 2 * P12_BLOCKSIZE ) + p12_PLen;
p12_DSPj += P12_BLOCKSIZE )
{
int dspIndex = P12_BLOCKSIZE - 1, bIndex = P12_BLOCKSIZE - 1;
int carry = 1;
/* Ij = (Ij + B + 1) mod 2^BLOCKSIZE */
for( dspIndex = P12_BLOCKSIZE - 1, bIndex = P12_BLOCKSIZE - 1;
dspIndex >= 0; dspIndex--, bIndex-- )
{
const int value = p12_DSPj[ dspIndex ] + p12_B[ bIndex ] + carry;
p12_DSPj[ dspIndex ] = value & 0xFF;
carry = value >> 8;
}
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
zeroise( p12_DSP, P12_BLOCKSIZE + P12_BLOCKSIZE + \
( ( CRYPT_MAX_TEXTSIZE + 1 ) * 2 ) );
zeroise( p12_Ai, P12_BLOCKSIZE );
zeroise( p12_B, P12_BLOCKSIZE );
return( CRYPT_OK );
}
#endif /* USE_PKCS12 */
#ifdef USE_SSL
/****************************************************************************
* *
* SSL/TLS Key Derivation *
* *
****************************************************************************/
/* Structure used to store TLS PRF state information */
typedef struct {
/* The hash functions and hash info */
HASHFUNCTION_ATOMIC hashFunctionAtomic;
HASHFUNCTION hashFunction;
int hashSize;
/* The initial hash state from prfInit() and the current hash state */
HASHINFO initialHashInfo, hashInfo;
/* The HMAC processed key and intermediate data value */
BUFFER( HMAC_DATASIZE, processedKeyLength ) \
BYTE processedKey[ HMAC_DATASIZE + 8 ];
BUFFER( HMAC_DATASIZE, hashSize ) \
BYTE hashA[ CRYPT_MAX_HASHSIZE + 8 ];
int processedKeyLength;
} TLS_PRF_INFO;
/* Perform SSL key derivation */
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int deriveSSL( STDC_UNUSED void *dummy,
INOUT MECHANISM_DERIVE_INFO *mechanismInfo )
{
HASHFUNCTION md5HashFunction, shaHashFunction;
HASHINFO hashInfo;
BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ], counterData[ 16 + 8 ];
BYTE *dataOutPtr = mechanismInfo->dataOut;
int md5HashSize, shaHashSize, counter = 0, keyIndex, iterationCount;
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_DERIVE_INFO ) ) );
/* Clear return value */
memset( mechanismInfo->dataOut, 0, mechanismInfo->dataOutLength );
getHashParameters( CRYPT_ALGO_MD5, &md5HashFunction, &md5HashSize );
getHashParameters( CRYPT_ALGO_SHA1, &shaHashFunction, &shaHashSize );
/* Produce enough blocks of output to fill the key */
for( keyIndex = 0, iterationCount = 0;
keyIndex < mechanismInfo->dataOutLength && \
iterationCount < FAILSAFE_ITERATIONS_MED;
keyIndex += md5HashSize, iterationCount++ )
{
const int noKeyBytes = \
( mechanismInfo->dataOutLength - keyIndex > md5HashSize ) ? \
md5HashSize : mechanismInfo->dataOutLength - keyIndex;
int i;
/* Set up the counter data */
for( i = 0; i <= counter && i < 16; i++ )
counterData[ i ] = 'A' + counter;
ENSURES( i < 16 );
counter++;
/* Calculate SHA1( 'A'/'BB'/'CCC'/... || keyData || salt ) */
shaHashFunction( hashInfo, NULL, 0, counterData, counter,
HASH_STATE_START );
shaHashFunction( hashInfo, NULL, 0, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_STATE_CONTINUE );
shaHashFunction( hashInfo, hash, CRYPT_MAX_HASHSIZE,
mechanismInfo->salt, mechanismInfo->saltLength,
HASH_STATE_END );
/* Calculate MD5( keyData || SHA1-hash ) */
md5HashFunction( hashInfo, NULL, 0, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_STATE_START );
md5HashFunction( hashInfo, hash, CRYPT_MAX_HASHSIZE,
hash, shaHashSize, HASH_STATE_END );
/* Copy the result to the output */
memcpy( dataOutPtr + keyIndex, hash, noKeyBytes );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
zeroise( hashInfo, sizeof( HASHINFO ) );
zeroise( hash, CRYPT_MAX_HASHSIZE );
return( CRYPT_OK );
}
/* Initialise the TLS PRF */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int tlsPrfInit( INOUT TLS_PRF_INFO *prfInfo,
IN_BUFFER( keyLength ) const void *key,
IN_LENGTH_SHORT const int keyLength,
IN_BUFFER( saltLength ) const void *salt,
IN_LENGTH_SHORT const int saltLength )
{
int status;
assert( isWritePtr( prfInfo, sizeof( TLS_PRF_INFO ) ) );
assert( isReadPtr( key, keyLength ) );
assert( isReadPtr( salt, saltLength ) );
REQUIRES( keyLength > 0 && keyLength < MAX_INTLENGTH_SHORT );
REQUIRES( saltLength > 0 && saltLength < MAX_INTLENGTH_SHORT );
/* Initialise the hash information with the keying info. This is
reused for any future hashing since it's constant */
status = prfInit( prfInfo->hashFunction, prfInfo->hashFunctionAtomic,
prfInfo->initialHashInfo, prfInfo->hashSize,
prfInfo->processedKey, HMAC_DATASIZE,
&prfInfo->processedKeyLength, key, keyLength );
if( cryptStatusError( status ) )
return( status );
/* Calculate A1 = HMAC( salt ) */
memcpy( prfInfo->hashInfo, prfInfo->initialHashInfo, sizeof( HASHINFO ) );
prfInfo->hashFunction( prfInfo->hashInfo, NULL, 0, salt, saltLength,
HASH_STATE_CONTINUE );
return( prfEnd( prfInfo->hashFunction, prfInfo->hashInfo,
prfInfo->hashSize, prfInfo->hashA,
CRYPT_MAX_HASHSIZE, prfInfo->processedKey,
prfInfo->processedKeyLength ) );
}
/* Implement one round of the TLS PRF */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
static int tlsPrfHash( OUT_BUFFER_FIXED( outLength ) BYTE *out,
IN_LENGTH_SHORT const int outLength,
INOUT TLS_PRF_INFO *prfInfo,
IN_BUFFER( saltLength ) const void *salt,
IN_LENGTH_SHORT const int saltLength )
{
HASHINFO hashInfo, AnHashInfo;
BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
int i, status;
assert( isWritePtr( out, outLength ) );
assert( isWritePtr( prfInfo, sizeof( TLS_PRF_INFO ) ) );
assert( isReadPtr( salt, saltLength ) );
REQUIRES( outLength > 0 && outLength <= prfInfo->hashSize && \
outLength <= CRYPT_MAX_HASHSIZE );
REQUIRES( saltLength >= 13 && saltLength <= 512 );
/* The result of the hashing is XORd to the output so we don't clear the
return value like usual */
/* Calculate HMAC( An || salt ) */
memcpy( hashInfo, prfInfo->initialHashInfo, sizeof( HASHINFO ) );
prfInfo->hashFunction( hashInfo, NULL, 0, prfInfo->hashA,
prfInfo->hashSize, HASH_STATE_CONTINUE );
memcpy( AnHashInfo, hashInfo, sizeof( HASHINFO ) );
prfInfo->hashFunction( hashInfo, NULL, 0, salt, saltLength,
HASH_STATE_CONTINUE );
status = prfEnd( prfInfo->hashFunction, hashInfo, prfInfo->hashSize,
hash, CRYPT_MAX_HASHSIZE, prfInfo->processedKey,
prfInfo->processedKeyLength );
if( cryptStatusError( status ) )
{
zeroise( AnHashInfo, sizeof( HASHINFO ) );
zeroise( hashInfo, sizeof( HASHINFO ) );
zeroise( hash, CRYPT_MAX_HASHSIZE );
return( status );
}
/* Calculate An+1 = HMAC( An ) */
memcpy( hashInfo, AnHashInfo, sizeof( HASHINFO ) );
status = prfEnd( prfInfo->hashFunction, hashInfo, prfInfo->hashSize,
prfInfo->hashA, prfInfo->hashSize,
prfInfo->processedKey, prfInfo->processedKeyLength );
if( cryptStatusError( status ) )
{
zeroise( AnHashInfo, sizeof( HASHINFO ) );
zeroise( hashInfo, sizeof( HASHINFO ) );
zeroise( hash, CRYPT_MAX_HASHSIZE );
return( status );
}
/* Copy the result to the output */
for( i = 0; i < outLength; i++ )
out[ i ] ^= hash[ i ];
zeroise( AnHashInfo, sizeof( HASHINFO ) );
zeroise( hashInfo, sizeof( HASHINFO ) );
zeroise( hash, CRYPT_MAX_HASHSIZE );
return( CRYPT_OK );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -