📄 cryptmch.c
字号:
return( CRYPT_OK );
}
/* Pad the payload out with a random nonce if required */
if( padSize > 0 )
getNonce( keyBlockPtr + payloadSize, padSize );
/* 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,
RESOURCE_IMESSAGE_CTX_ENCRYPT,
mechanismInfo->wrappedData,
payloadSize + padSize );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_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 the data is a multiple of the cipher block size */
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_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 */
setResourceData( &msgData, ivBuffer, CRYPT_MAX_IVSIZE );
krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_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 );
setResourceData( &msgData, dataEndPtr - 2 * blockSize, blockSize );
krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_CTX_DECRYPT,
dataEndPtr - blockSize, blockSize );
if( cryptStatusOK( status ) )
{
setResourceData( &msgData, dataEndPtr - blockSize, blockSize );
krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_CTX_DECRYPT, buffer,
mechanismInfo->wrappedDataLength - blockSize );
}
if( cryptStatusError( status ) )
{
zeroise( buffer, CRYPT_MAX_KEYSIZE + 16 );
return( status );
}
/* Using the original IV, decrypt the inner data */
setResourceData( &msgData, ivBuffer, blockSize );
krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_CTX_DECRYPT, buffer,
mechanismInfo->wrappedDataLength );
/* Make sure everything is in order and load the decrypted keying
information into the session key context */
if( cryptStatusOK( status ) )
{
if( buffer[ 0 ] < bitsToBytes( MIN_KEYSIZE_BITS ) || \
buffer[ 0 ] > bitsToBytes( MAX_KEYSIZE_BITS ) )
status = CRYPT_ERROR_BADDATA;
if( buffer[ 1 ] != ( buffer[ CMS_KEYBLOCK_HEADERSIZE ] ^ 0xFF ) || \
buffer[ 2 ] != ( buffer[ CMS_KEYBLOCK_HEADERSIZE + 1 ] ^ 0xFF ) || \
buffer[ 3 ] != ( buffer[ CMS_KEYBLOCK_HEADERSIZE + 2 ] ^ 0xFF ) )
status = CRYPT_ERROR_WRONGKEY;
}
if( cryptStatusOK( status ) )
{
setResourceData( &msgData, buffer + CMS_KEYBLOCK_HEADERSIZE,
buffer[ 0 ] );
status = krnlSendMessage( mechanismInfo->keyContext,
RESOURCE_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;
}
zeroise( buffer, CRYPT_MAX_KEYSIZE + 16 );
return( status );
}
/* Perform private key wrapping/unwrapping */
int exportPrivateKey( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
STATIC_FN int exportPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext );
STREAM stream;
int payloadSize, blockSize, padSize, status;
UNUSED( dummy );
/* Sanity check the input data */
assert( ( mechanismInfo->wrappedData == NULL && \
mechanismInfo->wrappedDataLength == 0 ) || \
( mechanismInfo->wrappedDataLength >= 16 ) );
assert( mechanismInfo->keyData == NULL );
assert( mechanismInfo->keyDataLength == 0 );
assert( mechanismInfo->auxContext == CRYPT_UNUSED );
/* Clear the return value */
if( mechanismInfo->wrappedData != NULL )
memset( mechanismInfo->wrappedData, 0,
mechanismInfo->wrappedDataLength );
/* Get the payload details */
sMemOpen( &stream, NULL, 0 );
status = exportPrivateKeyData( &stream, mechanismInfo->keyContext );
payloadSize = ( int ) stell( &stream );
sMemClose( &stream );
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &blockSize,
CRYPT_CTXINFO_IVSIZE );
if( cryptStatusError( status ) )
return( status );
padSize = roundUp( payloadSize + 1, blockSize ) - payloadSize;
if( cryptStatusError( status ) )
return( status );
/* If this is just a length check, we're done */
if( mechanismInfo->wrappedData == NULL )
{
mechanismInfo->wrappedDataLength = payloadSize + padSize;
return( CRYPT_OK );
}
/* Write the private key data, PKCS #5-pad it, and encrypt it */
sMemOpen( &stream, mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength );
status = exportPrivateKeyData( &stream, mechanismInfo->keyContext );
if( cryptStatusOK( status ) )
{
int i;
for( i = 0; i < padSize; i++ )
sputc( &stream, padSize );
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_CTX_ENCRYPT,
mechanismInfo->wrappedData,
payloadSize + padSize );
}
if( cryptStatusError( status ) )
sMemClose( &stream );
else
{
sMemDisconnect( &stream );
mechanismInfo->wrappedDataLength = payloadSize + padSize;
}
return( status );
}
int importPrivateKey( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
STATIC_FN int importPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext );
void *buffer;
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->auxContext == CRYPT_UNUSED );
/* Make sure the data has a sane length and is a multiple of the cipher
block size (since we force the use of the CBC mode we know it has to
have this property) */
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &blockSize,
CRYPT_CTXINFO_IVSIZE );
if( cryptStatusError( status ) )
return( status );
if( ( mechanismInfo->wrappedDataLength >= MAX_PRIVATE_KEYSIZE ) || \
( mechanismInfo->wrappedDataLength & ( blockSize - 1 ) ) )
return( CRYPT_ERROR_BADDATA );
/* Copy the encrypted private key data to a temporary buffer, decrypt it,
and read it into the context. If we get a corrupted-data error then
it's far more likely to be because we decrypted with the wrong key
than because any data was corrupted, so we convert it to a wrong-key
error */
if( ( status = krnlMemalloc( &buffer, MAX_PRIVATE_KEYSIZE ) ) != CRYPT_OK )
return( status );
memcpy( buffer, mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength );
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_CTX_DECRYPT, buffer,
mechanismInfo->wrappedDataLength );
if( cryptStatusOK( status ) )
{
int length;
length = getObjectLength( buffer, mechanismInfo->wrappedDataLength );
if( cryptStatusError( length ) )
status = ( length == CRYPT_ERROR_BADDATA ) ? \
CRYPT_ERROR_WRONGKEY : length;
else
{
const BYTE *bufPtr = ( BYTE * ) buffer + length;
const int padSize = blockSize - ( length & ( blockSize - 1 ) );
int i;
/* Check that the PKCS #5 padding is as expected. Performing the
check this way is the reverse of the way it's usually done
because we already know the payload size from the ASN.1 and
can use this to determine the expected padding value and thus
check that the end of the encrypted data hasn't been subject
to a bit-flipping attack. For example for RSA private keys
the end of the data is:
[ INTEGER u ][ INTEGER keySize ][ padding ]
where the keySize is encoded as a 4-byte value and the padding
is 1-8 bytes. In order to flip the low bits of u, there's a
5/8 chance that either the keySize value (checked in the RSA
read code) or padding will be messed up, both of which will be
detected (in addition the RSA key load checks try and verify u
when the key is loaded). For DLP keys the end of the data is:
[ INTEGER x ][ padding ]
for which bit flipping is rather harder to detect since 7/8 of
the time the following block won't be affected, however the
DLP key load checks also verify x when the key is loaded.
The padding checking is effectively free and helps make Klima-
Rosa type attacks harder */
for( i = 0; i < padSize; i++ )
if( bufPtr[ i ] != padSize )
status = CRYPT_ERROR_BADDATA;
}
}
if( cryptStatusOK( status ) )
{
STREAM stream;
sMemConnect( &stream, buffer, mechanismInfo->wrappedDataLength );
status = importPrivateKeyData( &stream, mechanismInfo->keyContext );
if( status == CRYPT_ERROR_BADDATA )
status = CRYPT_ERROR_WRONGKEY;
sMemClose( &stream );
}
krnlMemfree( &buffer );
return( status );
}
/****************************************************************************
* *
* Key Extract Functions *
* *
****************************************************************************/
/* Extract a key from a context. This is a somewhat ugly set of functions
which need to bypass the kernel's security checking and are the only ones
which can do this. Like trusted downgraders in other security models,
this is an unavoidable requirement in the complete-isolation model - some
bypass mechanism needs to be present in order to allow a key to be
exported from an encryption action object */
#include "cryptctx.h"
static int extractKeyData( const CRYPT_CONTEXT iCryptContext, void *keyData )
{
CRYPT_INFO *cryptInfoPtr;
getCheckInternalResource( iCryptContext, cryptInfoPtr, OBJECT_TYPE_CONTEXT );
if( cryptInfoPtr->type == CONTEXT_CONV )
memcpy( keyData, cryptInfoPtr->ctxConv.userKey,
cryptInfoPtr->ctxConv.userKeyLength );
else
memcpy( keyData, cryptInfoPtr->ctxMAC.userKey,
cryptInfoPtr->ctxMAC.userKeyLength );
unlockResourceExit( cryptInfoPtr, CRYPT_OK );
}
/* Prototypes for functions in asn1keys.c */
int readPrivateKey( STREAM *stream, CRYPT_INFO *cryptInfoPtr );
int writePrivateKey( STREAM *stream, const CRYPT_INFO *cryptInfoPtr );
static int exportPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext )
{
CRYPT_CONTEXT iPrivateKeyContext;
CRYPT_INFO *cryptInfoPtr;
int status;
/* We may have been passed something else with a context attached, get the
context itself */
status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETDEPENDENT,
&iPrivateKeyContext, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
/* Make sure that we've been given a PKC context with a private key
loaded (this has already been checked at a higher level, but we
perform a sanity check here to be sage) */
getCheckInternalResource( iPrivateKeyContext, cryptInfoPtr,
OBJECT_TYPE_CONTEXT );
if( cryptInfoPtr->type != CONTEXT_PKC || !cryptInfoPtr->ctxPKC.keySet || \
cryptInfoPtr->ctxPKC.isPublicKey )
unlockResourceExit( cryptInfoPtr, CRYPT_ARGERROR_OBJECT );
status = writePrivateKey( stream, cryptInfoPtr );
unlockResourceExit( cryptInfoPtr, status );
}
static int importPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext )
{
CRYPT_INFO *cryptInfoPtr;
int status;
getCheckInternalResource( iCryptContext, cryptInfoPtr, OBJECT_TYPE_CONTEXT );
status = readPrivateKey( stream, cryptInfoPtr );
unlockResourceExit( cryptInfoPtr, status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -