Я пишу небольшую консольную программу для тестирования DPAPI на основе ограничений, с которыми мне приходится работать для проекта (все wstring, нужно выводить зашифрованные данные в base64), и столкнулся с проблемой, когда при вызове LocalFree
на pbData выходного большого двоичного объекта CryptProtectData
расшифровка завершится неудачей.
My Encrypt()
и Decrypt()
helpers:
std::wstring Encrypt(std::wstring input)
{
char *inputBuf = new char[input.size() + 1];
size_t temp = 0;
wcstombs_s(&temp, inputBuf, input.size() + 1, input.c_str(), input.size());
CRYPT_INTEGER_BLOB inputBlob;
inputBlob.cbData = strlen(inputBuf) + 1;
inputBlob.pbData = (BYTE*)inputBuf;
CRYPT_INTEGER_BLOB outputBlob;
CryptProtectData(&inputBlob, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &outputBlob);
BYTE *outputBlobPtr = (BYTE *)(&outputBlob);
DWORD encodedLen = 0;
CryptBinaryToStringW(outputBlobPtr, sizeof(CRYPT_INTEGER_BLOB), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &encodedLen);
wchar_t *outputBuf = new wchar_t[encodedLen];
CryptBinaryToStringW(outputBlobPtr, sizeof(CRYPT_INTEGER_BLOB), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, outputBuf, &encodedLen);
std::wstring output = std::wstring(outputBuf, encodedLen);
LocalFree(outputBlob.pbData); // <-- This is the offending line
delete[] inputBuf;
delete[] outputBuf;
return output;
}
std::wstring Decrypt(std::wstring input)
{
wchar_t *inputBuf = new wchar_t[input.size() + 1];
wcscpy_s(inputBuf, input.size() + 1, input.c_str());
DWORD decodedLen = 0;
CryptStringToBinaryW(inputBuf, wcslen(inputBuf), CRYPT_STRING_BASE64, NULL, &decodedLen, NULL, NULL);
BYTE *encryptedBlobPtr = new BYTE[decodedLen];
if (CryptStringToBinaryW(inputBuf, wcslen(inputBuf), CRYPT_STRING_BASE64, encryptedBlobPtr, &decodedLen, NULL, NULL) == 0)
{
std::cout << "String to blob conversion error: " << GetLastError() << std::endl;
return std::wstring();
}
CRYPT_INTEGER_BLOB encryptedBlob = *((CRYPT_INTEGER_BLOB *)encryptedBlobPtr);
CRYPT_INTEGER_BLOB decryptedBlob;
if (CryptUnprotectData(&encryptedBlob, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &decryptedBlob) == 0)
{
std::cout << "Decryption error: " << GetLastError() << std::endl;
return std::wstring();
}
wchar_t *outputBuf = new wchar_t[decryptedBlob.cbData + 1];
size_t temp = 0;
mbstowcs_s(&temp, outputBuf, decryptedBlob.cbData + 1, (char *)decryptedBlob.pbData, decryptedBlob.cbData);
std::wstring output = std::wstring(outputBuf, decryptedBlob.cbData + 1);
LocalFree(decryptedBlob.pbData);
delete[] inputBuf;
delete[] encryptedBlobPtr;
delete[] outputBuf;
return output;
}
Если строка закомментирована, то вызывается Encrypt(L"Some string")
, сохраняя результат в wstring, а затем вызывая Decrypt(resultOfEncrypt)
, я получу "Some string"
обратно.Если там есть строка, то программа завершается с ошибкой CryptUnprotectData()
с GetLastError() == 13
(неверные данные).
Не понимаю ли я, как работает DPAPI или LocalFree ()?Почему outputBlob должен находиться в памяти, если я уже сохраняю его, преобразовав в строку?