I need to encrypt data whose length longer than the block size(128 bits) using windows CryptoApi and aes128 CBC mode.
Iv'e tried multiple ways in order to achive this goal, none worked correctly. I know the theory behind chaining and I theoretically know what I have to do.
- split the buffer into block sized blocks
- pad if necessary
- xor first block with IV sized of block size
- encrypt buffer
- repeate it - xor the next block with the former
some of above is implemented by CryptoApi(like XORing the first block with the IV) - I red that padding is also being done by the CryptEncrypt when passing TRUE as Final parameter of the function (I may be wrong). I've also tried to pad each block manually using PKCS7 algorithm but it also didn't get the result. AES initialization code (this is where all the initialization of CryptoApi is done, including algorithm specifics such as IV and Key setting):
BOOL AesInitialization()
{
DWORD dwStatus;
HCRYPTHASH hHash;
string FinalIv;
if (!CryptAcquireContextW(&hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, NULL))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %x\n", dwStatus);
return FALSE;
}
if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash))
{
dwStatus = GetLastError();
printf("CryptCreateHash failed: %x\n", dwStatus);
clean();
return FALSE;
}
//FinalKey = key;
if (!CryptHashData(hHash, (BYTE*)key, strlen(key), 0))
{
dwStatus = GetLastError();
printf("CryptHashData Failed : %#x\n", dwStatus);
clean();
CryptDestroyHash(hHash);
return FALSE;
}
if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey))
{
dwStatus = GetLastError();
printf("CryptDeriveKey failed: %x\n", dwStatus);
clean();
CryptDestroyHash(hHash);
return FALSE;
}
printf("[+] CryptDeriveKey Success\n");
DWORD dwMode = CRYPT_MODE_CBC;
// Set the mode to Cipher Block Chaining
if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE *)&dwMode, 0))
{
dwStatus = GetLastError();
printf("CryptSetKeyParam - setting mode failed: %x\n", dwStatus);
clean();
CryptDestroyHash(hHash);
return FALSE;
}
// Set the Initialization Vector to ours
FinalIv = pad(Iv, AES_BLOCK_SIZE);
if (!CryptSetKeyParam(hKey, KP_IV, (BYTE *)&FinalIv[0], 0))
{
dwStatus = GetLastError();
printf("CryptSetKeyParam - setting IV failed: %x\n", dwStatus);
clean();
CryptDestroyHash(hHash);
return FALSE;
}
CryptDestroyHash(hHash);
AesStat = TRUE;
return TRUE;
}
this is the acctual part of code where encryption is done
/*My code has changed several times as I tried many ways to accomplish my
goal.
My current code(which doesn't include manual padding right now), looks
like this:*/
BOOL AesEncrypt(string & PlainTxt)
{
// deviding into blocks sized AES_BLOCK_SIZE
string cipher;
string encrypted;
DWORD block_length;
unsigned total_length = PlainTxt.length();
encrypted.resize(AES_BLOCK_SIZE * 2); // give enough space for padding
for (unsigned index = 0; index < total_length; index += AES_BLOCK_SIZE)
{
encrypted.clear(); // clear former content
memcpy_s(&encrypted[0], encrypted.size(), &PlainTxt[index], AES_BLOCK_SIZE);
block_length = AES_BLOCK_SIZE;
if (!CryptEncrypt(hKey, NULL, true, 0, (BYTE *)&encrypted[0], &block_length, encrypted.length()))
{
printf("aes failed with %d\n", GetLastError());
return FALSE;
}
cipher.append(encrypted.data()); // append data to final string
}
PlainTxt.clear();
PlainTxt.resize(cipher.size());
PlainTxt.append(cipher.data());
return TRUE;
}
The first iteration failed with 234 error(MORE_DATA) and legnth is set by CryptEncrypt to 0x80 (128, in bytes).