I have been trying to write some code to use the Microsoft CryptoAPI. The goal is very simple: encrypt and then decrypt a string. I seem to have it almost working, but the very last call to CryptDecryptMessage fails.
So, I am able to successfully encrypt my string. When I then take the encrypted binary string and try to decrypt it, everything works except the last call to CryptDecryptMessage . The decryption code I am using is below.
As the code stands, the first call to CryptDecryptMessage, to get the required size of the output buffer, succeeds, BUT it always returns a size equal to the cleartext string size plus 6. I then size up my output buffer, and the next call to CryptDecryptMessage fails (return value is zero, dwSizeRequired
gets set to zero, nothing is put in the output buffer, and GetLastError
returns NTE_BAD_KEY).
On the other hand, if I uncomment the #define TESTING_INCORRECT
line, the behaviour is slightly different. The first call to CryptDecryptMessage succeeds. Its return value is zero, but GetLastError
returns ERROR_MORE_DATA
, which one would expect, and most importantly dwSizeRequired
is set with the size of the original cleartext string that was encoded. I then allocate and call CryptDecryptMessage the second time, it fails again as above.
Lastly, I do have the private certificate key in my keystore.
Does anyone have any idea what is wrong here????? Thanks.
void decrypt(std::string& sClearTextString , const std::vector<T_Byte>& sEncryptedBinaryString, const std::string& sKey)
{
BOOL bResult;
HCRYPTPROV hProv;
bResult = CryptAcquireContext( &hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0);
CHECK_CRYPT_ERR( !bResult , "Unable to find crypto context");
HCERTSTORE hStore(NULL);
const char* const pcKey = sKey.empty()? "MY" : sKey.c_str();
hStore = CertOpenSystemStore( 0, pcKey);
CHECK_CRYPT_ERR( hStore==NULL, "unable to open certificate store.");
HCERTSTORE CertStoreArray[] = {hStore};
CRYPT_DECRYPT_MESSAGE_PARA DecryptParams;
DWORD DecryptParamsSize = sizeof(DecryptParams);
memset(&DecryptParams, 0, DecryptParamsSize);
DecryptParams.cbSize = DecryptParamsSize;
DecryptParams.dwMsgAndCertEncodingType = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING);
DecryptParams.cCertStore = sizeof(CertStoreArray)/sizeof(HCERTSTORE);
DecryptParams.rghCertStore = CertStoreArray;
const BYTE* const pbContent = &sEncryptedBinaryString[0];
DWORD dwSize = STATICCAST<DWORD>(sEncryptedBinaryString.size());
DWORD dwSizeRequired = 0;
BYTE* pbOutBuffer = NULL;
//#define TESTING_INCORRECT
#ifdef TESTING_INCORRECT
std::string sDummyBuffer(2,'\0');
pbOutBuffer = (BYTE*)(&sDummyBuffer[0]);
#endif
// Get required buffer size.
bResult = CryptDecryptMessage( &DecryptParams, pbContent, dwSize, pbOutBuffer, &dwSizeRequired, NULL);
CHECK_CRYPT_ERR( !bResult && ERROR_MORE_DATA != GetLastError() , "Unable to get buffer length");
//Allocate buffer
sClearTextString.clear();
sClearTextString.resize(dwSizeRequired+1,0);
pbOutBuffer = (BYTE*)(&sClearTextString[0]);
//Now actually decryt
bResult = CryptDecryptMessage( &DecryptParams, pbContent, dwSize, pbOutBuffer, &dwSizeRequired, NULL);
CHECK_CRYPT_ERR( !bResult , "Unable to decrypt");
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
CryptReleaseContext(hProv, 0);
}