📄 keyex.c
字号:
&cryptMode, CRYPT_CTXINFO_MODE );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM2 : status );
/* Read the encrypted key record up to the start of the encrypted key and
make sure we'll be using the correct type of encryption context to
decrypt it */
memset( &queryInfo, 0, sizeof( QUERY_INFO ) );
sMemConnect( &stream, encryptedKey, encryptedKeyLength );
status = readKeyexFunction( &stream, &queryInfo );
sMemDisconnect( &stream );
if( cryptStatusOK( status ) && \
( cryptAlgo != queryInfo.cryptAlgo || \
cryptMode != queryInfo.cryptMode ) )
status = CRYPT_ARGERROR_NUM1;
if( cryptStatusError( status ) )
{
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
/* Extract the encrypted key from the buffer and decrypt it. Since we
don't want another thread changing the IV while we're using the import
context, we lock it for the duration */
status = krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
if( cryptStatusError( status ) )
return( status );
if( needsIV( cryptMode ) && cryptAlgo != CRYPT_ALGO_RC4 )
{
setMessageData( &msgData, queryInfo.iv, queryInfo.ivLength );
krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
}
setMechanismWrapInfo( &mechanismInfo,
queryInfo.dataStart, queryInfo.dataLength,
NULL, 0, iSessionKeyContext, iImportContext,
CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
&mechanismInfo, MECHANISM_ENC_CMS );
krnlSendMessage( iImportContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
clearMechanismInfo( &mechanismInfo );
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
/* Import a public-key encrypted session key */
static int importPublicKey( const void *encryptedKey,
const int encryptedKeyLength,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iImportContext,
CRYPT_CONTEXT *iReturnedContext,
const KEYEX_TYPE keyexType )
{
MECHANISM_WRAP_INFO mechanismInfo;
const READKEYTRANS_FUNCTION readKeyexFunction = \
keytransReadTable[ keyexType ];
QUERY_INFO queryInfo;
STREAM stream;
int status;
/* Make sure the requested key exchange format is available */
if( readKeyexFunction == NULL )
return( CRYPT_ERROR_NOTAVAIL );
/* Read the encrypted key record up to the start of the encrypted key and
make sure we've been given the correct key */
memset( &queryInfo, 0, sizeof( QUERY_INFO ) );
sMemConnect( &stream, encryptedKey, encryptedKeyLength );
status = readKeyexFunction( &stream, &queryInfo );
sMemDisconnect( &stream );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
int compareType;
setMessageData( &msgData, queryInfo.keyID,
queryInfo.keyIDlength );
switch( keyexType )
{
case KEYEX_CMS:
setMessageData( &msgData, queryInfo.iAndSStart,
queryInfo.iAndSLength );
compareType = MESSAGE_COMPARE_ISSUERANDSERIALNUMBER;
break;
case KEYEX_CRYPTLIB:
compareType = MESSAGE_COMPARE_KEYID;
break;
case KEYEX_PGP:
compareType = ( queryInfo.version == PGP_VERSION_2 ) ? \
MESSAGE_COMPARE_KEYID_PGP : \
MESSAGE_COMPARE_KEYID_OPENPGP;
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
status = krnlSendMessage( iImportContext, IMESSAGE_COMPARE,
&msgData, compareType );
if( cryptStatusError( status ) && \
compareType == MESSAGE_COMPARE_KEYID_OPENPGP )
/* Some broken PGP implementations put PGP 2.x IDs in packets
marked as OpenPGP packets, so if we were doing a check for
an OpenPGP ID and it failed, fall back to a PGP 2.x one */
status = krnlSendMessage( iImportContext, IMESSAGE_COMPARE,
&msgData, MESSAGE_COMPARE_KEYID_PGP );
if( cryptStatusError( status ) )
/* A failed comparison is reported as a generic CRYPT_ERROR,
convert it into a wrong-key error */
status = CRYPT_ERROR_WRONGKEY;
}
if( cryptStatusError( status ) )
{
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
/* Decrypt the encrypted key and load it into the context */
if( keyexType != KEYEX_PGP )
{
setMechanismWrapInfo( &mechanismInfo,
queryInfo.dataStart, queryInfo.dataLength,
NULL, 0, iSessionKeyContext, iImportContext,
CRYPT_UNUSED );
status = krnlSendMessage( iImportContext, IMESSAGE_DEV_IMPORT,
&mechanismInfo, MECHANISM_ENC_PKCS1 );
}
else
{
/* PGP doesn't provide separate session key information with the
encrypted data but wraps it up alongside the encrypted key, so we
can't import the wrapped key into a context via the standard key
import functions but instead have to create the context as part
of the unwrap process */
setMechanismWrapInfo( &mechanismInfo, queryInfo.dataStart,
queryInfo.dataLength, NULL, 0, CRYPT_UNUSED,
iImportContext, CRYPT_UNUSED );
status = krnlSendMessage( iImportContext, IMESSAGE_DEV_IMPORT,
&mechanismInfo, MECHANISM_ENC_PKCS1_PGP );
if( cryptStatusOK( status ) )
*iReturnedContext = mechanismInfo.keyContext;
}
clearMechanismInfo( &mechanismInfo );
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
#if 0 /* 24/11/02 Removed since it was only used for Fortezza */
/* Import a key agreement session key */
static int importKeyAgreeKey( const void *encryptedKey,
const int encryptedKeyLength,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iImportContext )
{
CRYPT_CONTEXT iLocalContext;
QUERY_INFO queryInfo;
STREAM stream;
BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
int status;
/* Read the key agreement record. Due to the somewhat peculiar concept
of what constitutes a public key for DH, this doesn't really work as
well as the standard key wrap algorithms since what we're reading are
the components of a complete context. As a result the initiator and
responder for the DH exchange end up with the following:
Initiator Responder
cryptInfoPtr p, g, x(I), y(I) -
iLocalContext p, g, y(R) p, g, y(I)
If we're doing the import for the responder, we copy the values from
the import context into the responder context and perform a key load,
which generates the responders x value and key ID. This is a horrible
kludge, what we should be doing is passing the import context back to
the user but this isn't possible because cryptImportKey() passes the
import context by value.
If we're doing the import for the initiator, we just check that the
key used by the responder was the same as the one used by the
initiator */
memset( &queryInfo, 0, sizeof( QUERY_INFO ) );
sMemConnect( &stream, encryptedKey, encryptedKeyLength );
status = readKeyAgreeInfo( &stream, &queryInfo, &iLocalContext );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
/* Generate the shared secret value and load it into the session key
context. We use a fixed 64-bit salt and explicitly set the iteration
count to make sure it isn't upset if the user changes config options */
status = krnlSendMessage( iImportContext, IMESSAGE_CTX_DECRYPT,
buffer, CRYPT_UNUSED );
if( !cryptStatusError( status ) )
{
static const BYTE *salt = ( BYTE * ) "\x00\x00\x00\x00\x00\x00\x00\x00";
static const int iterations = 100;
RESOURCE_DATA msgData;
krnlSendMessage( iSessionKeyContext, IMESSAGE_SETATTRIBUTE,
( int * ) &iterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
setMessageData( &msgData, ( void * ) salt, 8 );
krnlSendMessage( iSessionKeyContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_SALT );
setMessageData( &msgData, buffer, status );
status = krnlSendMessage( iSessionKeyContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_VALUE );
}
return( status );
}
#endif /* 0 */
/****************************************************************************
* *
* Import/Export a Session Key *
* *
****************************************************************************/
/* Import an extended encrypted key, either a cryptlib key or a CMS key */
static CRYPT_FORMAT_TYPE getFormatType( const void *data )
{
STREAM stream;
const BYTE *dataPtr = data;
#ifdef USE_PGP
long length;
#endif /* USE_PGP */
int status;
/* Figure out what we've got. PKCS #7/CMS/SMIME keyTrans begins:
keyTransRecipientInfo ::= SEQUENCE {
version INTEGER (0|2),
while a kek begins:
kekRecipientInfo ::= [3] IMPLICIT SEQUENCE {
version INTEGER (4),
which allows us to determine which type of object we have */
if( *dataPtr == BER_SEQUENCE )
{
CRYPT_FORMAT_TYPE formatType = CRYPT_FORMAT_NONE;
sMemConnect( &stream, data, 16 );
status = readSequence( &stream, NULL );
if( cryptStatusOK( status ) )
{
long version;
if( cryptStatusOK( readShortInteger( &stream, &version ) ) )
formatType = ( version == 0 ) ? CRYPT_FORMAT_CMS : \
( version == 2 ) ? CRYPT_FORMAT_CRYPTLIB : \
CRYPT_FORMAT_NONE;
}
sMemDisconnect( &stream );
return( formatType );
}
if( *dataPtr == MAKE_CTAG( 3 ) )
{
CRYPT_FORMAT_TYPE formatType = CRYPT_FORMAT_NONE;
sMemConnect( &stream, data, 16 );
status = readConstructed( &stream, NULL, 3 );
if( cryptStatusOK( status ) )
{
long version;
if( cryptStatusOK( readShortInteger( &stream, &version ) ) )
formatType = ( version == 0 ) ? CRYPT_FORMAT_CRYPTLIB : \
CRYPT_FORMAT_NONE;
}
sMemDisconnect( &stream );
return( formatType );
}
#ifdef USE_PGP
/* It's not ASN.1 data, check for PGP data */
sMemConnect( &stream, data, 16 );
status = pgpReadPacketHeader( &stream, NULL, &length );
if( cryptStatusOK( status ) && length > 30 && length < 8192 )
{
sMemDisconnect( &stream );
return( CRYPT_FORMAT_PGP );
}
sMemDisconnect( &stream );
#endif /* USE_PGP */
return( CRYPT_FORMAT_NONE );
}
C_RET cryptImportKeyEx( C_IN void C_PTR encryptedKey,
C_IN int encryptedKeyLength,
C_IN CRYPT_CONTEXT importKey,
C_IN CRYPT_CONTEXT sessionKeyContext,
C_OUT CRYPT_CONTEXT C_PTR returnedContext )
{
CRYPT_FORMAT_TYPE formatType;
CRYPT_ALGO_TYPE cryptAlgo;
CRYPT_CONTEXT iReturnedContext;
MESSAGE_CHECK_TYPE checkType;
int owner, originalOwner, status;
/* Perform basic error checking */
if( encryptedKeyLength < MIN_CRYPT_OBJECTSIZE )
return( CRYPT_ERROR_PARAM2 );
if( !isReadPtr( encryptedKey, encryptedKeyLength ) )
return( CRYPT_ERROR_PARAM1 );
if( ( formatType = getFormatType( encryptedKey ) ) == CRYPT_FORMAT_NONE )
return( CRYPT_ERROR_BADDATA );
/* Check the importing key */
status = krnlSendMessage( importKey, MESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ERROR_PARAM3 : status );
if( cryptAlgo >= CRYPT_ALGO_FIRST_PKC && cryptAlgo <= CRYPT_ALGO_LAST_PKC )
checkType = ( cryptAlgo == CRYPT_ALGO_DH ) ? \
MESSAGE_CHECK_PKC_KA_IMPORT : MESSAGE_CHECK_PKC_DECRYPT;
else
checkType = MESSAGE_CHECK_CRYPT;
if( isDlpAlgo( cryptAlgo ) )
/* The DLP algorithms have specialised data-formatting requirements
and can't normally be directly accessed via external messages,
however if we're performing a key export this is OK since they're
being used from cryptlib-internal routines. Doing the check via
an internal message is safe since we've already checked its
external accessibility when we got the algorithm info */
status = krnlSendMessage( importKey, IMESSAGE_CHECK, NULL,
checkType );
else
status = krnlSendMessage( importKey, MESSAGE_CHECK, NULL,
checkType );
if( cryptAlgo == CRYPT_ALGO_DH && status == CRYPT_ERROR_NOTINITED )
/* For key agreement keys the fact that there's no key attribute set
is OK since the key parameters are read from the exchanged object */
status = CRYPT_OK;
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ERROR_PARAM3 : status );
/* Check the session key */
if( formatType == CRYPT_FORMAT_PGP )
{
/* PGP stores the session key information with the encrypted key
data, so the user can't provide a context */
if( sessionKeyContext != CRYPT_UNUSED )
return( CRYPT_ERROR_PARAM4 );
if( !isWritePtr( returnedContext, sizeof( CRYPT_CONTEXT ) ) )
return( CRYPT_ERROR_PARAM5 );
}
else
{
CRYPT_ALGO_TYPE sessionKeyAlgo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -