📄 ms_capi.c
字号:
return( CRYPT_OK );
}
void deviceEndCryptoAPI( void )
{
if( hCryptoAPI != NULL_HINSTANCE )
FreeLibrary( hCryptoAPI );
hCryptoAPI = NULL_HINSTANCE;
}
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Get access to the PKCS #11 device associated with a context */
static int getContextDeviceInfo( const CRYPT_HANDLE iCryptContext,
CRYPT_DEVICE *iCryptDevice,
CRYPTOAPI_INFO **cryptoapiInfoPtrPtr )
{
CRYPT_DEVICE iLocalDevice;
DEVICE_INFO *deviceInfo;
int cryptStatus;
/* Clear return values */
*iCryptDevice = CRYPT_ERROR;
*cryptoapiInfoPtrPtr = NULL;
/* Get the the device associated with this context */
cryptStatus = krnlSendMessage( iCryptContext, IMESSAGE_GETDEPENDENT,
&iLocalDevice, OBJECT_TYPE_DEVICE );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Get the PKCS #11 info from the device info */
cryptStatus = krnlAcquireObject( iLocalDevice, OBJECT_TYPE_DEVICE,
( void ** ) &deviceInfo,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
*iCryptDevice = iLocalDevice;
*cryptoapiInfoPtrPtr = deviceInfo->deviceCryptoAPI;
return( CRYPT_OK );
}
/* Map a CryptoAPI-specific error to a cryptlib error */
static int mapError( CRYPTOAPI_INFO *cryptoapiInfo, const int defaultError )
{
ERROR_INFO *errorInfo = &cryptoapiInfo->errorInfo;
const DWORD errorCode = GetLastError();
int messageLength;
/* Get the error code and corresponding error message. FormatMessage()
adds EOL terminators so we have to strip those before we pass the
string back to the caller. There's an incredibly arcane way of
telling FormatMessage() to do this via escape codes passed in as
part of a va_arg argument list, but aside from being complex to set
up this also means that the function will try and insert information
such as filenames from the argument list when required (there's no
way to tell in advance which arguments are required), so this is
more trouble than it's worth */
errorInfo->errorCode = ( int ) errorCode;
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, 0,
errorInfo->errorString, MAX_ERRMSG_SIZE - 1, NULL );
for( messageLength = strlen( errorInfo->errorString );
messageLength > 0 && \
( errorInfo->errorString[ messageLength - 1 ] == '\n' || \
errorInfo->errorString[ messageLength - 1 ] == '\r' );
messageLength-- );
errorInfo->errorStringLength = messageLength;
/* Translate the CAPI error code into the cryptlib equivalent */
switch( errorCode )
{
case CRYPT_E_UNKNOWN_ALGO:
return( CRYPT_ERROR_NOTAVAIL );
case ERROR_BUSY:
return( CRYPT_ERROR_TIMEOUT );
case ERROR_MORE_DATA:
return( CRYPT_ERROR_OVERFLOW );
case ERROR_NO_MORE_ITEMS:
return( CRYPT_ERROR_COMPLETE );
case NTE_BAD_DATA:
return( CRYPT_ERROR_BADDATA );
case CRYPT_E_EXISTS:
case NTE_EXISTS:
return( CRYPT_ERROR_DUPLICATE );
case ERROR_NOT_ENOUGH_MEMORY:
case NTE_NO_MEMORY:
return( CRYPT_ERROR_MEMORY );
case CRYPT_E_SECURITY_SETTINGS:
case NTE_PERM:
return( CRYPT_ERROR_PERMISSION );
case NTE_BAD_SIGNATURE:
return( CRYPT_ERROR_SIGNATURE );
case CRYPT_E_NO_MATCH:
case CRYPT_E_NOT_FOUND:
case NTE_KEYSET_NOT_DEF:
case NTE_NOT_FOUND:
case NTE_PROV_DLL_NOT_FOUND:
case NTE_PROV_TYPE_NO_MATCH:
case NTE_PROV_TYPE_NOT_DEF:
return( CRYPT_ERROR_NOTFOUND );
}
return( defaultError );
}
static int mapDeviceError( CONTEXT_INFO *contextInfoPtr, const int defaultError )
{
CRYPT_DEVICE iCryptDevice;
CRYPTOAPI_INFO *cryptoapiInfo;
int status;
/* Get the device associated with this context, set the error information
in it, and exit */
status = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &cryptoapiInfo );
if( cryptStatusError( status ) )
return( status );
status = mapError( cryptoapiInfo, defaultError );
krnlReleaseObject( iCryptDevice );
return( status );
}
/* Map cryptlib to/from CryptoAPI algorithm IDs */
typedef struct {
const CRYPT_ALGO_TYPE cryptAlgo;
const ALG_ID algID;
} ALGO_MAP_INFO;
static const ALGO_MAP_INFO algoMap[] = {
/* PKC algorithms */
{ CRYPT_ALGO_RSA, CALG_RSA_SIGN },
{ CRYPT_ALGO_RSA, CALG_RSA_KEYX },
{ CRYPT_ALGO_DSA, CALG_DSS_SIGN },
/* Encryption algorithms */
{ CRYPT_ALGO_DES, CALG_DES },
{ CRYPT_ALGO_3DES, CALG_3DES },
{ CRYPT_ALGO_RC2, CALG_RC2 },
{ CRYPT_ALGO_RC4, CALG_RC4 },
{ CRYPT_ALGO_SKIPJACK, CALG_SKIPJACK },
/* Hash algorithms */
{ CRYPT_ALGO_MD2, CALG_MD2 },
{ CRYPT_ALGO_MD5, CALG_MD5 },
{ CRYPT_ALGO_SHA1, CALG_SHA },
{ CRYPT_ALGO_NONE, 0 }, { CRYPT_ALGO_NONE, 0 }
};
static ALG_ID cryptlibToCapiID( const CRYPT_ALGO_TYPE cryptAlgo )
{
int i;
for( i = 0; algoMap[ i ].cryptAlgo != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( algoMap, ALGO_MAP_INFO ); i++ )
{
if( algoMap[ i ].cryptAlgo == cryptAlgo )
break;
}
if( i >= FAILSAFE_ARRAYSIZE( algoMap, ALGO_MAP_INFO ) )
retIntError_Ext( 0 );
if( algoMap[ i ].cryptAlgo == CRYPT_ALGO_NONE )
return( 0 );
return( algoMap[ i ].algID );
}
static CRYPT_ALGO_TYPE capiToCryptlibID( const ALG_ID algID )
{
int i;
for( i = 0; algoMap[ i ].cryptAlgo != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( algoMap, ALGO_MAP_INFO ); i++ )
{
if( algoMap[ i ].algID == algID )
break;
}
if( i >= FAILSAFE_ARRAYSIZE( algoMap, ALGO_MAP_INFO ) )
retIntError_Ext( CRYPT_ALGO_NONE );
if( algoMap[ i ].cryptAlgo == CRYPT_ALGO_NONE )
return( CRYPT_ALGO_NONE );
return( algoMap[ i ].cryptAlgo );
}
/* Copy an MPI into the little-endian order required by CryptoAPI, returning
the end position of the copied MPI */
static BYTE *copyMPI( BYTE *dest, const BYTE *src, const int srcLen,
const int srcRequiredLen )
{
int i;
dest += srcLen - 1;
for( i = 0; i < srcLen; i++ )
*dest-- = *src++;
dest += srcLen + 1;
if( srcLen < srcRequiredLen )
{
/* CryptoAPI blobs don't contain any length information but
implicitly specify all lengths in terms of the size of the
main MPI component, so if the actual length is less than the
assumed length we pad the remainder out with zeroes */
for( i = 0; i < srcRequiredLen - srcLen; i++ )
*dest++ = 0;
}
return( dest );
}
/* Create the special-case RSA key with e=1 that's needed to allow direct
key import and export */
static int createExportKey( const HCRYPTPROV hProv, HCRYPTKEY *hPrivateKey,
int *privateKeySize )
{
BLOBHEADER *blobHeaderPtr;
RSAPUBKEY *pubKeyPtr;
BYTE keyBlob[ 1024 + 8 ], *keyBlobPtr;
BOOL result;
int bitLen16, keyBlobLen = 1024;
/* Generate a private key and export it as a private key blob:
Ofs Value
0 BLOBHEADER blobheader {
0 BYTE bType;
1 BYTE bVersion;
2 WORD reserved;
4 ALG_ID aiKeyAlg; }
8 RSAPUBKEY rsapubkey {
8 DWORD magic;
12 DWORD bitlen;
16 DWORD pubexp; }
20 BYTE modulus[ rsapubkey.bitlen / 8 ];
BYTE prime1[ rsapubkey.bitlen / 16 ];
BYTE prime2[ rsapubkey.bitlen / 16 ];
BYTE exponent1[ rsapubkey.bitlen / 16 ];
BYTE exponent2[ rsapubkey.bitlen / 16 ];
BYTE coefficient[ rsapubkey.bitlen / 16 ];
BYTE privateExponent[ rsapubkey.bitlen / 8 ]; */
if( !pCryptGenKey( hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, hPrivateKey ) || \
!pCryptExportKey( *hPrivateKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keyBlobLen ) || \
!pCryptDestroyKey( *hPrivateKey ) )
return( CRYPT_ERROR );
/* Perform a general sanity check on the returned data */
blobHeaderPtr = ( BLOBHEADER * ) keyBlob;
if( blobHeaderPtr->bType != PRIVATEKEYBLOB || \
blobHeaderPtr->bVersion != CUR_BLOB_VERSION || \
blobHeaderPtr->aiKeyAlg != CALG_RSA_KEYX )
{
pCryptDestroyKey( *hPrivateKey );
return( CRYPT_ERROR );
}
/* Set the public exponent to 1 (little-endian 32-bit value) and skip to
the private exponents */
pubKeyPtr = ( RSAPUBKEY * ) ( keyBlob + BLOBHEADER_SIZE );
bitLen16 = ( pubKeyPtr->bitlen / 16 );
pubKeyPtr->pubexp = 1;
keyBlobPtr = keyBlob + 20 + ( pubKeyPtr->bitlen / 8 ) + bitLen16 + bitLen16;
/* Set the two exponents to 1 */
*keyBlobPtr++ = 1;
memset( keyBlobPtr, 0, bitLen16 - 1 );
keyBlobPtr += bitLen16 - 1;
*keyBlobPtr++ = 1;
memset( keyBlobPtr, 0, bitLen16 - 1 );
keyBlobPtr += bitLen16 - 1;
/* Set the private exponent to 1 */
keyBlobPtr += bitLen16; /* Skip coefficient */
*keyBlobPtr++ = 1;
memset( keyBlobPtr, 0, bitLen16 - 1 );
keyBlobPtr += bitLen16 - 1;
/* Finally, re-import the hacked key and clean up */
result = pCryptImportKey( hProv, keyBlob, keyBlobLen, 0, 0, hPrivateKey );
if( result )
*privateKeySize = pubKeyPtr->bitlen / 8;
else
*hPrivateKey = 0;
zeroise( keyBlob, keyBlobLen );
return( result ? CRYPT_OK : CRYPT_ERROR );
}
/* Import a raw session key using the exponent-one RSA key */
static int importPlainKey( const HCRYPTPROV hProv,
const HCRYPTKEY hPrivateKey,
const int privateKeySize, HCRYPTKEY *hSessionKey,
const CRYPT_ALGO_TYPE cryptAlgo, const BYTE *keyData,
const int keyDataSize, void *errorInfoPtr )
{
BLOBHEADER *blobHeaderPtr;
BYTE keyBlob[ 1024 + 8 ], *keyBlobPtr;
ALG_ID algID;
DWORD *dwPtr;
BOOL result;
const int blobSize = sizeof( BLOBHEADER ) + sizeof( ALG_ID ) + privateKeySize;
int i;
/* Set up a SIMPLEBLOB:
Ofs Value
0 BLOBHEADER blobheader {
0 BYTE bType;
1 BYTE bVersion;
2 WORD reserved;
4 ALG_ID aiKeyAlg; }
8 ALG_ID algid;
12 BYTE encryptedkey[ rsapubkey.bitlen/8 ]; */
memset( keyBlob, 0, 1024 );
algID = cryptlibToCapiID( cryptAlgo );
if( algID == 0 )
return( CRYPT_ERROR_NOTAVAIL );
/* Set up the BLOBHEADER part of the blob */
blobHeaderPtr = ( BLOBHEADER * ) keyBlob;
blobHeaderPtr->bType = SIMPLEBLOB;
blobHeaderPtr->bVersion = CUR_BLOB_VERSION;
blobHeaderPtr->aiKeyAlg = algID;
/* Set up the private-key algorithm ID */
dwPtr = ( DWORD * )( keyBlob + BLOBHEADER_SIZE );
*dwPtr = CALG_RSA_KEYX;
/* Store the key as byte-reversed PKCS #1 padded data (or at least close
enough to it to work for the import) */
keyBlobPtr = keyBlob + 12;
for( i = keyDataSize - 1; i >= 0; i-- )
*keyBlobPtr++ = keyData[ i ];
*keyBlobPtr++ = 0;
memset( keyBlobPtr, 2, privateKeySize - ( keyDataSize + 2 ) );
/* Import the key from the faked PKCS #1 wrapped form */
result = pCryptImportKey( hProv, keyBlob, blobSize, hPrivateKey, 0, hSessionKey );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -