📄 cryptctx.c
字号:
/****************************************************************************
* *
* cryptlib Encryption Context Routines *
* Copyright Peter Gutmann 1992-2005 *
* *
****************************************************************************/
/* "Modern cryptography is nothing more than a mathematical framework for
debating the implications of various paranoid delusions"
- Don Alvarez */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PKC_CONTEXT /* Indicate that we're working with PKC context */
#include "crypt.h"
#ifdef INC_ALL
#include "context.h"
#include "asn1.h"
#else
#include "context/context.h"
#include "misc/asn1.h"
#endif /* Compiler-specific includes */
/* The default size of the salt for PKCS #5v2 key derivation, needed when we
set the CRYPT_CTXINFO_KEYING_VALUE */
#define PKCS5_SALT_SIZE 8 /* 64 bits */
/* The number of bytes of data that we check to make sure the encryption
operation succeeded (see the comment in encryptData() before changing
this) */
#define ENCRYPT_CHECKSIZE 16
/* Prototypes for functions in ctx_misc.c */
const CAPABILITY_INFO FAR_BSS *findCapabilityInfo(
const CAPABILITY_INFO_LIST *capabilityInfoList,
const CRYPT_ALGO_TYPE cryptAlgo );
/* Prototypes for functions in keyload.c */
void initKeyHandling( CONTEXT_INFO *contextInfoPtr );
int initKeyParams( CONTEXT_INFO *contextInfoPtr, const void *iv,
const int ivLength, const CRYPT_MODE_TYPE mode );
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Exit after setting extended error information */
static int exitError( CONTEXT_INFO *contextInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus,
const CRYPT_ERRTYPE_TYPE errorType, const int status )
{
setErrorInfo( contextInfoPtr, errorLocus, errorType );
return( status );
}
static int exitErrorInited( CONTEXT_INFO *contextInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
return( exitError( contextInfoPtr, errorLocus,
CRYPT_ERRTYPE_ATTR_PRESENT, CRYPT_ERROR_INITED ) );
}
static int exitErrorNotInited( CONTEXT_INFO *contextInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
return( exitError( contextInfoPtr, errorLocus,
CRYPT_ERRTYPE_ATTR_ABSENT, CRYPT_ERROR_NOTINITED ) );
}
static int exitErrorNotFound( CONTEXT_INFO *contextInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
return( exitError( contextInfoPtr, errorLocus,
CRYPT_ERRTYPE_ATTR_ABSENT, CRYPT_ERROR_NOTFOUND ) );
}
/* Convert a key attribute type into a key format type */
static int attributeToFormatType( const CRYPT_ATTRIBUTE_TYPE attribute )
{
switch( attribute )
{
case CRYPT_IATTRIBUTE_KEY_SSH1:
return( KEYFORMAT_SSH1 );
case CRYPT_IATTRIBUTE_KEY_SSH2:
return( KEYFORMAT_SSH2 );
case CRYPT_IATTRIBUTE_KEY_SSL:
return( KEYFORMAT_SSL );
case CRYPT_IATTRIBUTE_KEY_PGP:
case CRYPT_IATTRIBUTE_KEY_PGP_PARTIAL:
return( KEYFORMAT_PGP );
case CRYPT_IATTRIBUTE_KEY_SPKI:
case CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL:
return( KEYFORMAT_CERT );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Clear temporary bignum values used during PKC operations */
void clearTempBignums( PKC_INFO *pkcInfo )
{
BN_clear( &pkcInfo->tmp1 );
BN_clear( &pkcInfo->tmp2 );
BN_clear( &pkcInfo->tmp3 );
BN_CTX_clear( pkcInfo->bnCTX );
}
/****************************************************************************
* *
* Misc. Context Functions *
* *
****************************************************************************/
/* Initialise pointers to context-specific storage areas */
static void initContextStorage( CONTEXT_INFO *contextInfoPtr,
const int storageSize )
{
switch( contextInfoPtr->type )
{
case CONTEXT_CONV:
contextInfoPtr->ctxConv = ( CONV_INFO * ) contextInfoPtr->storage;
contextInfoPtr->ctxConv->key = contextInfoPtr->storage + storageSize;
break;
case CONTEXT_HASH:
contextInfoPtr->ctxHash = ( HASH_INFO * ) contextInfoPtr->storage;
contextInfoPtr->ctxHash->hashInfo = contextInfoPtr->storage + storageSize;
break;
case CONTEXT_MAC:
contextInfoPtr->ctxMAC = ( MAC_INFO * ) contextInfoPtr->storage;
contextInfoPtr->ctxMAC->macInfo = contextInfoPtr->storage + storageSize;
break;
case CONTEXT_PKC:
contextInfoPtr->ctxPKC = ( PKC_INFO * ) contextInfoPtr->storage;
break;
}
}
/* Perform any context-specific checks that a context meets the given
requirements (general checks have already been performed by the kernel).
Although these checks are automatically performed by the kernel when we
try and use the context, they're duplicated here to allow for better
error reporting by catching problems when the context is first passed to
a cryptlib function rather than much later and at a lower level when the
kernel disallows the action */
static int checkContext( CONTEXT_INFO *contextInfoPtr,
const MESSAGE_CHECK_TYPE checkType )
{
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
/* If it's a check that an object's ready for key generation (which is
algorithm-type independent), we check it before performing any
algorithm-specific checks */
if( checkType == MESSAGE_CHECK_KEYGEN_READY )
{
if( !needsKey( contextInfoPtr ) )
return( exitErrorInited( contextInfoPtr, CRYPT_CTXINFO_KEY ) );
return( CRYPT_OK );
}
/* If it's a check for the (potential) ability to perform conventional
encryption or MAC'ing at some point in the future, without currently
having a key loaded for the task, we're done */
if( checkType == MESSAGE_CHECK_CRYPT_READY || \
checkType == MESSAGE_CHECK_MAC_READY )
return( CRYPT_OK );
/* Perform general checks */
if( contextInfoPtr->type != CONTEXT_HASH && needsKey( contextInfoPtr ) )
return( exitErrorNotInited( contextInfoPtr, CRYPT_CTXINFO_KEY ) );
/* If it's a hash, MAC, conventional encryption, or basic PKC check,
we're done */
if( checkType == MESSAGE_CHECK_CRYPT || \
checkType == MESSAGE_CHECK_HASH || \
checkType == MESSAGE_CHECK_MAC || \
checkType == MESSAGE_CHECK_PKC )
return( CRYPT_OK );
/* Check for key-agreement algorithms */
if( isKeyxAlgo( capabilityInfoPtr->cryptAlgo ) )
/* DH can never be used for encryption or signatures (if it is then
we call it Elgamal) and KEA is explicitly for key agreement only.
Note that the status of DH is a bit ambiguous in that every DH key
is both a public and private key, in order to avoid confusion in
situations where we're checking for real private keys we always
denote a DH context as key-agreement only without taking a side
about whether it's a public or private key */
return( ( checkType == MESSAGE_CHECK_PKC_KA_EXPORT || \
checkType == MESSAGE_CHECK_PKC_KA_IMPORT ) ? \
CRYPT_OK : CRYPT_ARGERROR_OBJECT );
if( checkType == MESSAGE_CHECK_PKC_KA_EXPORT || \
checkType == MESSAGE_CHECK_PKC_KA_IMPORT )
return( CRYPT_ARGERROR_OBJECT ); /* Must be a key agreement algorithm */
/* We're down to various public-key checks */
assert( checkType == MESSAGE_CHECK_PKC_PRIVATE || \
checkType == MESSAGE_CHECK_PKC_ENCRYPT || \
checkType == MESSAGE_CHECK_PKC_DECRYPT || \
checkType == MESSAGE_CHECK_PKC_SIGCHECK || \
checkType == MESSAGE_CHECK_PKC_SIGN || \
checkType == MESSAGE_CHECK_CA );
/* Check that it's a private key if this is required */
if( ( checkType == MESSAGE_CHECK_PKC_PRIVATE || \
checkType == MESSAGE_CHECK_PKC_DECRYPT || \
checkType == MESSAGE_CHECK_PKC_SIGN ) && \
( contextInfoPtr->flags & CONTEXT_ISPUBLICKEY ) )
return( CRYPT_ARGERROR_OBJECT );
return( CRYPT_OK );
}
/* Derive a key into a context from a user-supplied keying value */
static int deriveKey( CONTEXT_INFO *contextInfoPtr, void *keyValue,
const int keyValueLen )
{
MECHANISM_DERIVE_INFO mechanismInfo;
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( contextInfoPtr->type == CONTEXT_CONV || \
contextInfoPtr->type == CONTEXT_MAC );
assert( needsKey( contextInfoPtr ) );
assert( isReadPtr( keyValue, keyValueLen ) );
/* Set up various derivation parameters if they're not already set.
Since there's only one MUST MAC algorithm for PKCS #5v2, we always
force the key derivation algorithm to this value to avoid interop
problems */
if( contextInfoPtr->type == CONTEXT_CONV )
{
CONV_INFO *convInfo = contextInfoPtr->ctxConv;
if( convInfo->saltLength <= 0 )
{
RESOURCE_DATA nonceMsgData;
setMessageData( &nonceMsgData, convInfo->salt, PKCS5_SALT_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &nonceMsgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
convInfo->saltLength = PKCS5_SALT_SIZE;
}
convInfo->keySetupAlgorithm = CRYPT_ALGO_HMAC_SHA;
setMechanismDeriveInfo( &mechanismInfo, convInfo->userKey,
capabilityInfoPtr->getInfoFunction( CAPABILITY_INFO_KEYSIZE,
contextInfoPtr, convInfo->userKeyLength ),
keyValue, keyValueLen, convInfo->keySetupAlgorithm,
convInfo->salt, convInfo->saltLength,
convInfo->keySetupIterations );
if( mechanismInfo.iterations <= 0 )
{
krnlSendMessage( contextInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&mechanismInfo.iterations,
CRYPT_OPTION_KEYING_ITERATIONS );
convInfo->keySetupIterations = mechanismInfo.iterations;
}
}
else
{
MAC_INFO *macInfo = contextInfoPtr->ctxMAC;
if( macInfo->saltLength <= 0 )
{
RESOURCE_DATA nonceMsgData;
setMessageData( &nonceMsgData, macInfo->salt, PKCS5_SALT_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &nonceMsgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
macInfo->saltLength = PKCS5_SALT_SIZE;
}
contextInfoPtr->ctxConv->keySetupAlgorithm = CRYPT_ALGO_HMAC_SHA;
setMechanismDeriveInfo( &mechanismInfo, macInfo->userKey,
capabilityInfoPtr->getInfoFunction( CAPABILITY_INFO_KEYSIZE,
contextInfoPtr, macInfo->userKeyLength ),
keyValue, keyValueLen, macInfo->keySetupAlgorithm,
macInfo->salt, macInfo->saltLength,
macInfo->keySetupIterations );
if( mechanismInfo.iterations <= 0 )
{
krnlSendMessage( contextInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&mechanismInfo.iterations,
CRYPT_OPTION_KEYING_ITERATIONS );
macInfo->keySetupIterations = mechanismInfo.iterations;
}
}
/* Turn the user key into an encryption context key and load the key
into the context */
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_DERIVE_PKCS5 );
if( cryptStatusOK( status ) )
status = contextInfoPtr->loadKeyFunction( contextInfoPtr,
mechanismInfo.dataOut,
mechanismInfo.dataOutLength );
if( cryptStatusOK( status ) )
{
contextInfoPtr->flags |= CONTEXT_KEY_SET | CONTEXT_EPHEMERAL;
if( contextInfoPtr->type == CONTEXT_MAC )
contextInfoPtr->flags |= CONTEXT_HASH_INITED;
}
return( status );
}
/* Load an encoded composite key into a context. This is used for two
purposes, to load public key components into native contexts and to save
encoded public-key values for use in certs associated with non-native
contexts held in a device. The latter is necessary because there's no
key data stored with the context itself, however it's necessary to have
SubjectPublicKeyInfo available for certificate requests/certificates.
Normally this is sufficient because cryptlib always generates native
contexts for public keys/certs, and for private keys the data is generated
in the device with the encoded public components attached to the context
as described above.
For DH keys this gets a bit more complex, since although the private key
is generated in the device, in the case of the DH responder this is only
the DH x value, with the parameters (p and g) being supplied externally
by the initiator. This means that it's necessary to decode at least some
of the public key data in order to create the y value after the x value
has been generated in the device.
The only situation where this functionality is currently needed is for the
SSHv2 code, which at the moment always uses native DH contexts. For this
reason we leave off resolving this issue until it's actually required */
static int setKey( CONTEXT_INFO *contextInfoPtr,
const CRYPT_ATTRIBUTE_TYPE keyType, const void *keyData,
const int keyDataLen )
{
static const int actionFlags = \
MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL ) | \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -