📄 mech_drv.c
字号:
}
/* Perform TLS key derivation. This implements the function described as
'PRF()' in the TLS spec */
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int deriveTLS( STDC_UNUSED void *dummy,
INOUT MECHANISM_DERIVE_INFO *mechanismInfo )
{
TLS_PRF_INFO md5Info, shaInfo;
BYTE *dataOutPtr = mechanismInfo->dataOut;
const void *s1, *s2;
const int dataOutLength = mechanismInfo->dataOutLength;
const int sLen = ( mechanismInfo->dataInLength + 1 ) / 2;
int md5Index, shaIndex, iterationCount, status;
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_DERIVE_INFO ) ) );
/* Clear return value */
memset( mechanismInfo->dataOut, 0, mechanismInfo->dataOutLength );
memset( &md5Info, 0, sizeof( TLS_PRF_INFO ) );
getHashAtomicParameters( CRYPT_ALGO_MD5, &md5Info.hashFunctionAtomic,
&md5Info.hashSize );
getHashParameters( CRYPT_ALGO_MD5, &md5Info.hashFunction, NULL );
memset( &shaInfo, 0, sizeof( TLS_PRF_INFO ) );
getHashAtomicParameters( CRYPT_ALGO_SHA1, &shaInfo.hashFunctionAtomic,
&shaInfo.hashSize );
getHashParameters( CRYPT_ALGO_SHA1, &shaInfo.hashFunction, NULL );
/* Find the start of the two halves of the keying info used for the
HMACing. The size of each half is given by ceil( dataInLength / 2 )
so there's a one-byte overlap if the input is an odd number of bytes
long */
s1 = mechanismInfo->dataIn;
s2 = ( BYTE * ) mechanismInfo->dataIn + \
( mechanismInfo->dataInLength - sLen );
/* The two hash functions have different block sizes that would require
complex buffering to handle leftover bytes from SHA-1, a simpler
method is to zero the output data block and XOR in the values from
each hash mechanism using separate output location indices for MD5 and
SHA-1 */
memset( mechanismInfo->dataOut, 0, mechanismInfo->dataOutLength );
/* Initialise the TLS PRF and calculate A1 = HMAC( salt ) */
status = tlsPrfInit( &md5Info, s1, sLen, mechanismInfo->salt,
mechanismInfo->saltLength );
if( cryptStatusOK( status ) )
status = tlsPrfInit( &shaInfo, s2, sLen, mechanismInfo->salt,
mechanismInfo->saltLength );
if( cryptStatusError( status ) )
{
zeroise( &md5Info, sizeof( TLS_PRF_INFO ) );
zeroise( &shaInfo, sizeof( TLS_PRF_INFO ) );
return( status );
}
/* Produce enough blocks of output to fill the key. We use the MD5 hash
size as the loop increment since this produces the smaller output
block */
for( md5Index = shaIndex = 0, iterationCount = 0;
md5Index < dataOutLength && iterationCount < FAILSAFE_ITERATIONS_MED;
iterationCount++ )
{
const int md5NoKeyBytes = min( dataOutLength - md5Index, \
md5Info.hashSize );
const int shaNoKeyBytes = min( dataOutLength - shaIndex, \
shaInfo.hashSize );
status = tlsPrfHash( dataOutPtr + md5Index, md5NoKeyBytes,
&md5Info, mechanismInfo->salt,
mechanismInfo->saltLength );
if( cryptStatusError( status ) )
break;
if( shaNoKeyBytes > 0 )
{
/* Since the SHA-1 counter advances faster than the MD5 one we
can end up with zero bytes left to process for SHA-1 when MD5
is processing it's last block */
status = tlsPrfHash( dataOutPtr + shaIndex, shaNoKeyBytes,
&shaInfo, mechanismInfo->salt,
mechanismInfo->saltLength );
if( cryptStatusError( status ) )
break;
}
md5Index += md5NoKeyBytes;
shaIndex += shaNoKeyBytes;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
zeroise( &md5Info, sizeof( TLS_PRF_INFO ) );
zeroise( &shaInfo, sizeof( TLS_PRF_INFO ) );
if( cryptStatusError( status ) )
{
zeroise( mechanismInfo->dataOut, mechanismInfo->dataOutLength );
return( status );
}
return( CRYPT_OK );
}
#endif /* USE_SSL */
/****************************************************************************
* *
* PGP Key Derivation *
* *
****************************************************************************/
#if defined( USE_PGP ) || defined( USE_PGPKEYS )
/* Implement one round of the TLS PRF */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 6, 8, 10 ) ) \
static int pgpPrfHash( OUT_BUFFER_FIXED( outLength ) BYTE *out,
IN_LENGTH_HASH const int outLength,
IN const HASHFUNCTION hashFunction,
INOUT TYPECAST( HASHINFO ) void *hashInfo,
IN_LENGTH_HASH const int hashSize,
IN_BUFFER( keyLength ) const void *key,
IN_LENGTH_SHORT_MIN( 2 ) const int keyLength,
IN_BUFFER( saltLength ) const void *salt,
IN_LENGTH_FIXED( PGP_SALTSIZE ) const int saltLength,
INOUT_LENGTH_Z long *byteCount,
IN_RANGE( CRYPT_UNUSED, 1 ) const int preloadLength )
{
long count = *byteCount;
assert( isWritePtr( out, outLength ) );
assert( isWritePtr( hashInfo, sizeof( HASHINFO ) ) );
assert( isReadPtr( key, keyLength ) );
assert( isReadPtr( salt, saltLength ) );
assert( isWritePtr( byteCount, sizeof( int ) ) );
REQUIRES( hashFunction != NULL );
REQUIRES( outLength == hashSize );
REQUIRES( hashSize >= 16 && hashSize <= CRYPT_MAX_HASHSIZE );
REQUIRES( keyLength >= 2 && keyLength <= MAX_INTLENGTH_SHORT );
REQUIRES( saltLength == PGP_SALTSIZE );
REQUIRES( preloadLength == CRYPT_UNUSED || \
( preloadLength >= 0 && preloadLength <= 1 ) );
REQUIRES( count > 0 && count < MAX_INTLENGTH );
/* Clear return value */
memset( out, 0, outLength );
/* If it's a subsequent round of hashing, preload the hash with zero
bytes. If it's the first round (preloadLength == 0) it's handled
specially below */
if( preloadLength > 0 )
{
hashFunction( hashInfo, NULL, 0, ( const BYTE * ) "\x00\x00\x00\x00",
preloadLength, HASH_STATE_START );
}
/* Hash the next round of salt || password. Since we're being asked to
stop once we've processed 'count' input bytes we implement an early-
out mechanism that exits if the length of the item being hashed is
sufficient to reach 'count' */
if( count <= saltLength )
{
hashFunction( hashInfo, out, outLength, salt, count,
HASH_STATE_END );
*byteCount = 0;
return( CRYPT_OK );
}
hashFunction( hashInfo, NULL, 0, salt, saltLength,
( preloadLength == 0 ) ? HASH_STATE_START : \
HASH_STATE_CONTINUE );
count -= saltLength;
if( count <= keyLength )
{
hashFunction( hashInfo, out, outLength, key, count, HASH_STATE_END );
*byteCount = 0;
return( CRYPT_OK );
}
hashFunction( hashInfo, NULL, 0, key, keyLength, HASH_STATE_CONTINUE );
count -= keyLength;
ENSURES( count > 0 && count < MAX_INTLENGTH );
*byteCount = count;
return( CRYPT_OK );
}
/* Perform OpenPGP S2K key derivation */
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int derivePGP( STDC_UNUSED void *dummy,
INOUT MECHANISM_DERIVE_INFO *mechanismInfo )
{
HASHFUNCTION hashFunction;
HASHINFO hashInfo;
long byteCount = ( long ) mechanismInfo->iterations << 6;
long secondByteCount = 0;
int hashSize, i, iterationCount, status = CRYPT_OK;
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_DERIVE_INFO ) ) );
REQUIRES( mechanismInfo->iterations >= 0 && \
mechanismInfo->iterations < MAX_INTLENGTH >> 6 );
REQUIRES( byteCount >= 0 && byteCount < MAX_INTLENGTH );
/* Clear return value */
memset( mechanismInfo->dataOut, 0, mechanismInfo->dataOutLength );
getHashParameters( mechanismInfo->hashAlgo, &hashFunction, &hashSize );
REQUIRES( mechanismInfo->dataOutLength < 2 * hashSize );
/* If it's a non-iterated hash or the count won't allow even a single
pass over the 8-byte salt and password, adjust it to make sure that
we run at least one full iteration */
if( byteCount < PGP_SALTSIZE + mechanismInfo->dataInLength )
byteCount = PGP_SALTSIZE + mechanismInfo->dataInLength;
/* If the hash output size is less than the required key size we run a
second round of hashing after the first one to provide the total
required amount of keying material */
if( hashSize < mechanismInfo->dataOutLength )
secondByteCount = byteCount;
/* Repeatedly hash the salt and password until we've met the byte count.
In effect this hashes:
salt || password || salt || password || ...
until we've processed 'byteCount' bytes of data */
for( i = 0, iterationCount = 0;
byteCount > 0 && cryptStatusOK( status ) && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
i++, iterationCount++ )
{
status = pgpPrfHash( mechanismInfo->dataOut,
hashSize, hashFunction, hashInfo, hashSize,
mechanismInfo->dataIn,
mechanismInfo->dataInLength,
mechanismInfo->salt,
mechanismInfo->saltLength, &byteCount,
( i <= 0 ) ? 0 : CRYPT_UNUSED );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
if( cryptStatusOK( status ) && secondByteCount > 0 )
{
for( i = 0, iterationCount = 0;
secondByteCount > 0 && cryptStatusOK( status ) && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
i++, iterationCount++ )
{
status = pgpPrfHash( ( BYTE * ) mechanismInfo->dataOut + hashSize,
hashSize, hashFunction, hashInfo, hashSize,
mechanismInfo->dataIn,
mechanismInfo->dataInLength,
mechanismInfo->salt,
mechanismInfo->saltLength, &secondByteCount,
( i <= 0 ) ? 1 : CRYPT_UNUSED );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
}
zeroise( hashInfo, sizeof( HASHINFO ) );
if( cryptStatusError( status ) )
{
zeroise( mechanismInfo->dataOut, mechanismInfo->dataOutLength );
return( status );
}
return( CRYPT_OK );
}
#endif /* USE_PGP || USE_PGPKEYS */
/****************************************************************************
* *
* Misc Key Derivation *
* *
****************************************************************************/
#ifdef USE_CMP
/* Perform CMP/Entrust key derivation */
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int deriveCMP( STDC_UNUSED void *dummy,
INOUT MECHANISM_DERIVE_INFO *mechanismInfo )
{
HASHFUNCTION_ATOMIC hashFunctionAtomic;
HASHFUNCTION hashFunction;
HASHINFO hashInfo;
int hashSize, iterations;
UNUSED_ARG( dummy );
assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_DERIVE_INFO ) ) );
/* Clear return value */
memset( mechanismInfo->dataOut, 0, mechanismInfo->dataOutLength );
/* Calculate SHA1( password || salt ) */
getHashAtomicParameters( mechanismInfo->hashAlgo, &hashFunctionAtomic,
&hashSize );
getHashParameters( mechanismInfo->hashAlgo, &hashFunction, NULL );
hashFunction( hashInfo, NULL, 0, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_STATE_START );
hashFunction( hashInfo, mechanismInfo->dataOut,
mechanismInfo->dataOutLength, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_STATE_END );
/* Iterate the hashing the remaining number of times. We start the
count at one since the first iteration has already been performed */
for( iterations = 1; iterations < mechanismInfo->iterations && \
iterations < FAILSAFE_ITERATIONS_MAX; iterations++ )
{
hashFunctionAtomic( mechanismInfo->dataOut,
mechanismInfo->dataOutLength,
mechanismInfo->dataOut, hashSize );
}
ENSURES( iterations < FAILSAFE_ITERATIONS_MAX );
zeroise( hashInfo, sizeof( HASHINFO ) );
return( CRYPT_OK );
}
#endif /* USE_CMP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -