/* interop.c 6/23/00 dangriff created */ #include #include #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 // 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; }