📄 cryptkey.c
字号:
/****************************************************************************
* *
* cryptlib Keying Routines *
* Copyright Peter Gutmann 1992-2000 *
* *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#include "cryptctx.h"
/****************************************************************************
* *
* Key Load Functions *
* *
****************************************************************************/
/* Determine whether a context needs to have a key loaded */
BOOLEAN needsKey( const CRYPT_INFO *cryptInfoPtr )
{
if( cryptInfoPtr->type == CONTEXT_CONV )
return( !cryptInfoPtr->ctxConv.keySet );
if( cryptInfoPtr->type == CONTEXT_PKC )
return( !cryptInfoPtr->ctxPKC.keySet );
if( cryptInfoPtr->type == CONTEXT_MAC )
return( !cryptInfoPtr->ctxMAC.keySet );
return( FALSE );
}
/* Check that the supplied PKC parameters make sense (algorithm-specific
validity checks are performed at a lower level). Although the checks are
somewhat algorithm-specific, we have to do them at this point in order to
avoid duplicating them in every plug-in PKC module, and because strictly
speaking it's the job of the higher-level code to ensure the lower-level
routines at least get fed approximately valid input */
static int checkPKCparams( const CRYPT_ALGO cryptAlgo, const void *keyInfo )
{
const CRYPT_PKCINFO_RSA *rsaKey = ( CRYPT_PKCINFO_RSA * ) keyInfo;
/* The DLP check is simpler than the RSA one because there are less
odd parameter combinations possible, so we get this one out of the
way first */
if( cryptAlgo != CRYPT_ALGO_RSA )
{
const CRYPT_PKCINFO_DLP *dlpKey = ( CRYPT_PKCINFO_DLP * ) keyInfo;
/* Check the general and public components */
if( ( dlpKey->isPublicKey != TRUE && dlpKey->isPublicKey != FALSE ) )
return( CRYPT_ARGERROR_STR1 );
if( dlpKey->pLen < 510 || dlpKey->pLen > MAX_PKCSIZE_BITS || \
dlpKey->qLen < 128 || dlpKey->qLen > MAX_PKCSIZE_BITS || \
dlpKey->gLen < 2 || dlpKey->gLen > MAX_PKCSIZE_BITS || \
dlpKey->yLen < 0 || dlpKey->yLen > MAX_PKCSIZE_BITS )
/* y may be 0 if only x and the public params are available */
return( CRYPT_ARGERROR_STR1 );
if( dlpKey->isPublicKey )
return( CRYPT_OK );
/* Check the private components */
if( dlpKey->xLen < 128 || dlpKey->xLen > MAX_PKCSIZE_BITS )
return( CRYPT_ARGERROR_STR1 );
return( CRYPT_OK );
}
/* Check the general and public components */
if( rsaKey->isPublicKey != TRUE && rsaKey->isPublicKey != FALSE )
return( CRYPT_ARGERROR_STR1 );
if( rsaKey->nLen < 504 || rsaKey->nLen > MAX_PKCSIZE_BITS || \
rsaKey->eLen < 2 || rsaKey->eLen > MAX_PKCSIZE_BITS )
return( CRYPT_ARGERROR_STR1 );
if( rsaKey->isPublicKey )
return( CRYPT_OK );
/* Check the private components. This can get somewhat complex, possible
combinations are:
d, p, q
d, p, q, e1, e2
p, q, e1, e2
The reason for some of the odder combinations is because some
implementations don't use all the values (for example d isn't needed at
all for the CRT shortcut). If only d, p, and q are present we recreate
e1 and e2 from them, we also create u if necessary */
if( rsaKey->pLen < 240 || rsaKey->pLen > MAX_PKCSIZE_BITS || \
rsaKey->qLen < 240 || rsaKey->qLen > MAX_PKCSIZE_BITS )
return( CRYPT_ARGERROR_STR1 );
if( !rsaKey->dLen && !rsaKey->e1Len )
/* Must have either d or e1 et al */
return( CRYPT_ARGERROR_STR1 );
if( rsaKey->dLen && \
( rsaKey->dLen < 504 || rsaKey->dLen > MAX_PKCSIZE_BITS ) )
return( CRYPT_ARGERROR_STR1 );
if( rsaKey->e1Len && \
( rsaKey->e1Len < 240 || rsaKey->e1Len > MAX_PKCSIZE_BITS || \
rsaKey->e2Len < 240 || rsaKey->e2Len > MAX_PKCSIZE_BITS ) )
return( CRYPT_ARGERROR_STR1 );
if( rsaKey->uLen && \
( rsaKey->uLen < 240 || rsaKey->uLen > MAX_PKCSIZE_BITS ) )
return( CRYPT_ARGERROR_STR1 );
return( CRYPT_OK );
}
/* Load a key into a CRYPT_INFO structure. This function is called by the
various higher-level functions which move a key into a context */
int loadKey( CRYPT_INFO *cryptInfoPtr, BYTE *key, const int keyLength )
{
const CAPABILITY_INFO *capabilityInfoPtr = cryptInfoPtr->capabilityInfo;
int status;
/* If it's a PKC context, load the PKC keying information */
if( cryptInfoPtr->type == CONTEXT_PKC )
{
/* If we're loading from externally-supplied parameters, make sure
the parameters make sense */
if( keyLength != sizeof( PKCINFO_LOADINTERNAL ) )
{
status = checkPKCparams( capabilityInfoPtr->cryptAlgo, key );
if( cryptStatusError( status ) )
return( status );
}
/* Load the keying info */
status = capabilityInfoPtr->initKeyFunction( cryptInfoPtr, key, keyLength );
if( cryptStatusOK( status ) )
cryptInfoPtr->ctxPKC.keySet = TRUE;
return( status );
}
/* If it's a MAC algorithm, load the key */
if( cryptInfoPtr->type == CONTEXT_MAC )
{
status = capabilityInfoPtr->initKeyFunction( cryptInfoPtr, key, keyLength );
if( cryptStatusOK( status ) )
cryptInfoPtr->ctxMAC.keySet = TRUE;
return( status );
}
/* If we don't need an IV, record it as being set */
if( !needsIV( cryptInfoPtr->ctxConv.mode ) || \
isStreamCipher( cryptInfoPtr->capabilityInfo->cryptAlgo ) )
cryptInfoPtr->ctxConv.ivSet = TRUE;
/* Perform the key setup */
assert( capabilityInfoPtr->initKeyFunction != NULL );
status = capabilityInfoPtr->initKeyFunction( cryptInfoPtr, key, keyLength );
if( cryptStatusOK( status ) )
cryptInfoPtr->ctxConv.keySet = TRUE;
return( status );
}
/****************************************************************************
* *
* Key Generation Functions *
* *
****************************************************************************/
/* Threaded key generation for those OS's which support threads. The
following function *must* be called as a thread */
#if defined( __WIN32__ ) || defined( __OS2__ ) || \
( defined( __UNIX__ ) && defined( USE_THREADS ) ) || defined( __BEOS__ )
#define HAS_THREADS /* Enable use of threads throughout this module */
THREADFUNC_DEFINE( threadKeygen, ptr )
{
CRYPT_INFO *cryptInfoPtr = ( CRYPT_INFO * ) ptr;
int busyStatus = CRYPT_ERROR_BUSY;
/* Mark the object as busy, perform the keygen, and set it back to non-
busy */
krnlSendMessage( cryptInfoPtr->objectHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
&busyStatus, CRYPT_IATTRIBUTE_STATUS );
cryptInfoPtr->asyncStatus = \
cryptInfoPtr->capabilityInfo->generateKeyFunction( cryptInfoPtr,
cryptInfoPtr->ctxPKC.keySizeBits );
if( cryptStatusOK( cryptInfoPtr->asyncStatus ) )
cryptInfoPtr->ctxPKC.keySet = TRUE; /* There's now a key loaded */
cryptInfoPtr->doAbort = FALSE;
cryptInfoPtr->done = TRUE;
krnlSendMessage( cryptInfoPtr->objectHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
THREAD_EXIT();
}
#endif /* Threaded keygen function */
/* Determine the optimal size for the generated key. This isn't as easy as
just taking the default key size since some algorithms have variable key
sizes (RCx) or alternative key sizes where the default isn't necessarily
the best choice (two-key vs three-key 3DES) */
int getOptimalKeysize( CRYPT_INFO *cryptInfoPtr,
const int requestedKeyLength )
{
const CAPABILITY_INFO *capabilityInfoPtr = cryptInfoPtr->capabilityInfo;
int keyLength, maxKeyLength = capabilityInfoPtr->maxKeySize;
assert( requestedKeyLength == 0 || \
( requestedKeyLength >= bitsToBytes( MIN_KEYSIZE_BITS ) && \
requestedKeyLength <= bitsToBytes( MAX_PKCSIZE_BITS ) ) );
/* Determine the upper limit on the key size and make sure the requested
length is valid */
if( requestedKeyLength == 0 )
{
/* For PKC contexts where we're generating a new key, we want to use
the recommended (rather than the longest possible) key size,
whereas for conventional contexts we want to use the longest
possible size for the session key (this will be adjusted further
down if necessary for those algorithms where it's excessively
long) */
keyLength = ( cryptInfoPtr->type == CONTEXT_PKC ) ? \
capabilityInfoPtr->keySize : maxKeyLength;
/* Although RC2 will handle keys of up to 1024 bits and RC4 up to
2048 bits, they're never used with this maximum size but (at
least in non-crippled implementations) always use 128 bits, so
we limit them to the default rather than maximum possible size */
if( capabilityInfoPtr->cryptAlgo == CRYPT_ALGO_RC2 || \
capabilityInfoPtr->cryptAlgo == CRYPT_ALGO_RC4 )
keyLength = capabilityInfoPtr->keySize;
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -