I am trying to use Windows CNG BCRYPT_XTS_AES_ALGORITHM
algorithm to encrypt and decrypt the files. As part of this, I had written the following code for encryption and decryption.
When I use this code with BCRYPT_AES_ALGORITHM
algorithm, both encrypt and decrypt are working fine. But when the same is being used with BCRYPT_XTS_AES_ALGORITHM
, it is throwing the STATUS_INVALID_PARAMETER
error in BCryptGenerateSymmetricKey
API.
Any help on this is very much appreciated.
auto AesCrypt::CreateAESProviderAlgo()->void
{
auto status = BCryptOpenAlgorithmProvider(&m_aesHandle, BCRYPT_AES_ALGORITHM, nullptr, 0);
//auto status = BCryptOpenAlgorithmProvider(&m_aesHandle, BCRYPT_XTS_AES_ALGORITHM, nullptr, 0);
if (0 != status) {
N2S_THROW("BCryptException::Failed to get provider for BCRYPT_XTS_AES_ALGORITHM. Reason: " + GetErrorCodeAsString(status));
}
DWORD cbData = 0;
DWORD cbKeyObject = 0;
status = BCryptGetProperty(m_aesHandle, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbData, 0);
if (0 != status) {
N2S_THROW("CreateSymmetricKeySHA1Hash::BCryptGetProperty return with error " + GetErrorCodeAsString(status));
}
m_pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
if (nullptr == m_pbKeyObject) {
N2S_THROW("CreateSymmetricKeySHA1Hash::Memory allocation failed.");
}
status = BCryptGenerateSymmetricKey(m_aesHandle, &m_keyHandle, m_pbKeyObject, cbKeyObject, (PUCHAR)m_encrptKey.c_str(), SYMM_KEY_SIZE_SECRET, 0);
if (0 != status) {
N2S_THROW("CreateSymmetricKeySHA1Hash::BCryptGenerateSymmetricKey return with error " + GetErrorCodeAsString(status));
}
}
auto AesCrypt::ProcessEncryptFile() ->void
{
DWORD bytesToSave = 0;
UCHAR bufFileToOpen[BLOCK_SIZE] = { 0 };
UCHAR bufFileToSave[BLOCK_SIZE * 2] = { 0 }; // TODO: Need to alloc on heap and reuse it.
auto toReadBytes = GetFileSize(m_workOnFile);
for (;;) // TODO: Need to take out the duplicate code from both locations.
{
m_readStream.read((CHAR *)bufFileToOpen, BLOCK_SIZE);
auto bytesRead = m_readStream.gcount();
if (0 == bytesRead) {
N2S_THROW("Error reading the file " + GetStringFromWstring(m_workOnFile));
}
toReadBytes -= bytesRead;
if (0 != toReadBytes && bytesRead == BLOCK_SIZE) {
GetCryptStatus(BCryptEncrypt(m_keyHandle, bufFileToOpen, (ULONG)bytesRead, nullptr, nullptr, 0, bufFileToSave, (ULONG)bytesRead, &bytesToSave, 0));
m_writeStream.write((CHAR *)bufFileToSave, bytesToSave);
continue;
}
// Reading the last byte
if (0 != BCryptEncrypt(m_keyHandle, bufFileToOpen, (ULONG)bytesRead, nullptr, nullptr, 0, nullptr, 0, &bytesToSave, BCRYPT_BLOCK_PADDING)) {
N2S_THROW("BCryptEncrypt::Error receiving the size required for the ciphertext.");
}
GetCryptStatus(BCryptEncrypt(m_keyHandle, bufFileToOpen, (ULONG)bytesRead, nullptr, nullptr, 0, bufFileToSave, bytesToSave, &bytesToSave, BCRYPT_BLOCK_PADDING));
m_writeStream.write((CHAR *)bufFileToSave, bytesToSave);
return; // Last block done.
}
}
auto AesCrypt::ProcessDecryptFile()->void
{
DWORD bytesToSave = 0;
UCHAR bufFileToOpen[BLOCK_SIZE] = { 0 };
UCHAR bufFileToSave[BLOCK_SIZE * 2] = { 0 }; // TODO: Need to alloc on heap and reuse it.
auto toReadBytes = GetFileSize(m_workOnFile);
for (;;)
{
m_readStream.read((CHAR *)bufFileToOpen, BLOCK_SIZE);
auto bytesRead = m_readStream.gcount();
if (0 == bytesRead) {
N2S_THROW("Error reading the file " + GetStringFromWstring(m_workOnFile));
}
toReadBytes -= bytesRead;
if (0 != toReadBytes && bytesRead == BLOCK_SIZE) {
GetCryptStatus(BCryptDecrypt(m_keyHandle, bufFileToOpen, (ULONG)bytesRead, nullptr, nullptr, 0, bufFileToSave, (ULONG)bytesRead, &bytesToSave, 0));
m_writeStream.write((CHAR *)bufFileToSave, bytesToSave);
continue;
}
// Reading last block data
if (0 != BCryptDecrypt(m_keyHandle, bufFileToOpen, (ULONG)bytesRead, nullptr, nullptr, 0, nullptr, 0, &bytesToSave, BCRYPT_BLOCK_PADDING)) {
N2S_THROW("BCryptEncrypt::Error receiving the size required for the ciphertext.");
}
GetCryptStatus(BCryptDecrypt(m_keyHandle, bufFileToOpen, (ULONG)bytesRead, nullptr, nullptr, 0, bufFileToSave, bytesToSave, &bytesToSave, BCRYPT_BLOCK_PADDING));
m_writeStream.write((CHAR *)bufFileToSave, bytesToSave);
return; // Last block done.
}
}