⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cryptkey.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -