📄 cryptmch.c
字号:
/* For DLP-based PKC's the output length isn't the same as the key
size so we adjust the return length as required */
setDLPParams( &dlpParams, wrappedData, length, wrappedData,
mechanismInfo->wrappedDataLength );
if( type == PKCS1_WRAP_PGP )
dlpParams.formatType = CRYPT_FORMAT_PGP;
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_ENCRYPT, &dlpParams,
sizeof( DLP_PARAMS ) );
if( cryptStatusOK( status ) )
length = dlpParams.outLen;
}
if( cryptStatusError( status ) )
{
zeroise( wrappedData, length );
return( status );
}
mechanismInfo->wrappedDataLength = length;
return( CRYPT_OK );
}
static int pkcs1Unwrap( MECHANISM_WRAP_INFO *mechanismInfo,
const PKCS1_WRAP_TYPE type )
{
CRYPT_ALGO_TYPE cryptAlgo;
STREAM stream;
RESOURCE_DATA msgData;
BYTE decryptedData[ CRYPT_MAX_PKCSIZE ];
int length, status;
assert( type == PKCS1_WRAP_NORMAL || type == PKCS1_WRAP_RAW || \
type == PKCS1_WRAP_PGP );
/* Clear the return value if we're returning raw data */
if( type == PKCS1_WRAP_RAW )
memset( mechanismInfo->keyData, 0, mechanismInfo->keyDataLength );
/* 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 );
/* Decrypt the data */
if( cryptAlgo == CRYPT_ALGO_RSA )
{
status = adjustPKCS1Data( decryptedData, mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength, length );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_DECRYPT, decryptedData,
length );
}
else
{
DLP_PARAMS dlpParams;
assert( cryptAlgo == CRYPT_ALGO_ELGAMAL );
setDLPParams( &dlpParams, mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength, decryptedData,
CRYPT_MAX_PKCSIZE );
if( type == PKCS1_WRAP_PGP )
dlpParams.formatType = CRYPT_FORMAT_PGP;
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_DECRYPT, &dlpParams,
sizeof( DLP_PARAMS ) );
length = dlpParams.outLen;
}
if( cryptStatusOK( status ) && \
( length < 11 + bitsToBytes( MIN_KEYSIZE_BITS ) || \
length > mechanismInfo->wrappedDataLength ) )
/* PKCS #1 padding requires at least 11 bytes of padding data, if
there isn't this much present we can't have a valid payload */
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
{
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
return( status );
}
/* Undo the PKCS #1 padding, which for encrypted data is
[ 0 ][ 2 ][ random nonzero padding ][ 0 ][ payload ] with a minimum of
8 bytes padding. Note that some implementations may have bignum code
that zero-truncates the result, producing 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, decryptedData, length );
if( sgetc( &stream ) || sgetc( &stream ) != 2 )
status = CRYPT_ERROR_BADDATA;
else
{
int ch = 1, i;
for( i = 0; i < length - 3; i++ )
if( ( ch = sgetc( &stream ) ) == 0 )
break;
if( ch != 0 || i < 8 )
status = CRYPT_ERROR_BADDATA;
else
length -= 2 + i + 1; /* [ 0 ][ 2 ] + padding + [ 0 ] */
}
if( cryptStatusOK( status ) && length < bitsToBytes( MIN_KEYSIZE_BITS ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
return( status );
}
/* Return the result to the caller or load it into a context as a key */
switch( type )
{
#ifdef USE_PGP
case PKCS1_WRAP_PGP:
/* PGP includes extra wrapping around the key, so we have to
process that before we can load it */
length -= 3; /* Subtract extra wrapping length */
status = pgpExtractKey( &mechanismInfo->keyContext, &stream,
length );
if( cryptStatusError( status ) )
break;
/* Fall through */
#endif /* USE_PGP */
case PKCS1_WRAP_NORMAL:
/* Load the decrypted keying information into the session key
context */
setMessageData( &msgData, sMemBufPtr( &stream ), length );
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
if( status == CRYPT_ARGERROR_STR1 || \
status == CRYPT_ARGERROR_NUM1 )
/* If there was an error with the key value or size, convert
the return value into something more appropriate */
status = CRYPT_ERROR_BADDATA;
break;
case PKCS1_WRAP_RAW:
/* Return the result to the caller */
if( length > mechanismInfo->keyDataLength )
status = CRYPT_ERROR_OVERFLOW;
else
{
memcpy( mechanismInfo->keyData, sMemBufPtr( &stream ),
length );
mechanismInfo->keyDataLength = length;
}
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
sMemDisconnect( &stream );
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
return( status );
}
int exportPKCS1( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED( dummy );
return( pkcs1Wrap( mechanismInfo,
( mechanismInfo->keyContext == CRYPT_UNUSED ) ? \
PKCS1_WRAP_RAW : PKCS1_WRAP_NORMAL ) );
}
int importPKCS1( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED( dummy );
return( pkcs1Unwrap( mechanismInfo,
( mechanismInfo->keyData != NULL ) ? \
PKCS1_WRAP_RAW : PKCS1_WRAP_NORMAL ) );
}
#ifdef USE_PGP
int exportPKCS1PGP( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED( dummy );
return( pkcs1Wrap( mechanismInfo, PKCS1_WRAP_PGP ) );
}
int importPKCS1PGP( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
UNUSED( dummy );
return( pkcs1Unwrap( mechanismInfo, PKCS1_WRAP_PGP ) );
}
#endif /* USE_PGP */
/* Perform CMS data wrapping. Returns an error code or the number of output
bytes */
#define CMS_KEYBLOCK_HEADERSIZE 4
static int cmsGetPadSize( const CRYPT_CONTEXT iExportContext,
const int payloadSize )
{
int blockSize, totalSize, status;
status = krnlSendMessage( iExportContext, IMESSAGE_GETATTRIBUTE,
&blockSize, CRYPT_CTXINFO_IVSIZE );
if( cryptStatusError( status ) )
return( status );
/* Determine the padding size, which is the amount of padding required to
bring the total data size up to a multiple of the block size with a
minimum size of two blocks */
totalSize = roundUp( payloadSize, blockSize );
if( totalSize < blockSize * 2 )
totalSize = blockSize * 2;
return( totalSize - payloadSize );
}
int exportCMS( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
int extractKeyData( const CRYPT_CONTEXT iCryptContext, void *keyData );
BYTE *keyBlockPtr = ( BYTE * ) mechanismInfo->wrappedData;
int payloadSize, padSize, status = CRYPT_OK;
UNUSED( dummy );
/* Sanity check the input data */
assert( ( mechanismInfo->wrappedData == NULL && \
mechanismInfo->wrappedDataLength == 0 ) || \
( mechanismInfo->wrappedDataLength >= 16 && \
mechanismInfo->wrappedDataLength >= mechanismInfo->keyDataLength ) );
assert( mechanismInfo->keyData == NULL );
assert( mechanismInfo->keyDataLength == 0 );
assert( mechanismInfo->keyContext != CRYPT_UNUSED );
assert( mechanismInfo->auxContext == CRYPT_UNUSED );
/* Clear the return value */
if( mechanismInfo->wrappedData != NULL )
memset( mechanismInfo->wrappedData, 0,
mechanismInfo->wrappedDataLength );
/* Get the payload details, either as data passed in by the caller or
from the key context */
if( mechanismInfo->keyContext == CRYPT_UNUSED )
payloadSize = mechanismInfo->keyDataLength;
else
{
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_GETATTRIBUTE, &payloadSize,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
}
payloadSize += CMS_KEYBLOCK_HEADERSIZE;
padSize = cmsGetPadSize( mechanismInfo->wrapContext, payloadSize );
/* If this is just a length check, we're done */
if( mechanismInfo->wrappedData == NULL )
{
mechanismInfo->wrappedDataLength = payloadSize + padSize;
return( CRYPT_OK );
}
/* Pad the payload out with a random nonce if required */
if( padSize > 0 )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, keyBlockPtr + payloadSize, padSize );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
}
/* Format the key block: [length][check value][key][padding], copy the
payload in at the last possible moment, then perform two passes of
encryption retaining the IV from the first pass for the second pass */
keyBlockPtr[ 0 ] = payloadSize - CMS_KEYBLOCK_HEADERSIZE;
if( mechanismInfo->keyContext != CRYPT_UNUSED )
status = extractKeyData( mechanismInfo->keyContext,
keyBlockPtr + CMS_KEYBLOCK_HEADERSIZE );
else
memcpy( keyBlockPtr + CMS_KEYBLOCK_HEADERSIZE,
mechanismInfo->keyData, payloadSize );
keyBlockPtr[ 1 ] = keyBlockPtr[ CMS_KEYBLOCK_HEADERSIZE ] ^ 0xFF;
keyBlockPtr[ 2 ] = keyBlockPtr[ CMS_KEYBLOCK_HEADERSIZE + 1 ] ^ 0xFF;
keyBlockPtr[ 3 ] = keyBlockPtr[ CMS_KEYBLOCK_HEADERSIZE + 2 ] ^ 0xFF;
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_ENCRYPT,
mechanismInfo->wrappedData,
payloadSize + padSize );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_ENCRYPT,
mechanismInfo->wrappedData,
payloadSize + padSize );
if( cryptStatusError( status ) )
{
zeroise( mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength );
return( status );
}
mechanismInfo->wrappedDataLength = payloadSize + padSize;
return( CRYPT_OK );
}
/* Perform CMS data unwrapping */
int importCMS( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
RESOURCE_DATA msgData;
BYTE buffer[ CRYPT_MAX_KEYSIZE + 16 ], ivBuffer[ CRYPT_MAX_IVSIZE ];
BYTE *dataEndPtr = buffer + mechanismInfo->wrappedDataLength;
int blockSize, status;
UNUSED( dummy );
/* Sanity check the input data */
assert( mechanismInfo->wrappedData != NULL );
assert( mechanismInfo->wrappedDataLength >= 16 );
assert( mechanismInfo->keyData == NULL );
assert( mechanismInfo->keyDataLength == 0 );
assert( mechanismInfo->keyContext != CRYPT_UNUSED );
assert( mechanismInfo->auxContext == CRYPT_UNUSED );
/* Make sure that the data is a multiple of the cipher block size */
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_GETATTRIBUTE, &blockSize,
CRYPT_CTXINFO_IVSIZE );
if( cryptStatusError( status ) )
return( status );
if( mechanismInfo->wrappedDataLength & ( blockSize - 1 ) )
return( CRYPT_ERROR_BADDATA );
/* Save the current IV for the inner decryption */
setMessageData( &msgData, ivBuffer, CRYPT_MAX_IVSIZE );
krnlSendMessage( mechanismInfo->wrapContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_IV );
/* Using the n-1'th ciphertext block as the new IV, decrypt the n'th block.
Then, using the decrypted n'th ciphertext block as the IV, decrypt the
remainder of the ciphertext blocks */
memcpy( buffer, mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength );
setMessageData( &msgData, dataEndPtr - 2 * blockSize, blockSize );
krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_CTXINFO_IV );
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_DECRYPT, dataEndPtr - blockSize,
blockSize );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, dataEndPtr - blockSize, blockSize );
krnlSendMessage( mechanismInfo->wrapContext,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -