📄 cryptmch.c
字号:
HASH_END );
else
hashFunction( hashInfo, NULL, mechanismInfo->dataIn,
mechanismInfo->dataInLength, HASH_CONTINUE );
secondByteCount -= mechanismInfo->dataInLength;
}
}
memcpy( mechanismInfo->dataOut, hashedKey, mechanismInfo->dataOutLength );
zeroise( hashInfo, sizeof( HASHINFO ) );
zeroise( hashedKey, CRYPT_MAX_KEYSIZE );
return( CRYPT_OK );
}
#endif /* USE_PGP || USE_PGPKEYS */
/****************************************************************************
* *
* Signature Mechanisms *
* *
****************************************************************************/
/* Perform PKCS #1 signing/sig.checking */
int signPKCS1( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
CRYPT_ALGO_TYPE hashAlgo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE hash[ CRYPT_MAX_HASHSIZE ], preSigData[ CRYPT_MAX_PKCSIZE ];
BOOLEAN useSideChannelProtection;
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 and config parameters */
status = krnlSendMessage( mechanismInfo->hashContext,
IMESSAGE_GETATTRIBUTE, &hashAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_GETATTRIBUTE, &length,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_GETATTRIBUTE,
&useSideChannelProtection,
CRYPT_OPTION_MISC_SIDECHANNELPROTECTION );
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 */
setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( mechanismInfo->hashContext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusError( status ) )
return( status );
hashSize = msgData.length;
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, length );
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 );
if( useSideChannelProtection )
/* Remember a copy of the signature data for later so we can check it
against the recovered signature data */
memcpy( preSigData, mechanismInfo->signature, length );
/* Sign the data */
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_CTX_SIGN, mechanismInfo->signature,
length );
if( cryptStatusError( status ) )
return( status );
mechanismInfo->signatureLength = length;
/* If we're using side-channel protection, check that the signature
verifies */
if( useSideChannelProtection )
{
BYTE recoveredSignature[ CRYPT_MAX_PKCSIZE ];
/* Make sure that the recovered signature data matches what we
signed, unless we're in the unlikely situation that the key
isn't valid for sig.checking. The rationale behind this
operation is covered (in great detail) in lib_rsa.c */
memcpy( recoveredSignature, mechanismInfo->signature, length );
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_CTX_SIGCHECK, recoveredSignature,
length );
if( status != CRYPT_ERROR_PERMISSION && \
status != CRYPT_ERROR_NOTAVAIL && \
memcmp( preSigData, recoveredSignature, length ) )
{
assert( NOTREACHED );
zeroise( mechanismInfo->signature, length );
mechanismInfo->signatureLength = 0;
return( CRYPT_ERROR_FAILED );
}
zeroise( recoveredSignature, length );
zeroise( preSigData, length );
}
return( CRYPT_OK );
}
int sigcheckPKCS1( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
CRYPT_ALGO_TYPE 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,
IMESSAGE_GETATTRIBUTE, &hashAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( mechanismInfo->hashContext,
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,
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,
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 that 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 = 1, 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;
}
sMemDisconnect( &stream );
zeroise( decryptedSignature, CRYPT_MAX_PKCSIZE );
if( cryptStatusError( status ) )
return( status );
/* Finally, make sure that 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 that 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 )
{
int extractKeyData( const CRYPT_CONTEXT iCryptContext, void *keyData );
CRYPT_ALGO_TYPE cryptAlgo;
RESOURCE_DATA msgData;
BYTE *wrappedData = mechanismInfo->wrappedData, *dataPtr;
int payloadSize, length, padSize, status;
#ifdef USE_PGP
int pgpAlgoID;
#endif /* USE_PGP */
assert( type == PKCS1_WRAP_NORMAL || type == PKCS1_WRAP_RAW || \
type == PKCS1_WRAP_PGP );
/* Clear the return value */
if( mechanismInfo->wrappedData != NULL )
memset( mechanismInfo->wrappedData, 0,
mechanismInfo->wrappedDataLength );
/* Get various algorithm parameters */
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_GETATTRIBUTE, &length,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
/* If this is just a length check, we're done */
if( mechanismInfo->wrappedData == NULL )
{
/* Determine how long the encrypted value will be. In the case of
Elgamal it's just an estimate since it can change by up to two
bytes depending on whether the values have the high bit set or
not, which requires zero-padding of the ASN.1-encoded integers.
This is rather nasty because it means we can't tell how large an
encrypted value will be without actually creating it. The 10-byte
length at the start is for the ASN.1 SEQUENCE (4) and 2 *
INTEGER (2*3) encoding */
mechanismInfo->wrappedDataLength = ( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? \
10 + ( 2 * ( length + 1 ) ) : length;
return( CRYPT_OK );
}
/* Get the payload details, either as data passed in by the caller or
from the key context */
if( type == PKCS1_WRAP_RAW )
payloadSize = mechanismInfo->keyDataLength;
else
{
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_GETATTRIBUTE, &payloadSize,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
}
#ifdef USE_PGP
if( type == PKCS1_WRAP_PGP )
{
CRYPT_ALGO_TYPE sessionKeyAlgo;
/* PGP includes an additional algorithm specifier and checksum with
the wrapped key so we adjust the length to take this into
account */
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_GETATTRIBUTE, &sessionKeyAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
pgpAlgoID = cryptlibToPgpAlgo( sessionKeyAlgo );
if( cryptStatusError( pgpAlgoID ) )
return( CRYPT_ERROR_NOTAVAIL );
payloadSize += 3;
}
#endif /* USE_PGP */
/* Determine PKCS #1 padding parameters and make sure that the key is
long enough to encrypt the payload. PKCS #1 requires that the
maximum payload size be 11 bytes less than the length (to give a
minimum of 8 bytes of random padding) */
padSize = length - ( payloadSize + 3 );
if( payloadSize > length - 11 )
return( CRYPT_ERROR_OVERFLOW );
/* Encode the payload using the format given in PKCS #1, which for
encrypted data is [ 0 ][ 2 ][ nonzero random padding ][ 0 ][ payload ].
Note that the random padding is a nice place for a subliminal channel,
especially with large public key sizes where you can communicate more
information in the padding than in the payload */
wrappedData[ 0 ] = 0;
wrappedData[ 1 ] = 2;
setMessageData( &msgData, wrappedData + 2, padSize );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM_NZ );
wrappedData[ 2 + padSize ] = 0;
if( cryptStatusError( status ) )
{
zeroise( wrappedData, length );
return( status );
}
/* Copy the payload in at the last possible moment, then encrypt it */
dataPtr = wrappedData + 2 + padSize + 1;
switch( type )
{
case PKCS1_WRAP_NORMAL:
status = extractKeyData( mechanismInfo->keyContext, dataPtr );
break;
case PKCS1_WRAP_RAW:
memcpy( dataPtr, mechanismInfo->keyData, payloadSize );
break;
#ifdef USE_PGP
case PKCS1_WRAP_PGP:
*dataPtr++ = pgpAlgoID;
status = extractKeyData( mechanismInfo->keyContext, dataPtr );
pgpCalculateChecksum( dataPtr, payloadSize - 3, TRUE );
break;
#endif /* USE_PGP */
default:
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
if( cryptStatusError( status ) )
return( status );
if( cryptAlgo == CRYPT_ALGO_RSA )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_ENCRYPT, wrappedData, length );
else
{
DLP_PARAMS dlpParams;
assert( cryptAlgo == CRYPT_ALGO_ELGAMAL );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -