📄 crypt.c
字号:
/****************************************************************************
* *
* cryptlib Encryption Context Routines *
* Copyright Peter Gutmann 1992-2002 *
* *
****************************************************************************/
/* "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>
#include "crypt.h"
#include "cryptctx.h"
#ifdef INC_ALL
#include "asn1.h"
#else
#include "keymgmt/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 */
/* Prototypes for functions in cryptkey.c */
BOOLEAN needsKey( const CRYPT_INFO *cryptInfoPtr );
int getOptimalKeysize( CRYPT_INFO *cryptInfoPtr,
const int requestedKeyLength );
int generateKey( CRYPT_INFO *cryptInfoPtr, const BOOLEAN isAsync );
int loadKey( CRYPT_INFO *cryptInfoPtr, BYTE *key, const int keyLength );
/* Prototypes for functions in asn1keys.c */
int writePublicKey( STREAM *stream, const CRYPT_INFO *cryptInfoPtr );
int writeSsh1PublicKey( STREAM *stream, const CRYPT_INFO *cryptInfoPtr );
int writeSsh2PublicKey( STREAM *stream, const CRYPT_INFO *cryptInfoPtr );
int readSsh1PublicKey( STREAM *stream, CRYPT_INFO *cryptInfoPtr );
int readSsh2PublicKey( STREAM *stream, CRYPT_INFO *cryptInfoPtr );
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check that a capability info record is consistent. This is a complex
function which is called from an assert() macro, so we only need to define
it when we're building a debug version */
#ifndef NDEBUG
BOOLEAN capabilityInfoOK( const CAPABILITY_INFO *capabilityInfoPtr,
const BOOLEAN asymmetricOK )
{
CRYPT_ALGO cryptAlgo = capabilityInfoPtr->cryptAlgo;
/* Check the algorithm and mode parameters */
if( cryptAlgo <= CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST_MAC || \
capabilityInfoPtr->algoName == NULL )
return( FALSE );
/* Make sure that the minimum functions are present */
if( isStreamCipher( cryptAlgo ) )
{
if( capabilityInfoPtr->encryptOFBFunction == NULL || \
capabilityInfoPtr->decryptOFBFunction == NULL )
return( FALSE );
}
else
if( asymmetricOK )
{
/* If asymmetric capabilities (eg decrypt but not encrypt,
present in some tinkertoy tokens) are OK, we only check
that there's at least one useful capability available */
if( capabilityInfoPtr->decryptFunction == NULL && \
capabilityInfoPtr->signFunction == NULL )
return( FALSE );
}
else
if( ( capabilityInfoPtr->encryptFunction == NULL || \
capabilityInfoPtr->decryptFunction == NULL ) && \
( capabilityInfoPtr->signFunction == NULL || \
capabilityInfoPtr->sigCheckFunction == NULL ) )
return( FALSE );
/* Make sure the algorithm/mode names will fit inside the query
information structure */
if( strlen( capabilityInfoPtr->algoName ) > CRYPT_MAX_TEXTSIZE - 1 )
return( FALSE );
/* Make sure the algorithm/mode-specific parameters are consistent */
if( capabilityInfoPtr->minKeySize > capabilityInfoPtr->keySize || \
capabilityInfoPtr->maxKeySize < capabilityInfoPtr->keySize )
return( FALSE );
if( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL )
{
if( ( capabilityInfoPtr->blockSize < bitsToBytes( 8 ) || \
capabilityInfoPtr->blockSize > CRYPT_MAX_IVSIZE ) || \
( capabilityInfoPtr->minKeySize < bitsToBytes( 40 ) || \
capabilityInfoPtr->keySize < bitsToBytes( 40 ) || \
capabilityInfoPtr->keySize > CRYPT_MAX_KEYSIZE || \
capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
return( FALSE );
if( !isStreamCipher( cryptAlgo ) && \
( capabilityInfoPtr->initIVFunction == NULL || \
capabilityInfoPtr->blockSize < bitsToBytes( 64 ) ) )
return( FALSE );
if( capabilityInfoPtr->initKeyFunction == NULL )
return( FALSE );
if( ( capabilityInfoPtr->encryptCBCFunction != NULL && \
capabilityInfoPtr->decryptCBCFunction == NULL ) || \
( capabilityInfoPtr->encryptCBCFunction == NULL && \
capabilityInfoPtr->decryptCBCFunction != NULL ) )
return( FALSE );
if( ( capabilityInfoPtr->encryptCFBFunction != NULL && \
capabilityInfoPtr->decryptCFBFunction == NULL ) || \
( capabilityInfoPtr->encryptCFBFunction == NULL && \
capabilityInfoPtr->decryptCFBFunction != NULL ) )
return( FALSE );
if( ( capabilityInfoPtr->encryptOFBFunction != NULL && \
capabilityInfoPtr->decryptOFBFunction == NULL ) || \
( capabilityInfoPtr->encryptOFBFunction == NULL && \
capabilityInfoPtr->decryptOFBFunction != NULL ) )
return( FALSE );
}
if( cryptAlgo >= CRYPT_ALGO_FIRST_PKC && \
cryptAlgo <= CRYPT_ALGO_LAST_PKC )
{
if( capabilityInfoPtr->blockSize || \
( capabilityInfoPtr->minKeySize < bitsToBytes( 512 ) || \
capabilityInfoPtr->keySize < bitsToBytes( 512 ) || \
capabilityInfoPtr->keySize > CRYPT_MAX_PKCSIZE || \
capabilityInfoPtr->maxKeySize > CRYPT_MAX_PKCSIZE ) )
return( FALSE );
if( capabilityInfoPtr->initKeyFunction == NULL )
return( FALSE );
}
if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH && \
cryptAlgo <= CRYPT_ALGO_LAST_HASH )
{
if( ( capabilityInfoPtr->blockSize < bitsToBytes( 64 ) || \
capabilityInfoPtr->blockSize > 256 ) || \
( capabilityInfoPtr->minKeySize || capabilityInfoPtr->keySize || \
capabilityInfoPtr->maxKeySize ) )
return( FALSE );
}
if( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC )
{
if( ( capabilityInfoPtr->blockSize < bitsToBytes( 64 ) || \
capabilityInfoPtr->blockSize > 256 ) || \
( capabilityInfoPtr->minKeySize < bitsToBytes( 40 ) || \
capabilityInfoPtr->keySize < bitsToBytes( 40 ) || \
capabilityInfoPtr->keySize > CRYPT_MAX_KEYSIZE || \
capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
return( FALSE );
if( capabilityInfoPtr->initKeyFunction == NULL )
return( FALSE );
}
return( TRUE );
}
#endif /* !NDEBUG */
/* Copy information from a capability record to a query record */
void copyCapabilityInfo( const CAPABILITY_INFO FAR_BSS *capabilityInfoPtr,
CRYPT_QUERY_INFO *cryptQueryInfo )
{
memset( cryptQueryInfo, 0, sizeof( CRYPT_QUERY_INFO ) );
strcpy( cryptQueryInfo->algoName, capabilityInfoPtr->algoName );
cryptQueryInfo->blockSize = capabilityInfoPtr->blockSize;
cryptQueryInfo->minKeySize = capabilityInfoPtr->minKeySize;
cryptQueryInfo->keySize = capabilityInfoPtr->keySize;
cryptQueryInfo->maxKeySize = capabilityInfoPtr->maxKeySize;
}
/* Find the capability record for a given encryption algorithm */
const CAPABILITY_INFO FAR_BSS *findCapabilityInfo(
const CAPABILITY_INFO FAR_BSS *capabilityInfoList,
const CRYPT_ALGO cryptAlgo )
{
const CAPABILITY_INFO *capabilityInfoPtr;
/* Find the capability corresponding to the requested algorithm/mode */
for( capabilityInfoPtr = capabilityInfoList;
capabilityInfoPtr != NULL;
capabilityInfoPtr = capabilityInfoPtr->next )
if( capabilityInfoPtr->cryptAlgo == cryptAlgo )
return( capabilityInfoPtr );
return( NULL );
}
/* Load an IV, shared by most capabilities */
int loadIV( CRYPT_INFO *cryptInfoPtr, const void *iv, const int ivLength )
{
const int ivSize = ( ivLength == CRYPT_USE_DEFAULT ) ? \
cryptInfoPtr->capabilityInfo->blockSize : ivLength;
/* Load the IV of the required length. If the required IV size is less
than the maximum possible IV size, we pad it to the right with
zeroes */
cryptInfoPtr->ctxConv.ivLength = ivSize;
cryptInfoPtr->ctxConv.ivCount = 0;
memset( cryptInfoPtr->ctxConv.iv, 0, CRYPT_MAX_IVSIZE );
memcpy( cryptInfoPtr->ctxConv.iv, iv, ivSize );
memcpy( cryptInfoPtr->ctxConv.currentIV, cryptInfoPtr->ctxConv.iv,
CRYPT_MAX_IVSIZE );
cryptInfoPtr->ctxConv.ivSet = TRUE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Encryption Context Management Functions *
* *
****************************************************************************/
/* Create a deep clone of a conventional encryption or hash/MAC context.
This code is used when it's necessary to create a local copy of a context
the caller has passed in */
static int contextMessageFunction( const CRYPT_CONTEXT cryptContext,
const RESOURCE_MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue );
static int cloneContext( CRYPT_CONTEXT *iDestContext,
const CRYPT_CONTEXT srcContext )
{
CRYPT_INFO *srcInfoPtr, *destInfoPtr;
CONTEXT_TYPE contextType;
void *keyPtr = NULL, *privateDataPtr = NULL;
int status, actionFlags, subType;
/* Get the action permissions for the source object */
status = krnlSendMessage( srcContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&actionFlags, CRYPT_IATTRIBUTE_ACTIONPERMS );
if( cryptStatusError( status ) )
return( status );
getCheckInternalResource( srcContext, srcInfoPtr, OBJECT_TYPE_CONTEXT );
contextType = srcInfoPtr->type;
assert( contextType == CONTEXT_CONV || \
contextType == CONTEXT_HASH || \
contextType == CONTEXT_MAC );
subType = ( contextType == CONTEXT_CONV ) ? SUBTYPE_CTX_CONV : \
( contextType == CONTEXT_HASH ) ? SUBTYPE_CTX_HASH : SUBTYPE_CTX_MAC;
/* We need to preallocate all required memory so we can check for
allocation failures before we copy the source context because undoing
the shallow cloning of the context isn't easily possible */
if( contextType == CONTEXT_CONV && srcInfoPtr->ctxConv.key != NULL )
{
const int size = krnlMemsize( srcInfoPtr->ctxConv.key );
status = krnlMemalloc( &keyPtr, size );
if( cryptStatusOK( status ) )
memcpy( keyPtr, srcInfoPtr->ctxConv.key, size );
}
if( contextType == CONTEXT_HASH && srcInfoPtr->ctxHash.hashInfo != NULL )
{
const int size = krnlMemsize( srcInfoPtr->ctxHash.hashInfo );
status = krnlMemalloc( &privateDataPtr, size );
if( cryptStatusOK( status ) )
memcpy( privateDataPtr, srcInfoPtr->ctxHash.hashInfo, size );
}
if( contextType == CONTEXT_MAC && srcInfoPtr->ctxMAC.macInfo != NULL )
{
const int size = krnlMemsize( srcInfoPtr->ctxMAC.macInfo );
status = krnlMemalloc( &privateDataPtr, size );
if( cryptStatusOK( status ) )
memcpy( privateDataPtr, srcInfoPtr->ctxMAC.macInfo, size );
}
if( cryptStatusError( status ) )
unlockResourceExit( srcInfoPtr, status );
/* Create the encryption context object */
status = krnlCreateObject( ( void ** ) &destInfoPtr,
srcInfoPtr->ownerHandle, OBJECT_TYPE_CONTEXT,
subType, sizeof( CRYPT_INFO ),
( needsSecureMemory( srcInfoPtr->type ) ? \
CREATEOBJECT_FLAG_SECUREMALLOC: 0 ),
actionFlags, contextMessageFunction );
if( cryptStatusError( status ) )
{
/* Undo the previous mallocs and exit */
if( keyPtr != NULL )
krnlMemfree( keyPtr );
if( privateDataPtr != NULL )
krnlMemfree( privateDataPtr );
unlockResourceExit( srcInfoPtr, status );
}
initResourceLock( destInfoPtr );
lockResource( destInfoPtr );
*iDestContext = destInfoPtr->objectHandle = status;
/* Now that all the things which could fail have been done, copy across
the shared fields (the expression mimics the offsetof() operator,
which isn't available with all compilers. A more general-purpose
alternative is to use (NULL->fieldName - NULL) (with some casting),
but since we know the structure and field in advance we don't need to
do this).
Since this operation copies over a few items of instance-specific
information, we have to make sure we reset or re-initialise this
information after the block copy */
memcpy( destInfoPtr, srcInfoPtr, ( size_t ) \
( ( BYTE * ) &srcInfoPtr->_sharedEnd - ( BYTE * ) srcInfoPtr ) );
if( contextType == CONTEXT_CONV )
destInfoPtr->ctxConv.key = keyPtr;
if( contextType == CONTEXT_HASH )
destInfoPtr->ctxHash.hashInfo = privateDataPtr;
if( contextType == CONTEXT_MAC )
destInfoPtr->ctxMAC.macInfo = privateDataPtr;
unlockResource( srcInfoPtr );
/* We've finished setting up the object-type-specific info, tell the
kernel the object is ready for use and initialised */
unlockResource( destInfoPtr );
status = krnlSendMessage( *iDestContext, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusOK( status ) )
{
/* Since this is an internal-use-only object, lock down the action
permissions so that only encryption and hash actions from internal
sources are allowed (assuming they were allowed to begin with).
Keygen is disabled entirely (there should already be a key loaded),
and signing isn't possible with a non-PKC object anyway */
actionFlags = \
MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_HASH, ACTION_PERM_NONE_EXTERNAL );
krnlSendMessage( *iDestContext, RESOURCE_IMESSAGE_SETATTRIBUTE,
&actionFlags, CRYPT_IATTRIBUTE_ACTIONPERMS );
status = krnlSendMessage( *iDestContext,
RESOURCE_IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED );
if( cryptStatusError( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -