📄 cryptmch.c
字号:
UNUSED( dummy );
getHashParameters( CRYPT_ALGO_MD5, &md5HashFunction, &md5HashSize );
getHashParameters( CRYPT_ALGO_SHA, &shaHashFunction, &shaHashSize );
/* Find the start of the two halves of the keying info used for the
HMAC'ing. 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 which 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 MD5 and SHA-1 information with the keying info. These
are reused for any future hashing since they're constant */
prfInit( md5HashFunction, md5InitialHashInfo, md5HashSize,
md5ProcessedKey, &md5ProcessedKeyLength, s1, sLen );
prfInit( shaHashFunction, shaInitialHashInfo, shaHashSize,
shaProcessedKey, &shaProcessedKeyLength, s2, sLen );
/* Calculate A1 = HMAC( salt ) */
memcpy( md5HashInfo, md5InitialHashInfo, MAX_HASHINFO_SIZE );
md5HashFunction( md5HashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_CONTINUE );
prfEnd( md5HashFunction, md5HashInfo, md5HashSize, md5A,
md5ProcessedKey, md5ProcessedKeyLength );
memcpy( shaHashInfo, shaInitialHashInfo, MAX_HASHINFO_SIZE );
shaHashFunction( shaHashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_CONTINUE );
prfEnd( shaHashFunction, shaHashInfo, shaHashSize, shaA,
shaProcessedKey, shaProcessedKeyLength );
/* 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( keyIndex = 0; keyIndex < mechanismInfo->dataOutLength;
keyIndex += md5HashSize )
{
const int md5NoKeyBytes = \
min( ( dataEndPtr - md5DataOutPtr ), md5HashSize );
const int shaNoKeyBytes = \
min( ( dataEndPtr - shaDataOutPtr ), shaHashSize );
int i; /* Spurious ()'s needed for broken compilers */
/* Calculate HMAC( An || salt ) */
memcpy( md5HashInfo, md5InitialHashInfo, MAX_HASHINFO_SIZE );
md5HashFunction( md5HashInfo, NULL, md5A, md5HashSize, HASH_CONTINUE );
memcpy( md5AnHashInfo, md5HashInfo, MAX_HASHINFO_SIZE );
md5HashFunction( md5HashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_CONTINUE );
prfEnd( md5HashFunction, md5HashInfo, md5HashSize, md5Hash,
md5ProcessedKey, md5ProcessedKeyLength );
memcpy( shaHashInfo, shaInitialHashInfo, MAX_HASHINFO_SIZE );
shaHashFunction( shaHashInfo, NULL, shaA, shaHashSize, HASH_CONTINUE );
memcpy( shaAnHashInfo, shaHashInfo, MAX_HASHINFO_SIZE );
shaHashFunction( shaHashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_CONTINUE );
prfEnd( shaHashFunction, shaHashInfo, shaHashSize, shaHash,
shaProcessedKey, shaProcessedKeyLength );
/* Calculate An+1 = HMAC( An ) */
memcpy( md5HashInfo, md5AnHashInfo, MAX_HASHINFO_SIZE );
prfEnd( md5HashFunction, md5HashInfo, md5HashSize, md5A,
md5ProcessedKey, md5ProcessedKeyLength );
memcpy( shaHashInfo, shaAnHashInfo, MAX_HASHINFO_SIZE );
prfEnd( shaHashFunction, shaHashInfo, shaHashSize, shaA,
shaProcessedKey, shaProcessedKeyLength );
/* Copy the result to the output */
for( i = 0; i < md5NoKeyBytes; i++ )
md5DataOutPtr[ i ] ^= md5Hash[ i ];
for( i = 0; i < shaNoKeyBytes; i++ )
shaDataOutPtr[ i ] ^= shaHash[ i ];
md5DataOutPtr += md5NoKeyBytes;
shaDataOutPtr += shaNoKeyBytes;
}
zeroise( md5HashInfo, MAX_HASHINFO_SIZE );
zeroise( md5InitialHashInfo, MAX_HASHINFO_SIZE );
zeroise( md5AnHashInfo, MAX_HASHINFO_SIZE );
zeroise( shaHashInfo, MAX_HASHINFO_SIZE );
zeroise( shaInitialHashInfo, MAX_HASHINFO_SIZE );
zeroise( shaAnHashInfo, MAX_HASHINFO_SIZE );
zeroise( md5ProcessedKey, HMAC_DATASIZE );
zeroise( shaProcessedKey, HMAC_DATASIZE );
zeroise( md5A, CRYPT_MAX_HASHSIZE );
zeroise( shaA, CRYPT_MAX_HASHSIZE );
return( CRYPT_OK );
}
/* Perform CMP/Entrust key derivation */
int deriveCMP( void *dummy, MECHANISM_DERIVE_INFO *mechanismInfo )
{
HASHFUNCTION hashFunction;
BYTE hashInfo[ MAX_HASHINFO_SIZE ];
int hashSize, iterations = mechanismInfo->iterations - 1;
UNUSED( dummy );
/* Calculate SHA1( password || salt ) */
getHashParameters( mechanismInfo->hashAlgo, &hashFunction, &hashSize );
hashFunction( hashInfo, NULL, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_START );
hashFunction( hashInfo, mechanismInfo->dataOut, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_END );
/* Iterate the hashing the remaining number of times */
while( iterations-- )
hashFunction( NULL, mechanismInfo->dataOut, mechanismInfo->dataOut,
hashSize, HASH_ALL );
zeroise( hashInfo, MAX_HASHINFO_SIZE );
return( CRYPT_OK );
}
/* Perform OpenPGP S2K key derivation */
int derivePGP( void *dummy, MECHANISM_DERIVE_INFO *mechanismInfo )
{
HASHFUNCTION hashFunction;
BYTE hashInfo[ MAX_HASHINFO_SIZE ], hashedKey[ CRYPT_MAX_KEYSIZE ];
long byteCount = ( long ) mechanismInfo->iterations << 6;
long secondByteCount = 0;
int hashSize;
getHashParameters( mechanismInfo->hashAlgo, &hashFunction, &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 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, run a
second round of hashing after the first one to provide the required
amount of keying material */
if( hashSize < mechanismInfo->dataOutLength )
secondByteCount = byteCount;
/* Repeatedly hash the salt and password until we've met the byte count */
hashFunction( hashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_START );
byteCount -= mechanismInfo->saltLength;
do
{
if( byteCount <= mechanismInfo->dataInLength )
hashFunction( hashInfo, hashedKey, mechanismInfo->dataIn,
byteCount, HASH_END );
else
hashFunction( hashInfo, NULL, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_CONTINUE );
byteCount -= mechanismInfo->dataInLength;
if( byteCount <= 0 )
continue;
if( byteCount <= mechanismInfo->saltLength )
hashFunction( hashInfo, hashedKey, mechanismInfo->salt,
byteCount, HASH_END );
else
hashFunction( hashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_CONTINUE );
byteCount -= mechanismInfo->saltLength;
}
while( byteCount > 0 );
if( secondByteCount )
{
/* Perform a second round of hashing, preloading the hash with a
single zero byte */
hashFunction( hashInfo, NULL, ( const BYTE * ) "\x00", 1,
HASH_START );
while( secondByteCount )
{
if( secondByteCount <= mechanismInfo->saltLength )
hashFunction( hashInfo, hashedKey + hashSize,
mechanismInfo->salt, secondByteCount,
HASH_END );
else
hashFunction( hashInfo, NULL, mechanismInfo->salt,
mechanismInfo->saltLength, HASH_CONTINUE );
secondByteCount -= mechanismInfo->saltLength;
if( secondByteCount <= 0 )
continue;
if( secondByteCount <= mechanismInfo->dataInLength )
hashFunction( hashInfo, hashedKey + hashSize,
mechanismInfo->dataIn, secondByteCount,
HASH_END );
else
hashFunction( hashInfo, NULL, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_CONTINUE );
secondByteCount -= mechanismInfo->dataInLength;
}
}
memcpy( mechanismInfo->dataOut, hashedKey, mechanismInfo->dataOutLength );
zeroise( hashInfo, MAX_HASHINFO_SIZE );
zeroise( hashedKey, CRYPT_MAX_KEYSIZE );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Signature Mechanisms *
* *
****************************************************************************/
/* Perform PKCS #1 signing/sig.checking */
int signPKCS1( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
CRYPT_ALGO hashAlgo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE hash[ CRYPT_MAX_HASHSIZE ];
int payloadSize, hashSize, length, i, status;
UNUSED( dummy );
/* Sanity check the input data */
assert( ( mechanismInfo->signature == NULL && \
mechanismInfo->signatureLength == 0 ) || \
( mechanismInfo->signatureLength >= 64 ) );
/* Clear the return value */
if( mechanismInfo->signature != NULL )
memset( mechanismInfo->signature, 0,
mechanismInfo->signatureLength );
/* Get various algorithm parameters */
status = krnlSendMessage( mechanismInfo->hashContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->signContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &length,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
/* If this is just a length check, we're done */
if( mechanismInfo->signature == NULL )
{
mechanismInfo->signatureLength = length;
return( CRYPT_OK );
}
/* Get the hash data and determine the encoded payload size */
setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( mechanismInfo->hashContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
hashSize = msgData.length;
if( cryptStatusError( status ) )
return( status );
payloadSize = sizeofMessageDigest( hashAlgo, hashSize );
/* Encode the payload using the format given in PKCS #1, which for
signed data is [ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ] */
sMemOpen( &stream, mechanismInfo->signature,
mechanismInfo->signatureLength );
sputc( &stream, 0 );
sputc( &stream, 1 );
for( i = 0; i < length - ( payloadSize + 3 ); i++ )
sputc( &stream, 0xFF );
sputc( &stream, 0 );
writeMessageDigest( &stream, hashAlgo, hash, hashSize );
sMemDisconnect( &stream );
/* Sign the data */
status = krnlSendMessage( mechanismInfo->signContext,
RESOURCE_IMESSAGE_CTX_SIGN,
mechanismInfo->signature, length );
if( cryptStatusError( status ) )
return( status );
mechanismInfo->signatureLength = length;
return( CRYPT_OK );
}
int sigcheckPKCS1( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
CRYPT_ALGO hashAlgo, recoveredHashAlgo;
STREAM stream;
BYTE decryptedSignature[ CRYPT_MAX_PKCSIZE ];
BYTE hash[ CRYPT_MAX_HASHSIZE ], recoveredHash[ CRYPT_MAX_HASHSIZE ];
int length, hashSize, recoveredHashSize, status;
UNUSED( dummy );
/* Sanity check the input data */
assert( mechanismInfo->signatureLength >= 60 );
/* Get various algorithm parameters */
status = krnlSendMessage( mechanismInfo->hashContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( mechanismInfo->hashContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
hashSize = msgData.length;
}
if( cryptStatusError( status ) )
return( status );
/* Format the input data as required for the sig check to work */
status = krnlSendMessage( mechanismInfo->signContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &length,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusOK( status ) )
status = adjustPKCS1Data( decryptedSignature,
mechanismInfo->signature, mechanismInfo->signatureLength,
length );
if( cryptStatusError( status ) )
return( status );
/* Recover the signed data */
status = krnlSendMessage( mechanismInfo->signContext,
RESOURCE_IMESSAGE_CTX_SIGCHECK,
decryptedSignature, length );
if( cryptStatusError( status ) )
return( status );
/* Undo the PKCS #1 padding, which for signed data is
[ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ]. Note that some
implementations may have bignum code which zero-truncates the result
which produces a CRYPT_ERROR_BADDATA error, it's the responsibility
of the lower-level crypto layer to reformat the data to return a
correctly-formatted result if necessary */
sMemConnect( &stream, decryptedSignature, length );
if( sgetc( &stream ) || sgetc( &stream ) != 1 )
status = CRYPT_ERROR_BADDATA;
else
{
int ch, i;
for( i = 0; i < length - 3; i++ )
if( ( ch = sgetc( &stream ) ) != 0xFF )
break;
if( ch != 0 || \
cryptStatusError( \
readMessageDigest( &stream, &recoveredHashAlgo,
recoveredHash, &recoveredHashSize ) ) )
status = CRYPT_ERROR_BADDATA;
}
sMemClose( &stream );
if( cryptStatusError( status ) )
return( status );
/* Finally, make sure the two hash values match */
if( hashAlgo != recoveredHashAlgo || hashSize != recoveredHashSize || \
memcmp( hash, recoveredHash, recoveredHashSize ) )
status = CRYPT_ERROR_SIGNATURE;
/* Clean up */
zeroise( hash, hashSize );
zeroise( recoveredHash, recoveredHashSize );
return( status );
}
/****************************************************************************
* *
* Key Wrap/Unwrap Mechanisms *
* *
****************************************************************************/
/* Perform PKCS #1 wrapping/unwrapping. There are several variations of
this which are handled through common PKCS #1 mechanism functions */
typedef enum { PKCS1_WRAP_NORMAL, PKCS1_WRAP_RAW, PKCS1_WRAP_PGP } PKCS1_WRAP_TYPE;
static int pkcs1Wrap( MECHANISM_WRAP_INFO *mechanismInfo,
const PKCS1_WRAP_TYPE type )
{
STATIC_FN int extractKeyData( const CRYPT_CONTEXT iCryptContext,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -