📄 cryptmch.c
字号:
IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_CTXINFO_IV );
status = krnlSendMessage( mechanismInfo->wrapContext,
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 */
setMessageData( &msgData, ivBuffer, blockSize );
krnlSendMessage( mechanismInfo->wrapContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_IV );
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_DECRYPT, buffer,
mechanismInfo->wrappedDataLength );
/* Make sure that 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 ) )
{
setMessageData( &msgData, buffer + CMS_KEYBLOCK_HEADERSIZE,
buffer[ 0 ] );
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;
}
zeroise( buffer, CRYPT_MAX_KEYSIZE + 16 );
return( status );
}
/* Perform private key wrapping/unwrapping. There are several variations of
this that are handled through common private key wrap mechanism
functions */
typedef enum { PRIVATEKEY_WRAP_NORMAL,
PRIVATEKEY_WRAP_OLD } PRIVATEKEY_WRAP_TYPE;
static int privateKeyWrap( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo,
const PRIVATEKEY_WRAP_TYPE type )
{
int exportPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext,
const KEYFORMAT_TYPE type );
const KEYFORMAT_TYPE formatType = ( type == PRIVATEKEY_WRAP_NORMAL ) ? \
KEYFORMAT_PRIVATE : KEYFORMAT_PRIVATE_OLD;
STREAM stream;
int payloadSize, blockSize, padSize, status;
UNUSED( dummy );
assert( type == PRIVATEKEY_WRAP_NORMAL || \
type == PRIVATEKEY_WRAP_OLD );
/* 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,
formatType );
payloadSize = stell( &stream );
sMemClose( &stream );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_GETATTRIBUTE, &blockSize,
CRYPT_CTXINFO_IVSIZE );
if( cryptStatusError( status ) )
return( status );
padSize = roundUp( payloadSize + 1, blockSize ) - payloadSize;
/* 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,
formatType );
if( cryptStatusOK( status ) )
{
BYTE startSample[ 8 ], endSample[ 8 ];
const void *endSamplePtr = ( BYTE * ) mechanismInfo->wrappedData + \
stell( &stream ) - 8;
int i;
/* Sample the first and last 8 bytes of data so that we can check
that they really have been encrypted */
memcpy( startSample, mechanismInfo->wrappedData, 8 );
memcpy( endSample, endSamplePtr, 8 );
/* Add the PKCS #5 padding and encrypt the data */
for( i = 0; i < padSize; i++ )
sputc( &stream, padSize );
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_ENCRYPT,
mechanismInfo->wrappedData,
payloadSize + padSize );
/* Make sure that the original data samples differ from the final
data */
if( cryptStatusOK( status ) && \
( !memcmp( startSample, mechanismInfo->wrappedData, 8 ) || \
!memcmp( endSample, endSamplePtr, 8 ) ) )
{
assert( NOTREACHED );
status = CRYPT_ERROR_FAILED;
}
zeroise( startSample, 8 );
zeroise( endSample, 8 );
}
if( cryptStatusError( status ) )
{
sMemClose( &stream );
zeroise( mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength );
}
else
{
sMemDisconnect( &stream );
mechanismInfo->wrappedDataLength = payloadSize + padSize;
}
return( status );
}
static int privateKeyUnwrap( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo,
const PRIVATEKEY_WRAP_TYPE type )
{
int importPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext,
const KEYFORMAT_TYPE type );
const KEYFORMAT_TYPE formatType = ( type == PRIVATEKEY_WRAP_NORMAL ) ? \
KEYFORMAT_PRIVATE : KEYFORMAT_PRIVATE;
void *buffer;
int blockSize, status;
UNUSED( dummy );
assert( type == PRIVATEKEY_WRAP_NORMAL || \
type == PRIVATEKEY_WRAP_OLD );
/* Make sure that the data has a sane length and is a multiple of the
cipher block size (since we force the use of CBC mode we know it has
to have this property) */
status = krnlSendMessage( mechanismInfo->wrapContext,
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, \
mechanismInfo->wrappedDataLength ) ) != CRYPT_OK )
return( status );
memcpy( buffer, mechanismInfo->wrappedData,
mechanismInfo->wrappedDataLength );
status = krnlSendMessage( mechanismInfo->wrapContext,
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,
formatType );
if( status == CRYPT_ERROR_BADDATA )
status = CRYPT_ERROR_WRONGKEY;
sMemDisconnect( &stream );
}
zeroise( buffer, mechanismInfo->wrappedDataLength );
krnlMemfree( &buffer );
return( status );
}
int exportPrivateKey( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
return( privateKeyWrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_NORMAL ) );
}
int importPrivateKey( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
return( privateKeyUnwrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_NORMAL ) );
}
int exportPrivateKeyPKCS8( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
return( privateKeyWrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_OLD ) );
}
int importPrivateKeyPKCS8( void *dummy, MECHANISM_WRAP_INFO *mechanismInfo )
{
return( privateKeyUnwrap( dummy, mechanismInfo, PRIVATEKEY_WRAP_OLD ) );
}
#ifdef USE_PGPKEYS
/* Perform PGP private key wrapping/unwrapping. There are several variations
of this that are handled through common private key wrap mechanism
functions */
typedef enum { PRIVATEKEY_WRAP_PGP,
PRIVATEKEY_WRAP_OPENPGP } PRIVATEKEY_WRAP_PGP_TYPE;
static int privateKeyUnwrapPGP( void *dummy,
MECHANISM_WRAP_INFO *mechanismInfo,
const PRIVATEKEY_WRAP_PGP_TYPE type )
{
int importPrivateKeyData( STREAM *stream,
const CRYPT_CONTEXT iCryptContext,
const KEYFORMAT_TYPE type );
CRYPT_ALGO_TYPE cryptAlgo;
void *buffer;
int status;
UNUSED( dummy );
assert( type == PRIVATEKEY_WRAP_PGP || type == PRIVATEKEY_WRAP_OPENPGP );
/* Get various algorithm parameters */
status = krnlSendMessage( mechanismInfo->keyContext,
IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
/* 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 );
if( type == PRIVATEKEY_WRAP_OPENPGP )
status = krnlSendMessage( mechanismInfo->wrapContext,
IMESSAGE_CTX_DECRYPT, buffer,
mechanismInfo->wrappedDataLength );
else
{
STREAM stream;
/* The PGP 2.x wrap encrypts only the MPI data rather than the
entire private key record, so we have to read and then decrypt
each component separately */
sMemConnect( &stream, buffer, mechanismInfo->wrappedDataLength );
status = pgpReadDecryptMPI( &stream, /* d or x */
mechanismInfo->wrapContext );
if( cryptStatusOK( status ) && cryptAlgo == CRYPT_ALGO_RSA )
{
status = pgpReadDecryptMPI( &stream, /* p */
mechanismInfo->wrapContext );
if( cryptStatusOK( status ) )
status = pgpReadDecryptMPI( &stream, /* q */
mechanismInfo->wrapContext );
if( cryptStatusOK( status ) )
status = pgpReadDecryptMPI( &stream, /* u */
mechanismInfo->wrapContext );
}
sMemDisconnect( &stream );
}
if( cryptStatusOK( status ) )
{
STREAM stream;
unsigned int checkSum, packetChecksum;
int streamPos;
/* Checksum the MPI payload to make sure that the decrypt went OK */
sMemConnect( &stream, buffer, mechanismInfo->wrappedDataLength );
checkSum = pgpChecksumMPI( &stream ); /* d or x */
if( cryptAlgo == CRYPT_ALGO_RSA )
{
checkSum += pgpChecksumMPI( &stream ); /* p */
checkSum += pgpChecksumMPI( &stream ); /* q */
checkSum += pgpChecksumMPI( &stream ); /* u */
}
streamPos = stell( &stream );
if( mechanismInfo->wrappedDataLength - streamPos == 20 )
{
HASHFUNCTION hashFunction;
BYTE hashValue[ CRYPT_MAX_HASHSIZE ];
int hashSize;
/* There's too much data present for it to be a simple checksum,
it must be an SHA-1 hash */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
hashFunc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -