📄 cryptctx.c
字号:
/****************************************************************************
* *
* cryptlib Encryption Context Routines *
* Copyright Peter Gutmann 1992-2008 *
* *
****************************************************************************/
/* "Modern cryptography is nothing more than a mathematical framework for
debating the implications of various paranoid delusions"
- Don Alvarez */
#define PKC_CONTEXT /* Indicate that we're working with PKC contexts */
#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 number of bytes of data that we check to make sure that the
encryption operation succeeded. See the comment in encryptData() before
changing this */
#define ENCRYPT_CHECKSIZE 16
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Initialise pointers to context-specific storage areas */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int initContextStorage( INOUT CONTEXT_INFO *contextInfoPtr,
IN_LENGTH_SHORT_Z const int storageSize )
{
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
REQUIRES( ( contextInfoPtr->type == CONTEXT_PKC && \
storageSize == sizeof( PKC_INFO ) ) || \
( contextInfoPtr->type != CONTEXT_PKC && \
storageSize >= 16 && storageSize < MAX_INTLENGTH_SHORT ) );
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;
}
return( CRYPT_OK );
}
/* 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkContext( INOUT CONTEXT_INFO *contextInfoPtr,
IN_ENUM( MESSAGE_CHECK ) \
const MESSAGE_CHECK_TYPE checkType )
{
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
REQUIRES( checkType > MESSAGE_CHECK_NONE && \
checkType < MESSAGE_CHECK_LAST );
/* If it's a check that an object's ready for key generation we can
perform the check without requiring any algorithm-specific
gyrations */
if( checkType == MESSAGE_CHECK_KEYGEN_READY )
{
/* Make sure that there isn't already a key loaded */
if( !needsKey( contextInfoPtr ) )
return( CRYPT_ERROR_INITED );
/* Make sure that we can actually generate a key. This should be
enforced by the kernel anyway but we use a backup check here */
if( capabilityInfoPtr->generateKeyFunction == NULL )
return( CRYPT_ERROR_NOTAVAIL );
return( CRYPT_OK );
}
/* If it's a check for the (potential) ability to perform conventional
encryption or MACing at some point in the future, without necessarily
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( CRYPT_ERROR_NOTINITED );
/* 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 )
{
/* A key agreement check requires a key agreement algorithm */
return( CRYPT_ARGERROR_OBJECT );
}
/* We're down to various public-key checks */
REQUIRES( 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_FLAG_ISPUBLICKEY ) )
return( CRYPT_ARGERROR_OBJECT );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Data Encryption Functions *
* *
****************************************************************************/
/* Encrypt a block of data */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int encryptDataConv( INOUT CONTEXT_INFO *contextInfoPtr,
IN_BUFFER( dataLength ) void *data,
IN_LENGTH_Z const int dataLength )
{
BYTE savedData[ ENCRYPT_CHECKSIZE + 8 ];
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
const int savedDataLength = min( dataLength, ENCRYPT_CHECKSIZE );
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( data, dataLength ) );
REQUIRES( contextInfoPtr->type == CONTEXT_CONV );
REQUIRES( !needsKey( contextInfoPtr ) );
REQUIRES( dataLength >= 0 && dataLength < MAX_INTLENGTH );
REQUIRES( isStreamCipher( capabilityInfoPtr->cryptAlgo ) || \
!needsIV( contextInfoPtr->ctxConv->mode ) ||
( contextInfoPtr->flags & CONTEXT_FLAG_IV_SET ) );
REQUIRES( contextInfoPtr->ctxConv->key == \
contextInfoPtr->storage + sizeof( CONV_INFO ) );
memcpy( savedData, data, savedDataLength );
status = contextInfoPtr->encryptFunction( contextInfoPtr, data,
dataLength );
if( cryptStatusError( status ) || savedDataLength <= 8 )
{
zeroise( savedData, savedDataLength );
return( status );
}
/* Check for a catastrophic failure of the encryption. A check of
a single block unfortunately isn't completely foolproof for 64-bit
blocksize ciphers in CBC mode because of the way the IV is applied to
the input. For the CBC encryption operation:
out = enc( in ^ IV )
if out == IV the operation turns into a no-op. Consider the simple
case where IV == in, so IV ^ in == 0. Then out = enc( 0 ) == IV,
with the input appearing again at the output. In fact for a 64-bit
block cipher this can occur during normal operation once every 2^32
blocks. Although the chances of this happening are fairly low (the
collision would have to occur on the first encrypted block in a
message since that's the one that we check), we check the first two
blocks if we're using a 64-bit block cipher in CBC mode in order to
reduce false positives */
if( !memcmp( savedData, data, savedDataLength ) )
{
zeroise( data, dataLength );
status = CRYPT_ERROR_FAILED;
}
zeroise( savedData, savedDataLength );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int encryptDataPKC( INOUT CONTEXT_INFO *contextInfoPtr,
IN_BUFFER( dataLength ) void *data,
IN_LENGTH_PKC const int dataLength )
{
BYTE savedData[ ENCRYPT_CHECKSIZE + 8 ];
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
const BOOLEAN isDLP = isDlpAlgo( capabilityInfoPtr->cryptAlgo );
const BOOLEAN isECC = isEccAlgo( capabilityInfoPtr->cryptAlgo );
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( data, dataLength ) );
REQUIRES( contextInfoPtr->type == CONTEXT_PKC );
REQUIRES( !needsKey( contextInfoPtr ) );
/* Key agreement algorithms are treated as a special case since they
don't actually encrypt the data */
if( isKeyxAlgo( capabilityInfoPtr->cryptAlgo ) )
{
REQUIRES( dataLength == sizeof( KEYAGREE_PARAMS ) );
status = contextInfoPtr->encryptFunction( contextInfoPtr, data,
dataLength );
if( !( contextInfoPtr->flags & CONTEXT_FLAG_DUMMY ) )
clearTempBignums( contextInfoPtr->ctxPKC );
return( status );
}
REQUIRES( ( ( isDLP || isECC ) && \
dataLength == sizeof( DLP_PARAMS ) ) || \
( ( !isDLP && !isECC ) && \
dataLength >= MIN_PKCSIZE && \
dataLength <= CRYPT_MAX_PKCSIZE ) );
memcpy( savedData, ( isDLP || isECC ) ? \
( ( DLP_PARAMS * ) data )->inParam1 : data,
ENCRYPT_CHECKSIZE );
status = contextInfoPtr->encryptFunction( contextInfoPtr, data,
dataLength );
if( !( contextInfoPtr->flags & CONTEXT_FLAG_DUMMY ) )
clearTempBignums( contextInfoPtr->ctxPKC );
if( cryptStatusError( status ) )
{
zeroise( savedData, ENCRYPT_CHECKSIZE );
return( status );
}
/* Check for a catastrophic failure of the encryption */
if( isDLP || isECC )
{
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) data;
if( !memcmp( savedData, dlpParams->outParam,
ENCRYPT_CHECKSIZE ) )
{
zeroise( dlpParams->outParam, dlpParams->outLen );
status = CRYPT_ERROR_FAILED;
}
}
else
{
if( !memcmp( savedData, data, ENCRYPT_CHECKSIZE ) )
{
zeroise( data, dataLength );
status = CRYPT_ERROR_FAILED;
}
}
zeroise( savedData, ENCRYPT_CHECKSIZE );
return( status );
}
/****************************************************************************
* *
* Context Message Handler *
* *
****************************************************************************/
/* Handle a message sent to an encryption context */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int contextMessageFunction( INOUT TYPECAST( CONTEXT_INFO * ) \
void *objectInfoPtr,
IN_MESSAGE const MESSAGE_TYPE message,
void *messageDataPtr,
IN_INT_Z const int messageValue )
{
CONTEXT_INFO *contextInfoPtr = ( CONTEXT_INFO * ) objectInfoPtr;
const CAPABILITY_INFO *capabilityInfo = contextInfoPtr->capabilityInfo;
int status;
assert( isWritePtr( objectInfoPtr, sizeof( CONTEXT_INFO ) ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -