LocalFree ломает DPAPI шифрование / дешифрование - PullRequest
0 голосов
/ 17 мая 2019

Я пишу небольшую консольную программу для тестирования 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 должен находиться в памяти, если я уже сохраняю его, преобразовав в строку?

...