📄 pkcs11.c
字号:
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( key, keyLength ) );
/* If this is meant to be a persistent object, modify the template to
make it a persistent token object and adjust the template entry count
to include the object label */
if( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT )
keyTemplate[ 2 ].pValue = ( CK_VOID_PTR ) &bTrue;
return( initKey( contextInfoPtr, keyTemplate, templateCount,
key, keyLength ) );
}
static int hmacInitKey( CONTEXT_INFO *contextInfoPtr, const void *key,
const int keyLength )
{
static const CK_OBJECT_CLASS class = CKO_SECRET_KEY;
static const CK_BBOOL bFalse = FALSE, bTrue = TRUE;
const CK_KEY_TYPE type = contextInfoPtr->capabilityInfo->paramKeyType;
CK_ATTRIBUTE keyTemplate[] = {
/* General-purpose fields */
{ CKA_CLASS, ( CK_VOID_PTR ) &class, sizeof( CK_OBJECT_CLASS ) },
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &type, sizeof( CK_KEY_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bFalse, sizeof( CK_BBOOL ) },
{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SENSITIVE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SIGN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VERIFY, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VALUE, NULL_PTR, 0 },
/* Persistent-object only fields */
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize }
};
const int templateCount = \
( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT ) ? 9 : 8;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( key, keyLength ) );
/* If this is meant to be a persistent object, modify the template to
make it a persistent token object and adjust the template entry count
to include the object label */
if( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT )
keyTemplate[ 2 ].pValue = ( CK_VOID_PTR ) &bTrue;
return( initKey( contextInfoPtr, keyTemplate, templateCount,
key, keyLength ) );
}
/* Generate a key into a device object. Normally we generate keys inside
cryptlib and load them into the device object (so a keygen becomes a
keygen inside cryptlib followed by a cipherInitKey()) in order to make
sure that the key data is accessible from the context. If we didn't do
this, the user would have to be very careful to perform all key wrap/
unwrap operations only via device objects. This is particularly
problematic with public-key operations since cryptlib always instantiates
public-key objects as cryptlib native objects since they're so much
quicker in that form. So for example importing a certificate and then
using it to wrap a conventional encryption key that's been generated in
a device is impossible because the key to wrap isn't accessible to the
public-key context tied to the certificate. Because of this,
USE_HW_KEYGEN should be used with great care */
#ifdef USE_HW_KEYGEN
static int generateKey( CONTEXT_INFO *contextInfoPtr,
CK_ATTRIBUTE *keyTemplate, const int templateCount,
const BOOLEAN isMAC )
{
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
CK_MECHANISM mechanism = { contextInfoPtr->capabilityInfo->paramKeyGen,
NULL_PTR, 0 };
CK_OBJECT_HANDLE hObject;
CK_RV status;
int cryptStatus;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( keyTemplate, \
templateCount * sizeof( CK_ATTRIBUTE ) ) );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Generate the key into the token */
status = C_GenerateKey( pkcs11Info->hSession, &mechanism,
keyTemplate, templateCount, &hObject );
cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
if( cryptStatusOK( cryptStatus ) )
{
assert( hObject != CK_OBJECT_NONE );
contextInfoPtr->deviceObject = hObject;
}
zeroise( keyTemplate, sizeof( CK_ATTRIBUTE ) * templateCount );
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
static int cipherGenerateKey( CONTEXT_INFO *contextInfoPtr,
const int keySizeBits )
{
static const CK_OBJECT_CLASS class = CKO_SECRET_KEY;
static const CK_BBOOL bFalse = FALSE, bTrue = TRUE;
const CK_KEY_TYPE type = contextInfoPtr->capabilityInfo->paramKeyType;
const CK_ULONG length = bitsToBytes( keySizeBits );
CK_ATTRIBUTE keyTemplate[] = {
/* General-purpose fields */
{ CKA_CLASS, ( CK_VOID_PTR ) &class, sizeof( CK_OBJECT_CLASS ) },
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &type, sizeof( CK_KEY_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bFalse, sizeof( CK_BBOOL ) },
{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SENSITIVE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_ENCRYPT, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_DECRYPT, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VALUE_LEN, ( CK_VOID_PTR ) &length, sizeof( CK_ULONG ) },
/* Persistent-object only fields */
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize }
};
const int templateCount = \
( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT ) ? 9 : 8;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
/* If this is meant to be a persistent object, modify the template to
make it a persistent token object and adjust the template entry count
to include the object label */
if( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT )
keyTemplate[ 2 ].pValue = ( CK_VOID_PTR ) &bTrue;
return( generateKey( contextInfoPtr, keyTemplate, templateCount, FALSE ) );
}
static int hmacGenerateKey( CONTEXT_INFO *contextInfoPtr,
const int keySizeBits )
{
static const CK_OBJECT_CLASS class = CKO_SECRET_KEY;
static const CK_BBOOL bFalse = FALSE, bTrue = TRUE;
const CK_KEY_TYPE type = contextInfoPtr->capabilityInfo->paramKeyType;
const CK_ULONG length = bitsToBytes( keySizeBits );
CK_ATTRIBUTE keyTemplate[] = {
/* General-purpose fields */
{ CKA_CLASS, ( CK_VOID_PTR ) &class, sizeof( CK_OBJECT_CLASS ) },
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &type, sizeof( CK_KEY_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bFalse, sizeof( CK_BBOOL ) },
{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SENSITIVE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SIGN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VERIFY, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VALUE_LEN, ( CK_VOID_PTR ) &length, sizeof( CK_ULONG ) },
/* Persistent-object only fields */
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize }
};
const int templateCount = \
( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT ) ? 9 : 8;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
/* If this is meant to be a persistent object, modify the template to
make it a persistent token object and adjust the template entry count
to include the object label */
if( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT )
keyTemplate[ 2 ].pValue = ( CK_VOID_PTR ) &bTrue;
return( generateKey( contextInfoPtr, keyTemplate, templateCount, TRUE ) );
}
#else
#define cipherGenerateKey NULL
#define hmacGenerateKey NULL
#endif /* USE_HW_KEYGEN */
/****************************************************************************
* *
* Conventional Crypto Mapping Functions *
* *
****************************************************************************/
/* Set up algorithm-specific encryption parameters */
static int initCryptParams( CONTEXT_INFO *contextInfoPtr, void *paramData )
{
const int ivSize = contextInfoPtr->capabilityInfo->blockSize;
if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RC2 )
{
if( contextInfoPtr->ctxConv->mode == CRYPT_MODE_ECB )
{
CK_RC2_PARAMS_PTR rc2params = ( CK_RC2_PARAMS_PTR ) paramData;
*rc2params = 128;
return( sizeof( CK_RC2_PARAMS ) );
}
else
{
CK_RC2_CBC_PARAMS_PTR rc2params = ( CK_RC2_CBC_PARAMS_PTR ) paramData;
rc2params->ulEffectiveBits = 128;
memcpy( rc2params->iv, contextInfoPtr->ctxConv->currentIV, ivSize );
return( sizeof( CK_RC2_CBC_PARAMS ) );
}
}
if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RC5 )
{
if( contextInfoPtr->ctxConv->mode == CRYPT_MODE_ECB )
{
CK_RC5_PARAMS_PTR rc5params = ( CK_RC5_PARAMS_PTR ) paramData;
rc5params->ulWordsize = 4; /* Word size in bytes = blocksize/2 */
rc5params->ulRounds = 12;
return( sizeof( CK_RC5_PARAMS ) );
}
else
{
CK_RC5_CBC_PARAMS_PTR rc5params = ( CK_RC5_CBC_PARAMS_PTR ) paramData;
rc5params->ulWordsize = 4; /* Word size in bytes = blocksize/2 */
rc5params->ulRounds = 12;
rc5params->pIv = contextInfoPtr->ctxConv->currentIV;
rc5params->ulIvLen = ivSize;
return( sizeof( CK_RC5_CBC_PARAMS ) );
}
}
return( 0 );
}
/* Encrypt/decrypt data */
static int cipherEncrypt( CONTEXT_INFO *contextInfoPtr, void *buffer,
int length, const CK_MECHANISM_TYPE mechanismType )
{
CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
BYTE paramDataBuffer[ 64 + 8 ];
const int ivSize = contextInfoPtr->capabilityInfo->blockSize;
int paramSize, cryptStatus;
/* Set up algorithm and mode-specific parameters */
paramSize = initCryptParams( contextInfoPtr, ¶mDataBuffer );
if( paramSize > 0 )
{
mechanism.pParameter = paramDataBuffer;
mechanism.ulParameterLen = paramSize;
}
else
{
/* Even if there are no algorithm-specific parameters, there may
still be a mode-specific IV parameter */
if( needsIV( contextInfoPtr->ctxConv->mode ) && \
!isStreamCipher( contextInfoPtr->capabilityInfo->cryptAlgo ) )
{
mechanism.pParameter = contextInfoPtr->ctxConv->currentIV;
mechanism.ulParameterLen = ivSize;
}
}
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
cryptStatus = genericEncrypt( pkcs11Info, contextInfoPtr, &mechanism, buffer,
length, length );
if( cryptStatusOK( cryptStatus ) )
{
if( needsIV( contextInfoPtr->ctxConv->mode ) && \
!isStreamCipher( contextInfoPtr->capabilityInfo->cryptAlgo ) )
{
/* Since PKCS #11 assumes that either all data is encrypted at
once or that a given mechanism is devoted entirely to a single
operation, we have to preserve the state (the IV) across
calls */
memcpy( contextInfoPtr->ctxConv->currentIV, \
( BYTE * ) buffer + length - ivSize, ivSize );
}
}
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
static int cipherDecrypt( CONTEXT_INFO *contextInfoPtr, void *buffer,
int length, const CK_MECHANISM_TYPE mechanismType )
{
CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 };
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
BYTE paramDataBuffer[ 64 + 8 ], ivBuffer[ CRYPT_MAX_IVSIZE + 8 ];
const int ivSize = contextInfoPtr->capabilityInfo->blockSize;
int paramSize, cryptStatus;
/* Set up algorithm and mode-specific parameters */
paramSize = initCryptParams( contextInfoPtr, ¶mDataBuffer );
if( paramSize > 0 )
{
mechanism.pParameter = paramDataBuffer;
mechanism.ulParameterLen = paramSize;
}
else
/* Even if there are no algorithm-specific parameters, there may
still be a mode-specific IV parameter. In addition we have to
save the end of the ciphertext as the IV for the next block if
this is required */
if( needsIV( contextInfoPtr->ctxConv->mode ) && \
!isStreamCipher( contextInfoPtr->capabilityInfo->cryptAlgo ) )
{
mechanism.pParameter = contextInfoPtr->ctxConv->currentIV;
mechanism.ulParameterLen = ivSize;
}
if( needsIV( contextInfoPtr->ctxConv->mode ) && \
!isStreamCipher( contextInfoPtr->capabilityInfo->cryptAlgo ) )
memcpy( ivBuffer, ( BYTE * ) buffer + length - ivSize, ivSize );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
cryptStatus = genericDecrypt( pkcs11Info, contextInfoPtr, &mechanism, buffer,
length );
if( cryptStatusOK( cryptStatus ) )
{
if( needsIV( contextInfoPtr->ctxConv->mode ) && \
!isStreamCipher( contextInfoPtr->capabilityInfo->cryptAlgo ) )
{
/* Since PKCS #11 assumes that either all data is encrypted at
once or that a given mechanism is devoted entirely to a single
operation, we have to preserve the state (the IV) across
calls */
memcpy( contextInfoPtr->ctxConv->currentIV, ivBuffer, ivSize );
}
}
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
/* Map a cryptlib algorithm and mode to a PKCS #11 mechanism type, with
shortcuts for the most frequently-used algorithm(s) */
static int cipherEncryptECB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
int length )
{
if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_3DES )
return( cipherEncrypt( contextInfoPtr, buffer, length, CKM_DES3_ECB ) );
if( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_AES )
return( cipherEncrypt( contextInfoPtr, buffer, length, CKM_AES_ECB ) );
return( cipherEncrypt( contextInfoPtr, buffer, length,
getMechanism( MECH_CONV, contextInfoPtr->capabilityInfo->cryptAlgo,
CRYPT_MODE_ECB ) ) );
}
static int cipherEncryptCBC( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
int length )
{
return( cipherEncrypt( contextInfoPtr, buffer, length,
contextInfoPtr->capabilityInfo->paramDefaultMech ) );
}
#ifdef USE_SKIPJACK
static int cipherEncryptCFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
int length )
{
return( cipherEncrypt( contextInfoPtr, buffer, length,
getMechanism( MECH_CONV, contextInfoPtr->capabilityInfo->cryptAlgo,
CRYPT_MODE_CFB ) ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -