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

📄 pkcs11.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	}
#endif /* USE_SKIPJACK */
#if defined( USE_RC4 ) || defined( USE_SKIPJACK )
static int cipherEncryptOFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, 
							 int length )
	{
	if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RC4 )
		return( cipherEncrypt( contextInfoPtr, buffer, length, CKM_RC4 ) );
	return( cipherEncrypt( contextInfoPtr, buffer, length, 
				getMechanism( MECH_CONV, contextInfoPtr->capabilityInfo->cryptAlgo, 
							  CRYPT_MODE_OFB ) ) );
	}
#endif /* USE_RC4 || USE_SKIPJACK */
static int cipherDecryptECB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, 
							 int length )
	{
	if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_3DES )
		return( cipherDecrypt( contextInfoPtr, buffer, length, CKM_DES3_ECB ) );
	if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_AES )
		return( cipherDecrypt( contextInfoPtr, buffer, length, CKM_AES_ECB ) );
	return( cipherDecrypt( contextInfoPtr, buffer, length, 
				getMechanism( MECH_CONV, contextInfoPtr->capabilityInfo->cryptAlgo, 
							  CRYPT_MODE_ECB ) ) );
	}
static int cipherDecryptCBC( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, 
							 int length )
	{
	return( cipherDecrypt( contextInfoPtr, buffer, length, 
						   contextInfoPtr->capabilityInfo->paramDefaultMech ) );
	}
#ifdef USE_SKIPJACK
static int cipherDecryptCFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, 
							 int length )
	{
	return( cipherDecrypt( contextInfoPtr, buffer, length, 
				getMechanism( MECH_CONV, contextInfoPtr->capabilityInfo->cryptAlgo, 
							  CRYPT_MODE_CFB ) ) );
	}
#endif /* USE_SKIPJACK */
#if defined( USE_RC4 ) || defined( USE_SKIPJACK )
static int cipherDecryptOFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, 
							 int length )
	{
	if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RC4 )
		return( cipherDecrypt( contextInfoPtr, buffer, length, CKM_RC4 ) );
	return( cipherDecrypt( contextInfoPtr, buffer, length, 
				getMechanism( MECH_CONV, contextInfoPtr->capabilityInfo->cryptAlgo, 
							  CRYPT_MODE_OFB ) ) );
	}
#endif /* USE_RC4 || USE_SKIPJACK */

/****************************************************************************
*																			*
*								MAC Mapping Functions						*
*																			*
****************************************************************************/

/* MAC data.  The PKCS #11 way of handling this is rather problematic since
   the HMAC operation is associated with a session and not with the the HMAC
   object.  This means that we can only have a single HMAC operation in 
   effect at any one time.  To protect against users starting a second 
   HMAC/sign operation, we record the device object handle of the currently 
   active signing object and don't allow any further signature operations to
   be initiated if there's an object currently in use */

static int hmac( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int length )
	{
	CK_MECHANISM mechanism = { contextInfoPtr->capabilityInfo->paramDefaultMech, 
							   NULL_PTR, 0 };
	CRYPT_DEVICE iCryptDevice;
	PKCS11_INFO *pkcs11Info;
	CK_RV status;
	int cryptStatus;

	/* Get the info for the device associated with this context */
	cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle, 
										&iCryptDevice, &pkcs11Info );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );

	/* If we're currently in the middle of a multi-stage sign operation we
	   can't start a new one.  We have to perform this tracking explicitly 
	   since PKCS #11 only allows one multi-stage operation per session */
	if( pkcs11Info->hActiveSignObject != CK_OBJECT_NONE && \
		pkcs11Info->hActiveSignObject != contextInfoPtr->deviceObject )
		{
		krnlReleaseObject( iCryptDevice );
		return( CRYPT_ERROR_INCOMPLETE );
		}

	/* If we haven't initialised the MAC operation yet, start it now */
	if( !( contextInfoPtr->flags & CONTEXT_FLAG_HASH_INITED ) )
		{
		status = C_SignInit( pkcs11Info->hSession, &mechanism, 
							 contextInfoPtr->deviceObject );
		if( status != CKR_OK )
			return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
		contextInfoPtr->flags |= CONTEXT_FLAG_HASH_INITED;
		pkcs11Info->hActiveSignObject = contextInfoPtr->deviceObject;
		}

	if( length > 0 )
		status = C_SignUpdate( pkcs11Info->hSession, buffer, length  );
	else
		{
		CK_ULONG dummy;

		status = C_SignFinal( pkcs11Info->hSession, 
							  contextInfoPtr->ctxMAC->mac, &dummy );
		pkcs11Info->hActiveSignObject = CK_OBJECT_NONE;
		}
	if( status != CKR_OK )
		return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );

	krnlReleaseObject( iCryptDevice );
	return( cryptStatus );
	}

/****************************************************************************
*																			*
*						 	Device Capability Routines						*
*																			*
****************************************************************************/

/* Conventional encryption and MAC mechanism info */

static const PKCS11_MECHANISM_INFO mechanismInfoConv[] = {
	/* Conventional encryption mechanisms */
	{ CKM_DES_ECB, CKM_DES_KEY_GEN, CKM_DES_CBC, CRYPT_ALGO_DES, CRYPT_MODE_ECB, CKK_DES,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_DES_CBC, CKM_DES_KEY_GEN, CKM_DES_CBC, CRYPT_ALGO_DES, CRYPT_MODE_CBC, CKK_DES,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
	{ CKM_DES3_ECB, CKM_DES3_KEY_GEN, CKM_DES3_CBC, CRYPT_ALGO_3DES, CRYPT_MODE_ECB, CKK_DES3,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_DES3_CBC, CKM_DES3_KEY_GEN, CKM_DES3_CBC, CRYPT_ALGO_3DES, CRYPT_MODE_CBC, CKK_DES3,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#ifdef USE_IDEA
	{ CKM_IDEA_ECB, CKM_IDEA_KEY_GEN, CKM_IDEA_CBC, CRYPT_ALGO_IDEA, CRYPT_MODE_ECB, CKK_IDEA,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_IDEA_CBC, CKM_IDEA_KEY_GEN, CKM_IDEA_CBC, CRYPT_ALGO_IDEA, CRYPT_MODE_CBC, CKK_IDEA,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#endif /* USE_IDEA */
#ifdef USE_CAST
	{ CKM_CAST5_ECB, CKM_CAST5_KEY_GEN, CKM_CAST5_CBC, CRYPT_ALGO_CAST, CRYPT_MODE_ECB, CKK_CAST5,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_CAST5_CBC, CKM_CAST5_KEY_GEN, CKM_CAST5_CBC, CRYPT_ALGO_CAST, CRYPT_MODE_CBC, CKK_CAST5,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#endif /* USE_CAST */
#ifdef USE_RC2
	{ CKM_RC2_ECB, CKM_RC2_KEY_GEN, CKM_RC2_CBC, CRYPT_ALGO_RC2, CRYPT_MODE_ECB, CKK_RC2,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_RC2_CBC, CKM_RC2_KEY_GEN, CKM_RC2_CBC, CRYPT_ALGO_RC2, CRYPT_MODE_CBC, CKK_RC2,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#endif /* USE_RC2 */
#ifdef USE_RC4
	{ CKM_RC4, CKM_RC4_KEY_GEN, CKM_RC4, CRYPT_ALGO_RC4, CRYPT_MODE_OFB, CKK_RC4,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptOFB, cipherDecryptOFB, NULL, NULL },
#endif /* USE_RC4 */
#ifdef USE_RC5
	{ CKM_RC5_ECB, CKM_RC5_KEY_GEN, CKM_RC5_CBC, CRYPT_ALGO_RC5, CRYPT_MODE_ECB, CKK_RC5,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_RC5_CBC, CKM_RC5_KEY_GEN, CKM_RC5_CBC, CRYPT_ALGO_RC5, CRYPT_MODE_CBC, CKK_RC5,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#endif /* USE_RC5 */
	{ CKM_AES_ECB, CKM_AES_KEY_GEN, CKM_AES_CBC, CRYPT_ALGO_AES, CRYPT_MODE_ECB, CKK_AES,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_AES_CBC, CKM_AES_KEY_GEN, CKM_AES_CBC, CRYPT_ALGO_AES, CRYPT_MODE_CBC, CKK_AES,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#ifdef USE_BLOWFISH
	{ CKM_BLOWFISH_CBC, CKM_BLOWFISH_KEY_GEN, CKM_BLOWFISH_CBC, CRYPT_ALGO_BLOWFISH, CRYPT_MODE_CBC, CKK_BLOWFISH,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
#endif /* USE_BLOWFISH */
#ifdef USE_SKIPJACK
	{ CKM_SKIPJACK_ECB64, CKM_SKIPJACK_KEY_GEN, CKM_SKIPJACK_CBC64, CRYPT_ALGO_SKIPJACK, CRYPT_MODE_ECB, CKK_SKIPJACK,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptECB, cipherDecryptECB, NULL, NULL },
	{ CKM_SKIPJACK_CBC64, CKM_SKIPJACK_KEY_GEN, CKM_SKIPJACK_CBC64, CRYPT_ALGO_SKIPJACK, CRYPT_MODE_CBC, CKK_SKIPJACK,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCBC, cipherDecryptCBC, NULL, NULL },
	{ CKM_SKIPJACK_CFB64, CKM_SKIPJACK_KEY_GEN, CKM_SKIPJACK_CBC64, CRYPT_ALGO_SKIPJACK, CRYPT_MODE_CFB, CKK_SKIPJACK,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptCFB, cipherDecryptCFB, NULL, NULL },
	{ CKM_SKIPJACK_OFB64, CKM_SKIPJACK_KEY_GEN, CKM_SKIPJACK_CBC64, CRYPT_ALGO_SKIPJACK, CRYPT_MODE_OFB, CKK_SKIPJACK,
	  genericEndFunction, cipherInitKey, cipherGenerateKey, 
	  cipherEncryptOFB, cipherDecryptOFB, NULL, NULL },
#endif /* USE_SKIPJACK */

	/* MAC mechanisms.  The positioning of the encrypt/decrypt functions is 
	   a bit odd because cryptlib treats hashing as an encrypt/decrypt
	   operation while PKCS #11 treats it as a sign/verify operation, the
	   function names correspond to the PKCS #11 usage but the position is
	   for cryptlib usage.  In addition there aren't any HMAC key types so
	   it's necessary to use CKK_GENERIC_SECRET (there's actually a bug in
	   the standard around this because CKK_GENERIC_SECRET keys can't be 
	   used for en/decryption or sign/verify, at the moment some 
	   implementations allow them to be used with HMAC and some don't).  In
	   order to allow for implementations that define their own HMAC keygen
	   and key types, we use macros for CKM_x_HMAC_KEY_GEN and CKK_x_HMAC 
	   that expand either to the vendor-specific type or the generic CKM/CKK
	   types */
#ifdef USE_HMAC_MD5
	{ CKM_MD5_HMAC, CKM_MD5_HMAC_KEY_GEN, CKM_MD5_HMAC, CRYPT_ALGO_HMAC_MD5, CRYPT_MODE_NONE, CKK_MD5_HMAC,
	  genericEndFunction, hmacInitKey, hmacGenerateKey, 
	  hmac, hmac, NULL, NULL },
#endif /* USE_HMAC_MD5 */
	{ CKM_SHA_1_HMAC, CKM_SHA_1_HMAC_KEY_GEN, CKM_SHA_1_HMAC, CRYPT_ALGO_HMAC_SHA1, CRYPT_MODE_NONE, CKK_SHA_1_HMAC,
	  genericEndFunction, hmacInitKey, hmacGenerateKey, 
	  hmac, hmac, NULL, NULL },
#ifdef USE_HMAC_RIPEMD160
	{ CKM_RIPEMD160_HMAC, CKM_RIPEMD160_HMAC_KEY_GEN, CKM_RIPEMD160_HMAC, CRYPT_ALGO_HMAC_RIPEMD160, CRYPT_MODE_NONE, CKK_RIPEMD160_HMAC,
	  genericEndFunction, hmacInitKey, hmacGenerateKey, 
	  hmac, hmac, NULL, NULL },
#endif /* USE_HMAC_RIPEMD160 */

	{ CKM_NONE, CKM_NONE, CKM_NONE, CRYPT_ERROR, CRYPT_ERROR },
		{ CKM_NONE, CKM_NONE, CKM_NONE, CRYPT_ERROR, CRYPT_ERROR }
	};

const PKCS11_MECHANISM_INFO *getMechanismInfoConv( int *mechanismInfoSize )
	{
	*mechanismInfoSize = FAILSAFE_ARRAYSIZE( mechanismInfoConv, \
											 PKCS11_MECHANISM_INFO );
	return( mechanismInfoConv );
	}

/* Map a cryptlib conventional-encryption algorithm and mode to a PKCS #11
   mechanism */

static CK_MECHANISM_TYPE getMechanism( const GETMECH_TYPE mechType,
									   const CRYPT_ALGO_TYPE cryptAlgo,
									   const CRYPT_MODE_TYPE cryptMode )
	{
	int i;

	assert( ( mechType == MECH_CONV && \
			  cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
			  cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL && \
			  cryptMode > CRYPT_MODE_NONE && \
			  cryptMode < CRYPT_MODE_LAST ) || 
			( mechType == MECH_CONV_KEYGEN && \
			  cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
			  cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL && \
			  cryptMode == CRYPT_MODE_NONE ) || 
			( ( mechType == MECH_MAC || mechType == MECH_MAC_KEYGEN ) && \
			  cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
			  cryptAlgo <= CRYPT_ALGO_LAST_MAC && \
			  cryptMode == CRYPT_MODE_NONE ) );

	/* Find a match for the algorithm type.  If it's a MAC algorithm or 
	   keygen mechanism, we're done */
	for( i = 0; mechanismInfoConv[ i ].cryptAlgo != cryptAlgo && \
				mechanismInfoConv[ i ].cryptAlgo != CRYPT_ERROR && \
				i < FAILSAFE_ARRAYSIZE( mechanismInfoConv, PKCS11_MECHANISM_INFO );
		 i++ );
	if( i >= FAILSAFE_ARRAYSIZE( mechanismInfoConv, PKCS11_MECHANISM_INFO ) )
		retIntError_Ext( CKM_NONE );
	assert( i < sizeof( mechanismInfoConv ) / sizeof( PKCS11_MECHANISM_INFO ) && \
			mechanismInfoConv[ i ].cryptAlgo != CRYPT_ERROR );
	if( mechType == MECH_MAC )
		return( mechanismInfoConv[ i ].mechanism );
	if( mechType == MECH_CONV_KEYGEN || mechType == MECH_MAC_KEYGEN )
		return( mechanismInfoConv[ i ].keygenMechanism );

	/* It's a conventional-encryption mechanism, we have to match the 
	   encryption mode as well */
	assert( mechType == MECH_CONV );
	while( mechanismInfoConv[ i ].cryptMode != cryptMode && \
		   mechanismInfoConv[ i ].cryptAlgo != CRYPT_ERROR && \
		   i < FAILSAFE_ARRAYSIZE( mechanismInfoConv, PKCS11_MECHANISM_INFO ) )
		i++;
	if( i >= FAILSAFE_ARRAYSIZE( mechanismInfoConv, PKCS11_MECHANISM_INFO ) )
		retIntError_Ext( CKM_NONE );
	assert( i < sizeof( mechanismInfoConv ) / sizeof( PKCS11_MECHANISM_INFO ) && \
			mechanismInfoConv[ i ].cryptAlgo != CRYPT_ERROR );

	return( mechanismInfoConv[ i ].mechanism );
	}

/****************************************************************************
*																			*
*						 	Device Access Routines							*
*																			*
****************************************************************************/

/* Mechanisms supported by PKCS #11 devices.  These are actually cryptlib 
   native mechanisms (support of the various mechanisms in devices is too 
   patchy to rely on, see for example the comments about PKCS vs.raw RSA
   mechanisms elsewhere), but not the full set supported by the system 
   device since functions like private key export aren't available.  The 
   list is sorted in order of frequency of use in order to make lookups a 
   bit faster */

static const FAR_BSS MECHANISM_FUNCTION_INFO mechanismFunctions[] = {
	{ MESSAGE_DEV_EXPORT, MECHANISM_ENC_PKCS1, ( MECHANISM_FUNCTION ) exportPKCS1 },
	{ MESSAGE_DEV_IMPORT, MECHANISM_ENC_PKCS1, ( MECHANISM_FUNCTION ) importPKCS1 },
	{ MESSAGE_DEV_SIGN, MECHANISM_SIG_PKCS1, ( MECHANISM_FUNCTION ) signPKCS1 },
	{ MESSAGE_DEV_SIGCHECK, MECHANISM_SIG_PKCS1, ( MECHANISM_FUNCTION ) sigcheckPKCS1 },
	{ MESSAGE_DEV_EXPORT, MECHANISM_ENC_PKCS1_RAW, ( MECHANISM_FUNCTION ) exportPKCS1 },
	{ MESSAGE_DEV_IMPORT, MECHANISM_ENC_PKCS1_RAW, ( MECHANISM_FUNCTION ) importPKCS1 },
#ifdef USE_PGP
	{ MESSAGE_DEV_EXPORT, MECHANISM_ENC_PKCS1_PGP, ( MECHANISM_FUNCTION ) exportPKCS1PGP },
	{ MESSAGE_DEV_IMPORT, MECHANISM_ENC_PKCS1_PGP, ( MECHANISM_FUNCTION ) importPKCS1PGP },
#endif /* USE_PGP */
	{ MESSAGE_DEV_EXPORT, MECHANISM_ENC_CMS, ( MECHANISM_FUNCTION ) exportCMS },
	{ MESSAGE_DEV_IMPORT, MECHANISM_ENC_CMS, ( MECHANISM_FUNCTION ) importCMS },
	{ MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_PKCS5, ( MECHANISM_FUNCTION ) derivePKCS5 },
#if defined( USE_PGP ) || defined( USE_PGPKEYS )
	{ MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_PGP, ( MECHANISM_FUNCTION ) derivePGP },
#endif /* USE_PGP || USE_PGPKEYS */
#ifdef USE_SSL
	{ MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_TLS, ( MECHANISM_FUNCTION ) deriveSSL },
	{ MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_SSL, ( MECHANISM_FUNCTION ) deriveTLS },
	{ MESSAGE_DEV_SIGN, MECHANISM_SIG_SSL, ( MECHANISM_FUNCTION ) signSSL },
	{ MESSAGE_DEV_SIGCHECK, MECHANISM_SIG_SSL, ( MECHANISM_FUNCTION ) sigcheckSSL },
#endif /* USE_SSL */
#ifdef USE_CMP
	{ MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_CMP, ( MECHANISM_FUNCTION ) deriveCMP },
#endif /* USE_CMP */
#ifdef USE_PKCS12
	{ MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_PKCS12, ( MECHANISM_FUNCTION ) derivePKCS12 },
#endif /* USE_PKCS12 */
	{ MESSAGE_NONE, MECHANISM_NONE, NULL }, { MESSAGE_NONE, MECHANISM_NONE, NULL }
	};

/* Set up the function pointers to the device methods */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int setDevicePKCS11( INOUT DEVICE_INFO *deviceInfo, 
					 IN_BUFFER( nameLength ) const char *name, 
					 IN_LENGTH_ATTRIBUTE const int nameLength )
	{
	int status;

	assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
	assert( isReadPtr( name, nameLength ) );

	REQUIRES( nameLength > 0 && nameLength < MAX_ATTRIBUTE_SIZE );

	status = initPKCS11Init( deviceInfo, name, nameLength );
	if( cryptStatusError( status ) )
		return( status );
	deviceInfo->controlFunction = controlFunction;
	initPKCS11RW( deviceInfo );
	deviceInfo->mechanismFunctions = mechanismFunctions;
	deviceInfo->mechanismFunctionCount = \
		FAILSAFE_ARRAYSIZE( mechanismFunctions, MECHANISM_FUNCTION_INFO );

	return( CRYPT_OK );
	}
#endif /* USE_PKCS11 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -