📄 cryptkey.c
字号:
if( requestedKeyLength < capabilityInfoPtr->minKeySize || \
requestedKeyLength > maxKeyLength )
{
setErrorInfo( cryptInfoPtr, CRYPT_CTXINFO_KEY,
CRYPT_ERRTYPE_ATTR_SIZE );
return( CRYPT_ARGERROR_NUM1 );
}
keyLength = requestedKeyLength;
}
/* If we're generating a conventional/MAC key we need to limit the
maximum length in order to make it exportable via the smallest normal
(ie non-elliptic-curve) public key */
if( cryptInfoPtr->type != CONTEXT_PKC && \
keyLength > bitsToBytes( MAX_KEYSIZE_BITS ) )
keyLength = bitsToBytes( MAX_KEYSIZE_BITS );
return( keyLength );
}
/* Generate a key into a CRYPT_INFO structure. This low-level function is
called by both the normal and async keygen functions, which set the keygen
up as required (the only time there's any real difference is for PKC
keygen) */
int generateKey( CRYPT_INFO *cryptInfoPtr, const BOOLEAN isAsync )
{
const CAPABILITY_INFO *capabilityInfoPtr = cryptInfoPtr->capabilityInfo;
const CONTEXT_TYPE contextType = cryptInfoPtr->type;
int keyLength, status;
/* Determine the best keysize for this algorithm */
keyLength = getOptimalKeysize( cryptInfoPtr,
( contextType == CONTEXT_CONV ) ? \
cryptInfoPtr->ctxConv.userKeyLength : \
( contextType == CONTEXT_MAC ) ? \
cryptInfoPtr->ctxMAC.userKeyLength : \
bitsToBytes( cryptInfoPtr->ctxPKC.keySizeBits ) );
if( cryptStatusError( keyLength ) )
return( keyLength );
/* Public-key generation works differently than the generation of session
keys into a conventional encryption context */
if( cryptInfoPtr->type == CONTEXT_PKC )
{
#ifdef HAS_THREADS
THREAD_HANDLE dummy;
#endif /* OS's with threads */
if( capabilityInfoPtr->generateKeyFunction == NULL )
return( CRYPT_ERROR_NOTAVAIL );
/* Generate the key into the context if it's a synchronous
operation */
if( !isAsync )
{
status = capabilityInfoPtr->generateKeyFunction( cryptInfoPtr,
bytesToBits( keyLength ) );
if( cryptStatusOK( status ) )
/* There's now a key loaded */
cryptInfoPtr->ctxPKC.keySet = TRUE;
return( status );
}
/* It's an async keygen, if the OS supports it set the context state
for the async keygen and spawn the thread/process. If the OS
doesn't support it, just drop through to the normal sync.keygen,
but set the async status to make it behave like an async keygen */
cryptInfoPtr->doAbort = cryptInfoPtr->done = FALSE;
cryptInfoPtr->asyncStatus = CRYPT_OK;
#ifdef HAS_THREADS
cryptInfoPtr->ctxPKC.keySizeBits = bytesToBits( keyLength );
status = THREAD_CREATE( threadKeygen, cryptInfoPtr );
return( THREAD_STATUS( status ) );
#else
cryptInfoPtr->asyncStatus = \
capabilityInfoPtr->generateKeyFunction( cryptInfoPtr,
bytesToBits( keyLength ) );
if( cryptStatusOK( cryptInfoPtr->asyncStatus ) )
/* There's now a key loaded */
cryptInfoPtr->ctxPKC.keySet = TRUE;
return( cryptInfoPtr->asyncStatus );
#endif /* Optional async keygen */
}
/* If the context is implemented in a crypto device, it may have the
capability to generate the key itself so if there's a keygen function
present we call this to generate the key directly into the context
rather than generating it ourselves and loading it in. Note that to
export this key we'll need to use an exporting context which is also
located in the device, since we can't access it externally */
if( capabilityInfoPtr->generateKeyFunction != NULL )
{
status = capabilityInfoPtr->generateKeyFunction( cryptInfoPtr,
bytesToBits( keyLength ) );
if( cryptStatusOK( status ) )
/* There's now a key loaded */
if( cryptInfoPtr->type == CONTEXT_CONV )
cryptInfoPtr->ctxConv.keySet = TRUE;
else
cryptInfoPtr->ctxMAC.keySet = TRUE;
return( status );
}
/* Generate a random session key into the context. We always use
synchronous key generation even if the user has called the async
function because it's quick enough that it doesn't make any
difference. In addition we load the random data directly into the
pagelocked encryption context and pass that in as the key buffer -
loadKey() won't copy the data if src == dest */
if( cryptInfoPtr->type == CONTEXT_CONV )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, cryptInfoPtr->ctxConv.userKey, keyLength );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM );
if( cryptStatusOK( status ) )
status = loadKey( cryptInfoPtr, cryptInfoPtr->ctxConv.userKey,
keyLength );
}
if( cryptInfoPtr->type == CONTEXT_MAC )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, cryptInfoPtr->ctxMAC.userKey, keyLength );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM );
if( cryptStatusOK( status ) )
status = loadKey( cryptInfoPtr, cryptInfoPtr->ctxMAC.userKey,
keyLength );
}
return( status );
}
/****************************************************************************
* *
* Asynchronous Keying Functions *
* *
****************************************************************************/
/* The asynchronous operations only make sense in environments which allow
some form of background processing. Ideally the synchronisation should be
done with a semaphore, however since Win32 pseudocritical sections are
very lightweight it's easier to use these to create a DIY semaphore. The
only downside for this is that if the user calls cryptDestroyContext()
without first calling cryptAsyncCancel(), we have to do it for them.
Since we're not using a real semaphore, we have to do a busy wait until
the abort completes. This isn't a serious problem since it very rarely
happens and when it does we just sleep for awhile, check the DIY
semaphore, and loop if the async.op.is still in progress. This is a lot
cheaper than performing a heavyweight semaphore check on every single use
of a context.
Overall there are three functions:
cryptGenerateKeyAsync();
cryptAsyncQuery();
cryptAsyncCancel();
These are implemented as:
cryptGenerateKeyAsync() is:
lock context resources;
set busy flag;
clear async status, abort flag;
spawn thread to begin key generation;
unlock context resources;
cryptAsyncQuery() is:
lock context resources;
check if busy flag set;
unlock context resources;
return flag status;
cryptAsyncCancel() is:
lock context resources;
set abort flag;
unlock context resources;
The async keygen function relies on the fact that the bnlib routines
supply a callback which can be used to handle control flow in and out of
the bnlib keygen functions. The callout is used to check the abort flag,
and the return value communicates whether the keygen should be aborted or
not:
while( !key ready )
status = generate more bits of key( &callback );
clean up;
exit thread;
callback is:
check abort flag;
if( abort flag set )
return( ASYNC_ABORT );
return( 0 );
Most other functions are modified to return a busy signal if the busy
flag is set. Also, cryptDestroyContext() is modified as described above.
The overall mechanism is somewhat ugly since it involves the caller
polling cryptAsyncQuery() until it returns CRYPT_OK, however there isn't
any nice way to handle the notification since both callbacks and some form
of message-passing are very OS-specific. A possible alternative is that
the caller passes in some reference to a message port and the message that
should be sent to it on completion. Under Windoze this would be done with
use PostMessage(), under Unix the "port" would be the address of a
callback function:
cryptGenerateKeyAsync( const CRYPT_CONTEXT cryptContext,
void *completionMessagePort,
int completionMessage );
However this makes certain assumptions such as the fact the the Windows
app has a message loop, so for now we use the cryptAsyncQuery() mechanism
and let the caller build functionality on top of that if they require it */
/* The async callback function. This is called by the bnlib routines and
checks the abort flag, returning ASYNC_ABORT if the flag is set to tell
the bnlib code to clean up and exit */
int keygenCallback( void *callbackArg )
{
CRYPT_INFO *cryptInfoPtr = callbackArg;
if( cryptInfoPtr->doAbort )
return( ASYNC_ABORT );
return( 0 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -