📄 cryptmch.c
字号:
void *keyData );
CRYPT_ALGO cryptAlgo;
RESOURCE_DATA msgData;
BYTE *wrappedData = mechanismInfo->wrappedData, *dataPtr;
int payloadSize, length, padSize, pgpAlgoID, status;
/* Clear the return value */
if( mechanismInfo->wrappedData != NULL )
memset( mechanismInfo->wrappedData, 0,
mechanismInfo->wrappedDataLength );
/* Get various algorithm parameters */
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_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,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&payloadSize, CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( status ) )
return( status );
}
if( type == PKCS1_WRAP_PGP )
{
CRYPT_ALGO 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,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&sessionKeyAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
pgpAlgoID = \
( sessionKeyAlgo == CRYPT_ALGO_3DES ) ? PGP_ALGO_3DES : \
( cryptAlgo == CRYPT_ALGO_BLOWFISH ) ? PGP_ALGO_BLOWFISH : \
( cryptAlgo == CRYPT_ALGO_CAST ) ? PGP_ALGO_CAST5 : \
PGP_ALGO_IDEA;
payloadSize += 3;
}
/* Determine PKCS #1 padding parameters and make sure 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;
setResourceData( &msgData, wrappedData + 2, padSize );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_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;
case PKCS1_WRAP_PGP:
*dataPtr++ = pgpAlgoID;
status = extractKeyData( mechanismInfo->keyContext, dataPtr );
calculatePGPchecksum( dataPtr, payloadSize - 3, TRUE );
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
if( cryptStatusError( status ) )
return( status );
if( cryptAlgo == CRYPT_ALGO_RSA )
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_IMESSAGE_CTX_ENCRYPT,
wrappedData, length );
else
{
DLP_PARAMS dlpParams;
assert( cryptAlgo == CRYPT_ALGO_ELGAMAL );
/* 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,
RESOURCE_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 cryptAlgo;
STREAM stream;
RESOURCE_DATA msgData;
BYTE decryptedData[ CRYPT_MAX_PKCSIZE ];
int length, status;
/* 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,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->wrapContext,
RESOURCE_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,
RESOURCE_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,
RESOURCE_IMESSAGE_CTX_DECRYPT,
&dlpParams, sizeof( DLP_PARAMS ) );
length = dlpParams.outLen;
}
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
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, decryptedData, length );
if( sgetc( &stream ) || sgetc( &stream ) != 2 )
status = CRYPT_ERROR_BADDATA;
else
{
int ch, 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( cryptStatusError( status ) )
{
sMemClose( &stream );
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
return( CRYPT_ERROR_BADDATA );
}
/* Return the result to the caller or load it into a context as a key */
switch( type )
{
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 = extractPGPKey( &mechanismInfo->keyContext, &stream,
length );
if( cryptStatusError( status ) )
break;
/* Fall through */
case PKCS1_WRAP_NORMAL:
/* Load the decrypted keying information into the session key
context */
setResourceData( &msgData, stream.buffer + stream.bufPos, length );
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;
break;
case PKCS1_WRAP_RAW:
/* Return the result to the caller */
if( length > mechanismInfo->keyDataLength )
status = CRYPT_ERROR_OVERFLOW;
else
{
memcpy( mechanismInfo->keyData,
stream.buffer + stream.bufPos, length );
mechanismInfo->keyDataLength = length;
}
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
sMemClose( &stream );
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 ) );
}
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 ) );
}
/* 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, RESOURCE_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 )
{
STATIC_FN 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,
RESOURCE_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -