1594 lines
28 KiB
C
1594 lines
28 KiB
C
/*
|
|
|
|
interop.c
|
|
|
|
6/23/00 dangriff created
|
|
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
#include "interop.h"
|
|
#include "cspstruc.h"
|
|
#include "csptestsuite.h"
|
|
|
|
//
|
|
// Function: IsDataEqual
|
|
//
|
|
BOOL IsDataEqual(
|
|
IN PDATA_BLOB pdb1,
|
|
IN PDATA_BLOB pdb2,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
/*
|
|
LOGFAILINFO LogFailInfo;
|
|
InitFailInfoFromTestCase(ptc, &LogFailInfo);
|
|
*/
|
|
|
|
if (pdb1->cbData != pdb2->cbData)
|
|
{
|
|
/*
|
|
LogFailInfo.dwErrorType = ERROR_WRONG_SIZE;
|
|
LogFail(&LogFailInfo);
|
|
*/
|
|
LogApiFailure(
|
|
API_DATACOMPARE,
|
|
ERROR_WRONG_SIZE,
|
|
ptc);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 != memcmp(pdb1->pbData, pdb2->pbData, pdb1->cbData))
|
|
{
|
|
/*
|
|
LogFailInfo.dwErrorType = ERROR_BAD_DATA;
|
|
LogFail(&LogFailInfo);
|
|
*/
|
|
LogApiFailure(
|
|
API_DATACOMPARE,
|
|
ERROR_BAD_DATA,
|
|
ptc);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Function: ExportPublicKey
|
|
//
|
|
BOOL ExportPublicKey(IN HCRYPTKEY hSourceKey, OUT PDATA_BLOB pdbKey, IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// Export the public key blob from the key handle
|
|
//
|
|
LOG_TRY(TExportKey(
|
|
hSourceKey,
|
|
0,
|
|
PUBLICKEYBLOB,
|
|
0,
|
|
NULL,
|
|
&(pdbKey->cbData),
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(&(pdbKey->pbData), pdbKey->cbData, ptc));
|
|
|
|
LOG_TRY(TExportKey(
|
|
hSourceKey,
|
|
0,
|
|
PUBLICKEYBLOB,
|
|
0,
|
|
pdbKey->pbData,
|
|
&(pdbKey->cbData),
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: CreateHashAndAddData
|
|
//
|
|
BOOL CreateHashAndAddData(
|
|
IN HCRYPTPROV hProv,
|
|
OUT HCRYPTHASH *phHash,
|
|
IN PHASH_INFO pHashInfo,
|
|
IN PTESTCASE ptc,
|
|
IN HCRYPTKEY hKey /* should be 0 when not doing MAC or HMAC */,
|
|
IN PHMAC_INFO pHmacInfo /* should be NULL when not doing HMAC */)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LOG_TRY(TCreateHash(
|
|
hProv,
|
|
pHashInfo->aiHash,
|
|
hKey,
|
|
0,
|
|
phHash,
|
|
ptc));
|
|
|
|
//
|
|
// This step only applies to the HMAC algorithm.
|
|
//
|
|
if ( (NULL != pHmacInfo) &&
|
|
(CALG_HMAC == pHashInfo->aiHash))
|
|
{
|
|
LOG_TRY(TSetHash(
|
|
*phHash,
|
|
HP_HMAC_INFO,
|
|
(PBYTE) pHmacInfo,
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
LOG_TRY(THashData(
|
|
*phHash,
|
|
pHashInfo->dbBaseData.pbData,
|
|
pHashInfo->dbBaseData.cbData,
|
|
0,
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: ExportPlaintextSessionKey
|
|
//
|
|
BOOL ExportPlaintextSessionKey(
|
|
IN HCRYPTKEY hKey,
|
|
IN HCRYPTPROV hProv,
|
|
OUT PDATA_BLOB pdbKey,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hExchangeKey = 0;
|
|
|
|
//
|
|
// First import the private RSA key with
|
|
// exponent of one.
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProv,
|
|
PrivateKeyWithExponentOfOne,
|
|
sizeof(PrivateKeyWithExponentOfOne),
|
|
0,
|
|
0,
|
|
&hExchangeKey,
|
|
ptc));
|
|
|
|
//
|
|
// Now export "encrypted" session key
|
|
//
|
|
LOG_TRY(TExportKey(
|
|
hKey,
|
|
hExchangeKey,
|
|
SIMPLEBLOB,
|
|
0,
|
|
NULL,
|
|
&(pdbKey->cbData),
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(&(pdbKey->pbData), pdbKey->cbData, ptc));
|
|
|
|
LOG_TRY(TExportKey(
|
|
hKey,
|
|
hExchangeKey,
|
|
SIMPLEBLOB,
|
|
0,
|
|
pdbKey->pbData,
|
|
&(pdbKey->cbData),
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hExchangeKey)
|
|
{
|
|
TDestroyKey(hExchangeKey, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: ImportPlaintextSessionKey
|
|
//
|
|
BOOL ImportPlaintextSessionKey(
|
|
IN PDATA_BLOB pdbKey,
|
|
OUT HCRYPTKEY *phKey,
|
|
IN HCRYPTPROV hProv,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hExchangeKey = 0;
|
|
|
|
//
|
|
// First import the private RSA key with
|
|
// exponent of one.
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProv,
|
|
PrivateKeyWithExponentOfOne,
|
|
sizeof(PrivateKeyWithExponentOfOne),
|
|
0,
|
|
0,
|
|
&hExchangeKey,
|
|
ptc));
|
|
|
|
//
|
|
// Next import the "encrypted" session key
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProv,
|
|
pdbKey->pbData,
|
|
pdbKey->cbData,
|
|
hExchangeKey,
|
|
0,
|
|
phKey,
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hExchangeKey)
|
|
{
|
|
TDestroyKey(hExchangeKey, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: CheckHashedData
|
|
//
|
|
BOOL CheckHashedData(
|
|
IN PHASH_INFO pHashInfo,
|
|
IN HCRYPTPROV hProv,
|
|
IN PTESTCASE ptc,
|
|
IN PTEST_MAC_INFO pTestMacInfo /* Should be NULL when not using MAC alg */)
|
|
{
|
|
HCRYPTKEY hKey = 0;
|
|
BOOL fSuccess = FALSE;
|
|
BOOL fUsingMac = FALSE;
|
|
HCRYPTHASH hHash = 0;
|
|
DATA_BLOB dbHash;
|
|
|
|
memset(&dbHash, 0, sizeof(dbHash));
|
|
|
|
if (NULL != pTestMacInfo)
|
|
{
|
|
fUsingMac = TRUE;
|
|
|
|
LOG_TRY(ImportPlaintextSessionKey(
|
|
&(pTestMacInfo->dbKey),
|
|
&hKey,
|
|
hProv,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Create a new hash object of the specified type
|
|
// and add the requested data.
|
|
//
|
|
LOG_TRY(TCreateHash(
|
|
hProv,
|
|
pHashInfo->aiHash,
|
|
hKey,
|
|
0,
|
|
&hHash,
|
|
ptc));
|
|
|
|
if ( fUsingMac &&
|
|
(CALG_HMAC == pHashInfo->aiHash))
|
|
{
|
|
LOG_TRY(TSetHash(
|
|
hHash,
|
|
HP_HMAC_INFO,
|
|
(PBYTE) &(pTestMacInfo->HmacInfo),
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
LOG_TRY(THashData(
|
|
hHash,
|
|
pHashInfo->dbBaseData.pbData,
|
|
pHashInfo->dbBaseData.cbData,
|
|
0,
|
|
ptc));
|
|
|
|
//
|
|
// Get the resulting hash value and compare it to the
|
|
// expected result.
|
|
//
|
|
LOG_TRY(TGetHash(
|
|
hHash,
|
|
HP_HASHVAL,
|
|
NULL,
|
|
&(dbHash.cbData),
|
|
0,
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(&(dbHash.pbData), dbHash.cbData, ptc));
|
|
|
|
LOG_TRY(TGetHash(
|
|
hHash,
|
|
HP_HASHVAL,
|
|
dbHash.pbData ,
|
|
&(dbHash.cbData),
|
|
0,
|
|
ptc));
|
|
|
|
LOG_TRY(IsDataEqual(
|
|
&dbHash,
|
|
&(pHashInfo->dbHashValue),
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (dbHash.pbData)
|
|
{
|
|
free(dbHash.pbData);
|
|
}
|
|
if (hKey)
|
|
{
|
|
TDestroyKey(hKey, ptc);
|
|
}
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: CheckDerivedKey
|
|
//
|
|
BOOL CheckDerivedKey(
|
|
IN PDERIVED_KEY_INFO pDerivedKeyInfo,
|
|
IN HCRYPTPROV hProv,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hSessionKey = 0;
|
|
HCRYPTHASH hHash = 0;
|
|
DWORD cbValidData = 0;
|
|
DATA_BLOB dbSessionKey;
|
|
|
|
memset(&dbSessionKey, 0, sizeof(dbSessionKey));
|
|
|
|
//
|
|
// Create a hash and hash the provided data
|
|
//
|
|
LOG_TRY(CreateHashAndAddData(
|
|
hProv,
|
|
&hHash,
|
|
&(pDerivedKeyInfo->HashInfo),
|
|
ptc,
|
|
0, NULL));
|
|
|
|
// Debugging
|
|
/*
|
|
pDerivedKeyInfo->cbHB = sizeof(pDerivedKeyInfo->rgbHashValB);
|
|
LOG_TRY(CryptGetHashParam(hHash, HP_HASHVAL, pDerivedKeyInfo->rgbHashValB, &(pDerivedKeyInfo->cbHB), 0));
|
|
*/
|
|
|
|
|
|
//
|
|
// Derive a session key from the resulting hash object
|
|
//
|
|
LOG_TRY(TDeriveKey(
|
|
hProv,
|
|
pDerivedKeyInfo->aiKey,
|
|
hHash,
|
|
CRYPT_EXPORTABLE | (pDerivedKeyInfo->dwKeySize) << 16,
|
|
&hSessionKey,
|
|
ptc));
|
|
|
|
// Debug
|
|
/*
|
|
pDerivedKeyInfo->cbCB = 10;
|
|
LOG_TRY(CryptEncrypt(hSessionKey, 0, TRUE, 0, pDerivedKeyInfo->rgbCipherB, &(pDerivedKeyInfo->cbCB), sizeof(pDerivedKeyInfo->rgbCipherA)));
|
|
*/
|
|
|
|
|
|
//
|
|
// Export the session key in plaintext form
|
|
//
|
|
LOG_TRY(ExportPlaintextSessionKey(hSessionKey, hProv, &dbSessionKey, ptc));
|
|
|
|
// Debug
|
|
/*
|
|
PrintBytes(L"SessionA", pDerivedKeyInfo->dbKey.pbData, pDerivedKeyInfo->dbKey.cbData);
|
|
PrintBytes(L"SessionB", dbSessionKey.pbData, dbSessionKey.cbData);
|
|
*/
|
|
|
|
//
|
|
// Fudge the data comparison slightly since the RSA cipher text blob
|
|
// actually contains mostly random padding in this case (having
|
|
// used ExportPlaintextSessionKey(), only the first <key length>
|
|
// bytes of the cipher data are interesting).
|
|
//
|
|
// Therefor, compare the following number of bytes in the blobs. The
|
|
// rest of it won't match.
|
|
//
|
|
// sizeof(BLOBHEADER) + sizeof(ALG_ID) + dwKeySize / 8
|
|
//
|
|
cbValidData = sizeof(BLOBHEADER) + sizeof(ALG_ID) + pDerivedKeyInfo->dwKeySize / 8;
|
|
dbSessionKey.cbData = cbValidData;
|
|
pDerivedKeyInfo->dbKey.cbData = cbValidData;
|
|
|
|
LOG_TRY(IsDataEqual(
|
|
&dbSessionKey,
|
|
&(pDerivedKeyInfo->dbKey),
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hSessionKey)
|
|
{
|
|
TDestroyKey(hSessionKey, ptc);
|
|
}
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
if (dbSessionKey.pbData)
|
|
{
|
|
free(dbSessionKey.pbData);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: CheckSignedData
|
|
//
|
|
BOOL CheckSignedData(
|
|
IN PSIGNED_DATA_INFO pSignedDataInfo,
|
|
IN HCRYPTPROV hProv,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTHASH hHash = 0;
|
|
HCRYPTKEY hPubKey = 0;
|
|
|
|
//
|
|
// Create a hash and hash the provided data
|
|
//
|
|
if (! CreateHashAndAddData(
|
|
hProv,
|
|
&hHash,
|
|
&(pSignedDataInfo->HashInfo),
|
|
ptc,
|
|
0, NULL))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Import the public key corresponding to the private key
|
|
// that was used to sign the hashed data.
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProv,
|
|
pSignedDataInfo->dbPublicKey.pbData,
|
|
pSignedDataInfo->dbPublicKey.cbData,
|
|
0,
|
|
0,
|
|
&hPubKey,
|
|
ptc));
|
|
|
|
LOG_TRY(TVerifySign(
|
|
hHash,
|
|
pSignedDataInfo->dbSignature.pbData,
|
|
pSignedDataInfo->dbSignature.cbData,
|
|
hPubKey,
|
|
NULL,
|
|
0,
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
if (hPubKey)
|
|
{
|
|
TDestroyKey(hPubKey, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: PrepareCipherBuffer
|
|
// Purpose: Allocate a buffer to receive encrypted data based
|
|
// on the size of the data to encrypt, and based on whether
|
|
// the cipher is block or stream.
|
|
//
|
|
BOOL PrepareCipherBuffer(
|
|
OUT PDATA_BLOB pdbTargetBuffer,
|
|
IN PDATA_BLOB pdbSourceBuffer,
|
|
IN DWORD cbBlockLen,
|
|
IN BOOL fIsBlockCipher,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (fIsBlockCipher)
|
|
{
|
|
//
|
|
// Determine the maximum length of the cipher text for
|
|
// this block cipher. The length of the cipher text is
|
|
// up to block length more than the length of the plaintext.
|
|
//
|
|
pdbTargetBuffer->cbData =
|
|
pdbSourceBuffer->cbData + cbBlockLen - (pdbSourceBuffer->cbData % cbBlockLen);
|
|
}
|
|
else
|
|
{
|
|
pdbTargetBuffer->cbData = pdbSourceBuffer->cbData;
|
|
}
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pdbTargetBuffer->pbData),
|
|
pdbTargetBuffer->cbData,
|
|
ptc));
|
|
|
|
memcpy(
|
|
pdbTargetBuffer->pbData,
|
|
pdbSourceBuffer->pbData,
|
|
pdbSourceBuffer->cbData);
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: DoBlockCipherOperation
|
|
// Purpose: Perform the block cipher operation indicated in the Op parameter
|
|
// on the data stored in the pdbSource parameter. The processed data
|
|
// will be in pdbTarget.
|
|
//
|
|
BOOL DoBlockCipherOperation(
|
|
IN HCRYPTKEY hKey,
|
|
OUT PDATA_BLOB pdbTarget,
|
|
IN PDATA_BLOB pdbSource,
|
|
IN DWORD cbBlockLen,
|
|
IN CIPHER_OP Op,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DWORD cbCurrent = CIPHER_BLOCKS_PER_ROUND * cbBlockLen;
|
|
DWORD cbProcessed = 0;
|
|
BOOL fFinal = FALSE;
|
|
DWORD dwKeyAlg = 0;
|
|
DWORD cb = 0;
|
|
|
|
switch ( Op )
|
|
{
|
|
case OP_Encrypt:
|
|
{
|
|
LOG_TRY(PrepareCipherBuffer(
|
|
pdbTarget,
|
|
pdbSource,
|
|
cbBlockLen,
|
|
TRUE,
|
|
ptc));
|
|
|
|
while (cbCurrent < pdbSource->cbData)
|
|
{
|
|
LOG_TRY(TEncrypt(
|
|
hKey,
|
|
0,
|
|
fFinal,
|
|
0,
|
|
pdbTarget->pbData + cbProcessed,
|
|
&cbCurrent,
|
|
pdbTarget->cbData - cbProcessed,
|
|
ptc));
|
|
|
|
if (fFinal)
|
|
{
|
|
break;
|
|
}
|
|
|
|
cbProcessed += cbCurrent;
|
|
|
|
if ((cbProcessed + cbCurrent) >= pdbSource->cbData)
|
|
{
|
|
cbCurrent = pdbSource->cbData - cbProcessed;
|
|
fFinal = TRUE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OP_Decrypt:
|
|
{
|
|
//
|
|
// For block decryption, the decrypted data will be no
|
|
// larger than the cipher text.
|
|
//
|
|
pdbTarget->cbData = pdbSource->cbData;
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pdbTarget->pbData),
|
|
pdbTarget->cbData,
|
|
ptc));
|
|
|
|
memcpy(pdbTarget->pbData, pdbSource->pbData, pdbTarget->cbData);
|
|
|
|
//
|
|
// Known 3DES_112 bug in Windows 2000. Specifying a 112
|
|
// bit key size, rather than 128 bits, causes the last two
|
|
// bytes of key data to be random.
|
|
//
|
|
cb = sizeof(dwKeyAlg);
|
|
LOG_TRY(TGetKey(
|
|
hKey,
|
|
KP_ALGID,
|
|
(PBYTE) &dwKeyAlg,
|
|
&cb,
|
|
0,
|
|
ptc));
|
|
|
|
if (CALG_3DES_112 == dwKeyAlg)
|
|
{
|
|
ptc->KnownErrorID = KNOWN_TESTDECRYPTPROC_3DES112;
|
|
ptc->pwszErrorHelp = L"Inconsistent encryption results when using a 14 byte 3DES_112 key";
|
|
}
|
|
|
|
while (cbCurrent < pdbTarget->cbData)
|
|
{
|
|
LOG_TRY(TDecrypt(
|
|
hKey,
|
|
0,
|
|
fFinal,
|
|
0,
|
|
pdbTarget->pbData + cbProcessed,
|
|
&cbCurrent,
|
|
ptc));
|
|
|
|
if (fFinal)
|
|
{
|
|
//
|
|
// Set the size of the actual resulting plaintext.
|
|
//
|
|
pdbTarget->cbData = cbProcessed + cbCurrent;
|
|
break;
|
|
}
|
|
|
|
cbProcessed += cbCurrent;
|
|
|
|
if ((cbProcessed + cbCurrent) >= pdbTarget->cbData)
|
|
{
|
|
cbCurrent = pdbTarget->cbData - cbProcessed;
|
|
fFinal = TRUE;
|
|
}
|
|
}
|
|
|
|
ptc->KnownErrorID = KNOWN_ERROR_UNKNOWN;
|
|
ptc->pwszErrorHelp = NULL;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: DoStreamCipherOperation
|
|
// Purpose: Perform the stream cipher operation indicated in the Op parameter
|
|
// on the data stored in the pdbSource parameter. The processed data
|
|
// will be in pdbTarget.
|
|
//
|
|
BOOL DoStreamCipherOperation(
|
|
IN HCRYPTKEY hKey,
|
|
OUT PDATA_BLOB pdbTarget,
|
|
IN PDATA_BLOB pdbSource,
|
|
IN CIPHER_OP Op,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DWORD cbData = pdbSource->cbData;
|
|
|
|
switch ( Op )
|
|
{
|
|
case OP_Encrypt:
|
|
{
|
|
LOG_TRY(PrepareCipherBuffer(
|
|
pdbTarget,
|
|
pdbSource,
|
|
0,
|
|
FALSE,
|
|
ptc));
|
|
|
|
LOG_TRY(TEncrypt(
|
|
hKey,
|
|
0,
|
|
TRUE,
|
|
0,
|
|
pdbTarget->pbData,
|
|
&cbData,
|
|
pdbTarget->cbData,
|
|
ptc));
|
|
|
|
break;
|
|
}
|
|
case OP_Decrypt:
|
|
{
|
|
pdbTarget->cbData = pdbSource->cbData;
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pdbTarget->pbData),
|
|
pdbTarget->cbData,
|
|
ptc));
|
|
|
|
memcpy(pdbTarget->pbData, pdbSource->pbData, pdbTarget->cbData);
|
|
|
|
LOG_TRY(TDecrypt(
|
|
hKey,
|
|
0,
|
|
TRUE,
|
|
0,
|
|
pdbTarget->pbData,
|
|
&cbData,
|
|
ptc));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: ProcessCipherData
|
|
//
|
|
BOOL ProcessCipherData(
|
|
IN HCRYPTPROV hProvA,
|
|
IN OUT PTEST_ENCRYPT_INFO pTestEncryptInfo,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hKey = 0;
|
|
DWORD cbData = 0;
|
|
DWORD cbBlockLen = 0;
|
|
//DWORD cbProcessed = 0;
|
|
//DWORD cbCurrent = 0;
|
|
//BOOL fFinal = FALSE;
|
|
|
|
//
|
|
// Create the key
|
|
//
|
|
LOG_TRY(TGenKey(
|
|
hProvA,
|
|
pTestEncryptInfo->aiKeyAlg,
|
|
CRYPT_EXPORTABLE | (pTestEncryptInfo->dwKeySize << 16),
|
|
&hKey,
|
|
ptc));
|
|
|
|
//
|
|
// Generate the salt, if requested
|
|
//
|
|
if (pTestEncryptInfo->fUseSalt)
|
|
{
|
|
//
|
|
// Microsoft CSP's have a maximum key + salt length of
|
|
// 128 bits, but the test will set a long salt value
|
|
// regardless of the key size to ensure
|
|
// that possible interop issues are exposed.
|
|
//
|
|
LOG_TRY(TestAlloc(
|
|
&(pTestEncryptInfo->dbSalt.pbData),
|
|
DEFAULT_SALT_LEN,
|
|
ptc));
|
|
pTestEncryptInfo->dbSalt.cbData = DEFAULT_SALT_LEN;
|
|
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_SALT_EX,
|
|
(PBYTE) &(pTestEncryptInfo->dbSalt),
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Set the cipher mode, if requested
|
|
//
|
|
if (pTestEncryptInfo->fSetMode)
|
|
{
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_MODE,
|
|
(PBYTE) &(pTestEncryptInfo->dwMode),
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Determine cipher block len, if applicable
|
|
//
|
|
if (ALG_TYPE_BLOCK & pTestEncryptInfo->aiKeyAlg)
|
|
{
|
|
cbData = sizeof(cbBlockLen);
|
|
LOG_TRY(TGetKey(
|
|
hKey,
|
|
KP_BLOCKLEN,
|
|
(PBYTE) &cbBlockLen,
|
|
&cbData,
|
|
0,
|
|
ptc));
|
|
|
|
// Block length is returned in bits
|
|
cbBlockLen = cbBlockLen / 8;
|
|
pTestEncryptInfo->cbBlockLen = cbBlockLen;
|
|
}
|
|
|
|
//
|
|
// Set the IV, if requested
|
|
//
|
|
// If caller has requested an IV for a stream cipher,
|
|
// these calls may fail.
|
|
//
|
|
if (pTestEncryptInfo->fSetIV)
|
|
{
|
|
//
|
|
// Size of IV must be equal to cipher block length
|
|
//
|
|
LOG_TRY(TestAlloc(
|
|
&(pTestEncryptInfo->pbIV),
|
|
cbBlockLen,
|
|
ptc));
|
|
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_IV,
|
|
pTestEncryptInfo->pbIV,
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Generate the base data
|
|
//
|
|
if (ALG_TYPE_BLOCK & pTestEncryptInfo->aiKeyAlg)
|
|
{
|
|
//
|
|
// To create a "better" block cipher test scenario,
|
|
// the base data will not be an exact multiple of the
|
|
// block length. This will allow an interesting multi-round
|
|
// encryption, with the last round requiring less than a block
|
|
// length of padding.
|
|
//
|
|
// data len = BLOCKS_IN_BASE_DATA * cbBlockLen - 1byte
|
|
//
|
|
pTestEncryptInfo->dbBaseData.cbData = BLOCKS_IN_BASE_DATA * cbBlockLen - 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set base data len for a stream cipher
|
|
//
|
|
pTestEncryptInfo->dbBaseData.cbData = STREAM_CIPHER_BASE_DATA_LEN;
|
|
}
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pTestEncryptInfo->dbBaseData.pbData),
|
|
pTestEncryptInfo->dbBaseData.cbData,
|
|
ptc));
|
|
|
|
LOG_TRY(TGenRand(
|
|
hProvA,
|
|
pTestEncryptInfo->dbBaseData.cbData,
|
|
pTestEncryptInfo->dbBaseData.pbData,
|
|
ptc));
|
|
|
|
//
|
|
// Call DoBlockCipherOperation or DoStreamCipherOperation,
|
|
// depending on the cipher algorithm, to perform the requested
|
|
// operation.
|
|
//
|
|
if (ALG_TYPE_BLOCK & pTestEncryptInfo->aiKeyAlg)
|
|
{
|
|
LOG_TRY(DoBlockCipherOperation(
|
|
hKey,
|
|
&(pTestEncryptInfo->dbProcessedData),
|
|
&(pTestEncryptInfo->dbBaseData),
|
|
cbBlockLen,
|
|
pTestEncryptInfo->Operation,
|
|
ptc));
|
|
}
|
|
else
|
|
{
|
|
LOG_TRY(DoStreamCipherOperation(
|
|
hKey,
|
|
&(pTestEncryptInfo->dbProcessedData),
|
|
&(pTestEncryptInfo->dbBaseData),
|
|
pTestEncryptInfo->Operation,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Export the session key in plain text
|
|
//
|
|
LOG_TRY(ExportPlaintextSessionKey(
|
|
hKey,
|
|
hProvA,
|
|
&(pTestEncryptInfo->dbKey),
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hKey)
|
|
{
|
|
TDestroyKey(hKey, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: VerifyCipherData
|
|
//
|
|
BOOL VerifyCipherData(
|
|
IN HCRYPTPROV hProvB,
|
|
IN PTEST_ENCRYPT_INFO pTestEncryptInfo,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hKey = 0;
|
|
CIPHER_OP Op;
|
|
DATA_BLOB dbData;
|
|
|
|
memset(&dbData, 0, sizeof(dbData));
|
|
|
|
//
|
|
// Import the plaintext session key
|
|
//
|
|
LOG_TRY(ImportPlaintextSessionKey(
|
|
&(pTestEncryptInfo->dbKey),
|
|
&hKey,
|
|
hProvB,
|
|
ptc));
|
|
|
|
if (pTestEncryptInfo->fUseSalt)
|
|
{
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_SALT_EX,
|
|
(PBYTE) &(pTestEncryptInfo->dbSalt),
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Set the salt value, if requested
|
|
//
|
|
if (pTestEncryptInfo->fUseSalt)
|
|
{
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_SALT_EX,
|
|
(PBYTE) &(pTestEncryptInfo->dbSalt),
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Set the cipher mode, if requested
|
|
//
|
|
if (pTestEncryptInfo->fSetMode)
|
|
{
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_MODE,
|
|
(PBYTE) &(pTestEncryptInfo->dwMode),
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// Set the IV, if requested
|
|
//
|
|
if (pTestEncryptInfo->fSetIV)
|
|
{
|
|
LOG_TRY(TSetKey(
|
|
hKey,
|
|
KP_IV,
|
|
pTestEncryptInfo->pbIV,
|
|
0,
|
|
ptc));
|
|
}
|
|
|
|
//
|
|
// The verification operation should be the opposite of what
|
|
// the caller initially specified (the opposite of the operation
|
|
// performed in ProcessCipherData).
|
|
//
|
|
Op = (OP_Encrypt == pTestEncryptInfo->Operation) ? OP_Decrypt : OP_Encrypt;
|
|
|
|
//
|
|
// Call DoBlockCipherOperation or DoStreamCipherOperation,
|
|
// depending on the cipher algorithm, to perform the requested
|
|
// operation.
|
|
//
|
|
if (ALG_TYPE_BLOCK & pTestEncryptInfo->aiKeyAlg)
|
|
{
|
|
LOG_TRY(DoBlockCipherOperation(
|
|
hKey,
|
|
&dbData,
|
|
&(pTestEncryptInfo->dbProcessedData),
|
|
pTestEncryptInfo->cbBlockLen,
|
|
Op,
|
|
ptc));
|
|
}
|
|
else
|
|
{
|
|
LOG_TRY(DoStreamCipherOperation(
|
|
hKey,
|
|
&dbData,
|
|
&(pTestEncryptInfo->dbProcessedData),
|
|
Op,
|
|
ptc));
|
|
}
|
|
|
|
if (CALG_3DES_112 == pTestEncryptInfo->aiKeyAlg)
|
|
{
|
|
ptc->KnownErrorID = KNOWN_TESTDECRYPTPROC_3DES112;
|
|
}
|
|
|
|
LOG_TRY(IsDataEqual(&dbData, &(pTestEncryptInfo->dbBaseData), ptc));
|
|
|
|
ptc->KnownErrorID = KNOWN_ERROR_UNKNOWN;
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hKey)
|
|
{
|
|
TDestroyKey(hKey, ptc);
|
|
}
|
|
if (dbData.pbData)
|
|
{
|
|
free(dbData.pbData);
|
|
}
|
|
if (pTestEncryptInfo->dbBaseData.pbData)
|
|
{
|
|
free(pTestEncryptInfo->dbBaseData.pbData);
|
|
}
|
|
if (pTestEncryptInfo->dbProcessedData.pbData)
|
|
{
|
|
free(pTestEncryptInfo->dbProcessedData.pbData);
|
|
}
|
|
if (pTestEncryptInfo->dbKey.pbData)
|
|
{
|
|
free(pTestEncryptInfo->dbKey.pbData);
|
|
}
|
|
if (pTestEncryptInfo->pbIV)
|
|
{
|
|
free(pTestEncryptInfo->pbIV);
|
|
}
|
|
if (pTestEncryptInfo->dbSalt.pbData)
|
|
{
|
|
free(pTestEncryptInfo->dbSalt.pbData);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: GetHashVal
|
|
// Purpose: Populate a data blob with the hash value from the
|
|
// provided hash handle.
|
|
//
|
|
BOOL GetHashVal(
|
|
IN HCRYPTHASH hHash,
|
|
OUT PDATA_BLOB pdb,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LOG_TRY(TGetHash(
|
|
hHash,
|
|
HP_HASHVAL,
|
|
NULL,
|
|
&(pdb->cbData),
|
|
0,
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(&(pdb->pbData), pdb->cbData, ptc));
|
|
|
|
LOG_TRY(TGetHash(
|
|
hHash,
|
|
HP_HASHVAL,
|
|
pdb->pbData,
|
|
&(pdb->cbData),
|
|
0,
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: CreateHashedSessionKey
|
|
//
|
|
BOOL CreateHashedSessionKey(
|
|
IN HCRYPTPROV hProv,
|
|
IN OUT PHASH_SESSION_INFO pHashSessionInfo,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hKey = 0;
|
|
HCRYPTHASH hHash = 0;
|
|
|
|
LOG_TRY(TGenKey(
|
|
hProv,
|
|
pHashSessionInfo->aiKey,
|
|
CRYPT_EXPORTABLE | (pHashSessionInfo->dwKeySize << 16),
|
|
&hKey,
|
|
ptc));
|
|
|
|
LOG_TRY(TCreateHash(
|
|
hProv,
|
|
pHashSessionInfo->aiHash,
|
|
0,
|
|
0,
|
|
&hHash,
|
|
ptc));
|
|
|
|
LOG_TRY(THashSession(hHash, hKey, pHashSessionInfo->dwFlags, ptc));
|
|
|
|
LOG_TRY(GetHashVal(hHash, &(pHashSessionInfo->dbHash), ptc));
|
|
|
|
LOG_TRY(ExportPlaintextSessionKey(
|
|
hKey,
|
|
hProv,
|
|
&(pHashSessionInfo->dbKey),
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hKey)
|
|
{
|
|
TDestroyKey(hKey, ptc);
|
|
}
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: VerifyHashedSessionKey
|
|
// Purpose: Import the plaintext session key into a separate CSP.
|
|
// Hash the session key with CryptHashSessionKey. Verify
|
|
// the resulting hash value.
|
|
//
|
|
BOOL VerifyHashedSessionKey(
|
|
IN HCRYPTPROV hInteropProv,
|
|
IN PHASH_SESSION_INFO pHashSessionInfo,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hKey = 0;
|
|
HCRYPTHASH hHash = 0;
|
|
DATA_BLOB dbInteropHash;
|
|
|
|
memset(&dbInteropHash, 0, sizeof(dbInteropHash));
|
|
|
|
LOG_TRY(ImportPlaintextSessionKey(
|
|
&(pHashSessionInfo->dbKey),
|
|
&hKey,
|
|
hInteropProv,
|
|
ptc));
|
|
|
|
LOG_TRY(TCreateHash(
|
|
hInteropProv,
|
|
pHashSessionInfo->aiHash,
|
|
0,
|
|
0,
|
|
&hHash,
|
|
ptc));
|
|
|
|
LOG_TRY(THashSession(hHash, hKey, pHashSessionInfo->dwFlags, ptc));
|
|
|
|
LOG_TRY(GetHashVal(hHash, &dbInteropHash, ptc));
|
|
|
|
LOG_TRY(IsDataEqual(&(pHashSessionInfo->dbHash), &dbInteropHash, ptc));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (hKey)
|
|
{
|
|
TDestroyKey(hKey, ptc);
|
|
}
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
if (dbInteropHash.pbData)
|
|
{
|
|
free(dbInteropHash.pbData);
|
|
}
|
|
if (pHashSessionInfo->dbHash.pbData)
|
|
{
|
|
free(pHashSessionInfo->dbHash.pbData);
|
|
}
|
|
if (pHashSessionInfo->dbKey.pbData)
|
|
{
|
|
free(pHashSessionInfo->dbKey.pbData);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: RSA1_CreateKeyPair
|
|
//
|
|
BOOL RSA1_CreateKeyPair(
|
|
IN HCRYPTPROV hProvA,
|
|
IN PKEYEXCHANGE_INFO pKeyExchangeInfo,
|
|
OUT PKEYEXCHANGE_STATE pKeyExchangeState,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hPubKeyA = 0;
|
|
|
|
//
|
|
// Create an RSA key exchange key pair and export the public
|
|
// key.
|
|
//
|
|
LOG_TRY(TGenKey(
|
|
hProvA,
|
|
AT_KEYEXCHANGE,
|
|
(pKeyExchangeInfo->dwPubKeySize << 16) | CRYPT_EXPORTABLE,
|
|
&hPubKeyA,
|
|
ptc));
|
|
|
|
if (! ExportPublicKey(hPubKeyA, &(pKeyExchangeState->dbPubKeyA), ptc))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hPubKeyA)
|
|
{
|
|
TDestroyKey(hPubKeyA, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: RSA2_EncryptPlainText
|
|
//
|
|
BOOL RSA2_EncryptPlainText(
|
|
IN HCRYPTPROV hProvB,
|
|
IN PKEYEXCHANGE_INFO pKeyExchangeInfo,
|
|
IN OUT PKEYEXCHANGE_STATE pKeyExchangeState,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HCRYPTKEY hSessionKeyB = 0;
|
|
HCRYPTKEY hPubKeyB = 0;
|
|
HCRYPTKEY hPubKeyA = 0;
|
|
HCRYPTHASH hHash = 0;
|
|
//DWORD cbBuffer = 0;
|
|
DWORD cbData = 0;
|
|
|
|
//
|
|
// User B creates an RSA signature key pair
|
|
//
|
|
LOG_TRY(TGenKey(
|
|
hProvB,
|
|
AT_SIGNATURE,
|
|
(pKeyExchangeInfo->dwPubKeySize << 16) | CRYPT_EXPORTABLE,
|
|
&hPubKeyB,
|
|
ptc));
|
|
|
|
//
|
|
// Create hash and session key
|
|
//
|
|
LOG_TRY(TCreateHash(
|
|
hProvB,
|
|
pKeyExchangeInfo->aiHash,
|
|
0,
|
|
0,
|
|
&hHash,
|
|
ptc));
|
|
|
|
LOG_TRY(TGenKey(
|
|
hProvB,
|
|
pKeyExchangeInfo->aiSessionKey,
|
|
(pKeyExchangeInfo->dwSessionKeySize << 16) | CRYPT_EXPORTABLE,
|
|
&hSessionKeyB,
|
|
ptc));
|
|
|
|
//
|
|
// Encrypt and hash the data simultaneously
|
|
//
|
|
cbData = pKeyExchangeState->dbCipherTextB.cbData = pKeyExchangeInfo->dbPlainText.cbData;
|
|
|
|
LOG_TRY(TEncrypt(
|
|
hSessionKeyB,
|
|
0,
|
|
TRUE,
|
|
0,
|
|
NULL,
|
|
&(pKeyExchangeState->dbCipherTextB.cbData),
|
|
0,
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pKeyExchangeState->dbCipherTextB.pbData),
|
|
pKeyExchangeState->dbCipherTextB.cbData,
|
|
ptc));
|
|
|
|
memcpy(
|
|
pKeyExchangeState->dbCipherTextB.pbData,
|
|
pKeyExchangeInfo->dbPlainText.pbData,
|
|
cbData);
|
|
|
|
LOG_TRY(TEncrypt(
|
|
hSessionKeyB,
|
|
hHash,
|
|
TRUE,
|
|
0,
|
|
pKeyExchangeState->dbCipherTextB.pbData,
|
|
&cbData,
|
|
pKeyExchangeState->dbCipherTextB.cbData,
|
|
ptc));
|
|
|
|
//
|
|
// Now sign the hashed plain text
|
|
//
|
|
LOG_TRY(TSignHash(
|
|
hHash,
|
|
AT_SIGNATURE,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&(pKeyExchangeState->dbSignatureB.cbData),
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pKeyExchangeState->dbSignatureB.pbData),
|
|
pKeyExchangeState->dbSignatureB.cbData,
|
|
ptc));
|
|
|
|
LOG_TRY(TSignHash(
|
|
hHash,
|
|
AT_SIGNATURE,
|
|
NULL,
|
|
0,
|
|
pKeyExchangeState->dbSignatureB.pbData,
|
|
&(pKeyExchangeState->dbSignatureB.cbData),
|
|
ptc));
|
|
|
|
//
|
|
// Import User A's public key. Then export User B's session key encrypted
|
|
// with User A's public key.
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProvB,
|
|
pKeyExchangeState->dbPubKeyA.pbData,
|
|
pKeyExchangeState->dbPubKeyA.cbData,
|
|
0,
|
|
0,
|
|
&hPubKeyA,
|
|
ptc));
|
|
|
|
LOG_TRY(TExportKey(
|
|
hSessionKeyB,
|
|
hPubKeyA,
|
|
SIMPLEBLOB,
|
|
0,
|
|
NULL,
|
|
&(pKeyExchangeState->dbEncryptedSessionKeyB.cbData),
|
|
ptc));
|
|
|
|
LOG_TRY(TestAlloc(
|
|
&(pKeyExchangeState->dbEncryptedSessionKeyB.pbData),
|
|
pKeyExchangeState->dbEncryptedSessionKeyB.cbData,
|
|
ptc));
|
|
|
|
LOG_TRY(TExportKey(
|
|
hSessionKeyB,
|
|
hPubKeyA,
|
|
SIMPLEBLOB,
|
|
0,
|
|
pKeyExchangeState->dbEncryptedSessionKeyB.pbData,
|
|
&(pKeyExchangeState->dbEncryptedSessionKeyB.cbData),
|
|
ptc));
|
|
|
|
//
|
|
// Export User B's public key so that User A can verify the signed data
|
|
//
|
|
if (! ExportPublicKey(hPubKeyB, &(pKeyExchangeState->dbPubKeyB), ptc))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hSessionKeyB)
|
|
{
|
|
TDestroyKey(hSessionKeyB, ptc);
|
|
}
|
|
if (hPubKeyB)
|
|
{
|
|
TDestroyKey(hPubKeyB, ptc);
|
|
}
|
|
if (hPubKeyA)
|
|
{
|
|
TDestroyKey(hPubKeyA, ptc);
|
|
}
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: RSA3_DecryptAndCheck
|
|
//
|
|
BOOL RSA3_DecryptAndCheck(
|
|
IN HCRYPTPROV hProvA,
|
|
IN PKEYEXCHANGE_INFO pKeyExchangeInfo,
|
|
IN PKEYEXCHANGE_STATE pKeyExchangeState,
|
|
IN PTESTCASE ptc)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
HCRYPTKEY hPubKeyA = 0;
|
|
HCRYPTKEY hPubKeyB = 0;
|
|
HCRYPTKEY hSessionKey = 0;
|
|
HCRYPTHASH hHash = 0;
|
|
|
|
//
|
|
// Get User A's RSA key exchange key handle
|
|
//
|
|
LOG_TRY(TGetUser(
|
|
hProvA,
|
|
AT_KEYEXCHANGE,
|
|
&hPubKeyA,
|
|
ptc));
|
|
|
|
//
|
|
// Import and decrypt the session key from User B
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProvA,
|
|
pKeyExchangeState->dbEncryptedSessionKeyB.pbData,
|
|
pKeyExchangeState->dbEncryptedSessionKeyB.cbData,
|
|
hPubKeyA,
|
|
0,
|
|
&hSessionKey,
|
|
ptc));
|
|
|
|
//
|
|
// Create a hash. Then simultaneously decrypt the cipher text and
|
|
// hash the resulting plain text.
|
|
//
|
|
LOG_TRY(TCreateHash(
|
|
hProvA,
|
|
pKeyExchangeInfo->aiHash,
|
|
0,
|
|
0,
|
|
&hHash,
|
|
ptc));
|
|
|
|
LOG_TRY(TDecrypt(
|
|
hSessionKey,
|
|
hHash,
|
|
TRUE,
|
|
0,
|
|
pKeyExchangeState->dbCipherTextB.pbData,
|
|
&(pKeyExchangeState->dbCipherTextB.cbData),
|
|
ptc));
|
|
|
|
//
|
|
// Import User B's signature public key.
|
|
//
|
|
LOG_TRY(TImportKey(
|
|
hProvA,
|
|
pKeyExchangeState->dbPubKeyB.pbData,
|
|
pKeyExchangeState->dbPubKeyB.cbData,
|
|
0,
|
|
0,
|
|
&hPubKeyB,
|
|
ptc));
|
|
|
|
//
|
|
// Verify the signature blob
|
|
//
|
|
LOG_TRY(TVerifySign(
|
|
hHash,
|
|
pKeyExchangeState->dbSignatureB.pbData,
|
|
pKeyExchangeState->dbSignatureB.cbData,
|
|
hPubKeyB,
|
|
NULL,
|
|
0,
|
|
ptc));
|
|
|
|
fSuccess = TRUE;
|
|
Cleanup:
|
|
|
|
if (hSessionKey)
|
|
{
|
|
TDestroyKey(hSessionKey, ptc);
|
|
}
|
|
if (hPubKeyA)
|
|
{
|
|
TDestroyKey(hPubKeyA, ptc);
|
|
}
|
|
if (hPubKeyB)
|
|
{
|
|
TDestroyKey(hPubKeyB, ptc);
|
|
}
|
|
if (hHash)
|
|
{
|
|
TDestroyHash(hHash, ptc);
|
|
}
|
|
if (pKeyExchangeState->dbCipherTextB.pbData)
|
|
{
|
|
free(pKeyExchangeState->dbCipherTextB.pbData);
|
|
}
|
|
if (pKeyExchangeState->dbPubKeyA.pbData)
|
|
{
|
|
free(pKeyExchangeState->dbPubKeyA.pbData);
|
|
}
|
|
if (pKeyExchangeState->dbPubKeyB.pbData)
|
|
{
|
|
free(pKeyExchangeState->dbPubKeyB.pbData);
|
|
}
|
|
if (pKeyExchangeState->dbSignatureB.pbData)
|
|
{
|
|
free(pKeyExchangeState->dbSignatureB.pbData);
|
|
}
|
|
if (pKeyExchangeState->dbEncryptedSessionKeyB.pbData)
|
|
{
|
|
free(pKeyExchangeState->dbEncryptedSessionKeyB.pbData);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|