?? lib_keyx.c
字號:
/****************************************************************************
* *
* cryptlib Key Exchange Routines *
* Copyright Peter Gutmann 1993-2001 *
* *
****************************************************************************/
#include <string.h>
#include <stdlib.h>
#include "crypt.h"
#ifdef INC_ALL
#include "asn1.h"
#include "asn1objs.h"
#include "asn1oid.h"
#else
#include "keymgmt/asn1.h"
#include "keymgmt/asn1objs.h"
#include "keymgmt/asn1oid.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Low-level Key Export Functions *
* *
****************************************************************************/
/* Export a conventionally encrypted session key */
static int exportConventionalKey( void *encryptedKey, int *encryptedKeyLength,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iExportContext )
{
MECHANISM_WRAP_INFO mechanismInfo;
BYTE buffer[ CRYPT_MAX_KEYSIZE + 16 ];
int keySize, ivSize, status;
krnlSendMessage( iSessionKeyContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&keySize, CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusError( krnlSendMessage( iExportContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &ivSize,
CRYPT_CTXINFO_IVSIZE ) ) )
ivSize = 0;
/* If we're just doing a length check, write the data to a null stream
and return its length */
if( encryptedKey == NULL )
{
STREAM nullStream;
int dummyDataSize;
/* Calculate the eventual encrypted key size */
setMechanismWrapInfo( &mechanismInfo, NULL, 0,
NULL, 0, iSessionKeyContext, iExportContext,
CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_EXPORT, &mechanismInfo,
MECHANISM_CMS );
dummyDataSize = mechanismInfo.wrappedDataLength;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
return( status );
/* Generate an IV to allow the KEK write to succeed - see the comment
below about this */
if( ivSize )
krnlSendNotifier( iExportContext, RESOURCE_IMESSAGE_CTX_GENIV );
/* Write the data to a null stream to determine its size. The
buffer doesn't contain anything useful since it's only used for a
size check */
sMemOpen( &nullStream, NULL, 0 );
status = writeKEKInfo( &nullStream, iExportContext, buffer,
dummyDataSize );
*encryptedKeyLength = stell( &nullStream );
sMemClose( &nullStream );
return( status );
}
/* Load an IV into the exporting context. This is somewhat nasty in that
a side-effect of exporting a key is to load an IV into the exporting
context which isn't really part of the function's job description.
The alternative is to require the user to explicitly load an IV before
exporting the key, which is equally nasty (they'll never remember).
The lesser of the two evils is to load the IV here and assume that
anyone loading the IV themselves will read the docs which warn about
the side-effects of exporting a key.
Note that we always load a new IV when we export a key because the
caller may be using the context to exchange multiple keys. Since each
exported key requires its own IV, we perform an unconditional reload.
In addition because we don't want another thread coming along and
changing the IV while we're in the process of encrypting with it, we
lock the exporting key object until the encryption has completed and
the IV is written to the output */
krnlSendNotifier( iExportContext, RESOURCE_IMESSAGE_LOCK );
if( ivSize )
krnlSendNotifier( iExportContext, RESOURCE_IMESSAGE_CTX_GENIV );
/* Encrypt the session key and write the result to the output stream */
setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_KEYSIZE + 16,
NULL, 0, iSessionKeyContext, iExportContext,
CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_EXPORT, &mechanismInfo,
MECHANISM_CMS );
if( cryptStatusOK( status ) )
{
STREAM stream;
sMemOpen( &stream, encryptedKey, STREAMSIZE_UNKNOWN );
status = writeKEKInfo( &stream, iExportContext,
mechanismInfo.wrappedData,
mechanismInfo.wrappedDataLength );
*encryptedKeyLength = stell( &stream );
sMemDisconnect( &stream );
}
clearMechanismInfo( &mechanismInfo );
zeroise( buffer, CRYPT_MAX_KEYSIZE + 16 );
krnlSendNotifier( iExportContext, RESOURCE_IMESSAGE_UNLOCK );
return( status );
}
/* Export a public-key encrypted session key */
static int exportPublicKey( void *encryptedKey, int *encryptedKeyLength,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iExportContext,
const void *auxInfo, const int auxInfoLength,
const RECIPIENT_TYPE recipientType )
{
MECHANISM_WRAP_INFO mechanismInfo;
BYTE buffer[ CRYPT_MAX_PKCSIZE ];
int keySize, status;
krnlSendMessage( iSessionKeyContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&keySize, CRYPT_CTXINFO_KEYSIZE );
/* If we're just doing a length check, write the data to a null stream
and return its length */
if( encryptedKey == NULL )
{
STREAM nullStream;
int dummyDataSize;
/* Calculate the eventual encrypted key size */
setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0,
iSessionKeyContext, iExportContext,
CRYPT_UNUSED );
status = krnlSendMessage( iExportContext, RESOURCE_IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_PKCS1 );
dummyDataSize = mechanismInfo.wrappedDataLength;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
return( status );
/* Write the data to a null stream to determine its size. The
buffer doesn't contain anything useful since it's only used for a
size check */
sMemOpen( &nullStream, NULL, 0 );
status = writeKeyTransInfo( &nullStream, iExportContext, buffer,
dummyDataSize, auxInfo, auxInfoLength, recipientType );
if( cryptStatusOK( status ) )
*encryptedKeyLength = stell( &nullStream );
sMemClose( &nullStream );
return( status );
}
/* Encrypt the session key and write the result to the output stream */
setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_PKCSIZE, NULL, 0,
iSessionKeyContext, iExportContext, CRYPT_UNUSED );
status = krnlSendMessage( iExportContext, RESOURCE_IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_PKCS1 );
if( cryptStatusOK( status ) )
{
STREAM stream;
sMemOpen( &stream, encryptedKey, STREAMSIZE_UNKNOWN );
status = writeKeyTransInfo( &stream, iExportContext,
mechanismInfo.wrappedData,
mechanismInfo.wrappedDataLength,
auxInfo, auxInfoLength, recipientType );
if( cryptStatusOK( status ) )
*encryptedKeyLength = stell( &stream );
sMemDisconnect( &stream );
}
clearMechanismInfo( &mechanismInfo );
/* Clean up */
return( status );
}
/* Export a key agreement key */
static int exportKeyAgreeKey( void *encryptedKey, int *encryptedKeyLength,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iExportContext,
const CRYPT_CONTEXT iAuxContext,
const void *auxInfo, const int auxInfoLength )
{
CRYPT_ALGO keyAgreeAlgo;
MECHANISM_WRAP_INFO mechanismInfo;
BYTE buffer[ CRYPT_MAX_PKCSIZE ];
int wrappedKeyLen, ukmLen, status;
/* Extract general information */
status = krnlSendMessage( iExportContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&keyAgreeAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) && keyAgreeAlgo == CRYPT_ALGO_DH )
status = CRYPT_ERROR_PARAM4;
if( cryptStatusError( status ) )
return( status );
/* If we're just doing a length check, write the data to a null stream
and return its length */
if( encryptedKey == NULL )
{
STREAM nullStream;
/* Calculate the eventual encrypted key size */
setMechanismWrapInfo( &mechanismInfo, NULL, 0,
NULL, 0, iSessionKeyContext, iExportContext,
iAuxContext );
status = krnlSendMessage( iExportContext, RESOURCE_IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_KEA );
wrappedKeyLen = mechanismInfo.wrappedDataLength >> 8;
ukmLen = mechanismInfo.wrappedDataLength & 0xFF;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
return( status );
/* Write the data to a null stream to determine its size. The
buffer doesn't contain anything useful since it's only used for a
size check */
sMemOpen( &nullStream, NULL, 0 );
status = writeKeyAgreeInfo( &nullStream, iExportContext,
buffer, wrappedKeyLen, buffer,
ukmLen, auxInfo, auxInfoLength );
if( cryptStatusOK( status ) )
*encryptedKeyLength = stell( &nullStream );
sMemClose( &nullStream );
return( status );
}
/* Export the session key and write the result to the output stream */
setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_PKCSIZE,
NULL, 0, iSessionKeyContext, iExportContext,
iAuxContext );
status = krnlSendMessage( iExportContext, RESOURCE_IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_KEA );
if( cryptStatusOK( status ) )
{
STREAM stream;
/* Extract the length information */
wrappedKeyLen = mechanismInfo.wrappedDataLength >> 8;
ukmLen = mechanismInfo.wrappedDataLength & 0xFF;
sMemOpen( &stream, encryptedKey, STREAMSIZE_UNKNOWN );
status = writeKeyAgreeInfo( &stream, iExportContext, buffer,
wrappedKeyLen, buffer, ukmLen, auxInfo,
auxInfoLength );
if( cryptStatusOK( status ) )
*encryptedKeyLength = stell( &stream );
sMemDisconnect( &stream );
}
clearMechanismInfo( &mechanismInfo );
/* Clean up */
zeroise( buffer, CRYPT_MAX_PKCSIZE );
return( status );
}
/****************************************************************************
* *
* Low-level Key Import Functions *
* *
****************************************************************************/
/* Import a conventionally encrypted session key */
static int importConventionalKey( const void *encryptedKey,
const int encryptedKeyLength,
const CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_CONTEXT iImportContext )
{
CRYPT_ALGO cryptAlgo;
CRYPT_MODE cryptMode;
MECHANISM_WRAP_INFO mechanismInfo;
QUERY_INFO queryInfo;
RESOURCE_DATA msgData;
STREAM stream;
int status;
/* Get information on the importing key */
krnlSendMessage( iImportContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
status = krnlSendMessage( iImportContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptMode, CRYPT_CTXINFO_MODE );
if( cryptStatusError( status ) )
return( 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 */
sMemConnect( &stream, encryptedKey, encryptedKeyLength );
status = readKEKInfo( &stream, &queryInfo );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
if( cryptAlgo != queryInfo.cryptAlgo || cryptMode != queryInfo.cryptMode )
return( CRYPT_ARGERROR_NUM1 );
/* 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
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -