I am using the CryptoAPI and initializing the hash with CBC and an IV to create a random encrypted string each time the same string is encrypted. I then try and decrypt but only get a partial string. I'm missing something simple here (I hope!). Can someone help me?
Example of [expected] encrypted binary string:
W»½¬{èeüÔÓoE付bnx=s„?äèÍÙÎÛg°fÒéò½üír&¯ñ\œÅö»R
Example of [messed up!] decrypted binary string:
c±O Ê›©qtœ‘þH² mother were hanging up clothes
UPDATE: So what is happening is when I take this code and put it into a DLL, each function Aes*() calls AesInitialization() separately. So an encrypted string will have its own IV.
QUESTION: How do I send the IV with the ciphertext to fix this?
Here is my working sample:
#include <iostream>
#include <windows.h>
#include <wincrypt.h>
using std::string;
const char *key = "yM7TbMuL3TNUmeBs1Mqdw73G2BmMBHHV7cDAF3V5v9FAOqYc0mF133T8WE5foqAG3rJAK8dU1hKc";
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
#define AES_BLOCK_SIZE 16
BOOL AesInitialization()
{
// Set hCryptProv and hKey
HCRYPTHASH hHash = NULL;
BOOL result = FALSE;
if (CryptAcquireContextW(&hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
if (CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash))
if (CryptHashData(hHash, (BYTE*)key, strlen(key), 0))
if (CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey))
{
DWORD dwMode = CRYPT_MODE_CBC;
result = CryptSetKeyParam(hKey, KP_MODE, (BYTE *)&dwMode, 0);
}
if (hHash != NULL)
CryptDestroyHash(hHash);
return result;
}
BOOL AesEncrypt(string &data)
{
BOOL result = TRUE;
string iv;
iv.resize(AES_BLOCK_SIZE); // allocate space for random IV
result = CryptGenRandom(hCryptProv, AES_BLOCK_SIZE, (BYTE *)&iv[0]);
if (result)
{
if (CryptSetKeyParam(hKey, KP_IV, (BYTE *) iv.c_str(), 0))
{
data = data + iv; // Append the random string
DWORD dwDataLen = data.length();
data.resize(dwDataLen + AES_BLOCK_SIZE); // give enough space for padding
result = CryptEncrypt(hKey, NULL, TRUE, 0, (BYTE *)&data[0], &dwDataLen, data.length());
data.resize(dwDataLen); // resize to actual ciphertext length
}
}
return result;
}
BOOL AesDecrypt(string &data)
{
BOOL success = TRUE;
string iv;
iv.resize(AES_BLOCK_SIZE); // ensure IV has the correct size
iv.assign(key);
if (CryptSetKeyParam(hKey, KP_IV, (BYTE*)iv.c_str(), 0))
{
if (CryptSetKeyParam(hKey, KP_IV, (BYTE*)&iv[0], 0))
{
DWORD dwDataLen = data.length();
success = CryptDecrypt(hKey, NULL, TRUE, 0, (BYTE *)&data[0], &dwDataLen);
data.resize(dwDataLen - AES_BLOCK_SIZE); // resize to actual ciphertext length
}
}
return success;
}
int main()
{
if (!AesInitialization())
return 1;
string message = "my mother & your mother were hanging up clothes";
string iv;
if (!AesEncrypt(message))
return 1;
if (!AesDecrypt(message))
return 1;
return 0;
}