C++加密“加密解密”返回“0xc000000d”

zpgglvta  于 2023-01-22  发布在  其他
关注(0)|答案(1)|浏览(171)

This is a repost, as my last one was too much, so I'm going to make it simple.
On the second call to BCryptDecrypt() , it fails returning 0xc000000d . I am aware the code is bad and has many points of failure, but in my test none of those points failed.
I compared this to the C# version of the code that works, debuggers for both show they have all the same values for buffers / returned values just fails at the second call of BCryptDecrypt() .
My goal is to decrypt an Encrypted / Ciphered Text Block using a Key from that Block. Uses AES-GCM I want to use ONLY Bcrypt. It is possible as I have a C# version, I don't want to import extra libs, like OpenSSL.
If you want to try, here is the Base64 Encoded Key, you need to decode from base64, skip 5 bytes for "DPAPI" , then call to CryptUnprotectData() .
The value to be Decrypted / Decoded is (Base64 + AES-GCM):
RFBBUEkBAAAA0Iyd3wEV0RGMegDAT8KX6wEAAADeBU2aOO6lQ73DYvrL8hhAAAAAAAIAAAAAABBmAAAAAQAAIAAAALXsSijRcSAV3S8PSvKZXUddV2eE+nv5xtn8JaePfpjrAAAAAA6AAAAAAgAAIAAAAJ96r2xQdEkkXuEaGEcVG24QJSKXG9s14w/yS8gdO/CxMAAAABs64+DTxkrQnkH1e3d0w/tOPIRrB1OBPrw4uxX4Q0AfYv6pyMZKXchhn1qol8bMvUAAAADisCS/m6UBBzMxVLBgpCvQsGIa6hYT/J8NGZuFOqydlstlxLBL2K8tCX550IoHtwuEA8EGJTxMsW6wh/0H3VRn
(this is my password/key for my CTF / Project, I allow it to be decrypted / decoded)
Code to decrypt:

std::vector<uint8_t> AesGcm::DecryptWithKey(
    const std::vector<uint8_t>& ciphered_data, 
    const std::vector<uint8_t>& key)
{
    //Create the IV
    std::vector<uint8_t> iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // IV 12 bytes
    std::copy(ciphered_data.begin() + 3, ciphered_data.begin() + 15, iv.begin());

    //Create Buffer witth Ciphered Data only
    std::vector<uint8_t> buffer(ciphered_data.size() - 15);
    std::copy(ciphered_data.begin() + 15, ciphered_data.end(), buffer.begin());

    //Create TAG
    std::vector<uint8_t> tag(16);
    std::vector<uint8_t> data(buffer.size() - tag.size());

    //Last 16 bytes for tag
    std::copy(buffer.end() - 16, buffer.end(), tag.begin());

    //encrypted password
    std::copy(buffer.begin(), buffer.end() - tag.size(), data.begin());
    
    std::vector<uint8_t> aad(0);//Just an Empty AAD param

    return Decrypt(key, iv, aad, data, tag);
}

std::vector<uint8_t> AesGcm::Decrypt(
    const std::vector<uint8_t>& key,
          std::vector<uint8_t>& iv,
          std::vector<uint8_t>& aad,
          std::vector<uint8_t>& cipher_text,
          std::vector<uint8_t>& authTag)
{
    std::vector<uint8_t> p_text(0);
    BCRYPT_ALG_HANDLE hAlg;

    if (!OpenAlgorithmProvider(hAlg, MS_PRIMITIVE_PROVIDER, BCRYPT_CHAIN_MODE_GCM))
        return p_text;
    
    auto key_sz_bts = AesGcm::GetProperty(hAlg, BCRYPT_OBJECT_LENGTH);
    if (key_sz_bts.empty() || key_sz_bts.size() != 4) {
        std::cout << "Inavlid PropertySize::" << key_sz_bts.size() << std::endl;
        if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0x0);
        return p_text;
    }

    auto blob_vec = AesGcm::CreateBlob(key);
    auto key_sz = *reinterpret_cast<int*>(key_sz_bts.data());

    if (blob_vec.empty()) {
        std::cout << "Invalid Blob Size::" << blob_vec.size() << std::endl;
        if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0x0);
        return p_text;
    }

    BCRYPT_KEY_HANDLE hBck;
    std::vector<uint8_t> kdata_buffer(key_sz);
    std::vector<uint8_t> mac(authTag.size());

    DWORD dwStatus =
        BCryptImportKey(hAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hBck, kdata_buffer.data(), kdata_buffer.size(), blob_vec.data(), blob_vec.size(), 0x0);

    if (FAILED(dwStatus)) {
        std::cout << "BCryptImportKey(FAILED)::[0x" << std::hex << dwStatus << "]" << std::endl;
        if (hBck) BCryptDestroyKey(hBck);
        if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0x0);
        return p_text;
    }

    //Create the AUTH Struct
    BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
    authInfo.dwInfoVersion = 0x00000001;
    authInfo.pbNonce = iv.data();
    authInfo.cbNonce = iv.size();
    authInfo.pbAuthData = aad.data(); //aad.data();
    authInfo.cbAuthData = aad.size();//aad.size();
    authInfo.pbTag = authTag.data();
    authInfo.cbTag = authTag.size();
    authInfo.pbMacContext = mac.data();
    authInfo.cbMacContext = mac.size();//authTag.size();
    authInfo.cbAAD = 0;
    authInfo.cbData = 0;
    
    //authInfo.cbSize = sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO);
    authInfo.cbSize = sizeof(authInfo);

    auto authtg_tg_bts = AesGcm::GetProperty(hAlg, BCRYPT_AUTH_TAG_LENGTH);

    //Get Auth Tag Size
    auto atag_size = *reinterpret_cast<int*>(&authtg_tg_bts[4]);
    std::vector<uint8_t> iv_data(atag_size);
    DWORD ptext_size = 0;

    //Decrypt Data now
    dwStatus = BCryptDecrypt(
        hBck, cipher_text.data(), cipher_text.size(), &authInfo, iv_data.data(), iv_data.size(), nullptr, 0, &ptext_size, 0x0);

    if (FAILED(dwStatus) || ptext_size <= 0) {
        std::cout << "BCryptDecrypt2(FAILED)::[0x" << std::hex << dwStatus << "]::SIZE::" << ptext_size << std::endl;
        goto end;
    }

    p_text.resize(ptext_size);

    //Fails at this Second Call
    dwStatus = BCryptDecrypt(
        hBck,
        cipher_text.data(),
        cipher_text.size(),
        &authInfo,
        iv_data.data(),
        iv_data.size(), p_text.data(), p_text.size(), &ptext_size, 0x0);

    if (FAILED(dwStatus)) {
        std::cout << "BCryptDecrypt2(FAILED)::[0x" << std::hex << dwStatus << "]" << std::endl;
        goto end;
    }

end:
    if (hBck) BCryptDestroyKey(hBck);
    if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0x0);
    return p_text;
}

"Unprotect" decoded Base64 Key:

//encryptedData is the Decoded Base64 Data skipped 5 Bytes
DATA_BLOB DataIn;
DataIn.cbData = encryptedData.size();
DataIn.pbData = (BYTE*)encryptedData.data();//const_cast<uint8_t*>(encryptedData.data());

auto num = 1u;
if (dwFlags == 1) {
    num |= 4u;
}

DATA_BLOB DataOut;
if (!CryptUnprotectData(&DataIn, NULL, NULL, NULL, NULL, num, &DataOut))
    throw std::exception("CryptUnprotectData failed.");
    
std::vector<uint8_t> result(DataOut.pbData, DataOut.pbData + DataOut.cbData);
LocalFree(DataOut.pbData);

Rest of the code (incase I am doing something wrong somewhere else)

std::vector<uint8_t> AesGcm::CreateBlob(const std::vector<uint8_t>& key) {
    //Create KeyBlob
    std::vector<uint8_t> key_bloc_vec(4 * 3 + key.size());

    //Write The MAGIC
    DWORD kbm = BCRYPT_KEY_DATA_BLOB_MAGIC;
    //uint8_t* bytes = reinterpret_cast<uint8_t*>(&kbm);
    std::memcpy(key_bloc_vec.data(), reinterpret_cast<uint8_t*>(&kbm), sizeof(int));

    //Write 0x1
    DWORD rnd = 0x1;
    //uint8_t* bytes = reinterpret_cast<uint8_t*>(&rnd);
    std::memcpy(key_bloc_vec.data() + 4, reinterpret_cast<uint8_t*>(&rnd), sizeof(int));

    //Write Size
    DWORD ksz = key.size();
    std::memcpy(key_bloc_vec.data() + 8, reinterpret_cast<uint8_t*>(&ksz), sizeof(int));

    //Write KEY
    std::memcpy(key_bloc_vec.data() + 12, key.data(), key.size());

    return key_bloc_vec;
}

bool AesGcm::OpenAlgorithmProvider(BCRYPT_ALG_HANDLE& hBC, const TCHAR* provider, const TCHAR* chaining_mode) {
    DWORD dwStatus = BCryptOpenAlgorithmProvider(&hBC, BCRYPT_AES_ALGORITHM, provider, 0x0);
    if (FAILED(dwStatus)) {
        std::cout << "BCryptOpenAlgorithmProvider(FAILED)::[0x" << std::hex << dwStatus << "]" << std::endl;
        return false;
    }

    //std::wstring cc_mode(BCRYPT_CHAIN_MODE_GCM);
    //std::vector<uint8_t> bmode_bys(cc_mode.size() * sizeof(wchar_t) + 2);
    //std::memcpy(bmode_bys.data(), cc_mode.data(), bmode_bys.size());

    //dwStatus = BCryptSetProperty(hBC, BCRYPT_CHAINING_MODE, bmode_bys.data(), bmode_bys.size() - 2, 0x0);
    //if (FAILED(dwStatus)) {
    //  std::cout << "BCryptSetProperty(FAILED)::[0x" << std::hex << dwStatus << "]" << std::endl;
    //  return false;
    //}

    dwStatus = BCryptSetProperty(hBC, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0x0);
    if (FAILED(dwStatus)) {
        std::cout << "BCryptSetProperty(FAILED)::[0x" << std::hex << dwStatus << "]" << std::endl;
        return false;
    }

    return true;
}

std::vector<uint8_t> AesGcm::GetProperty(BCRYPT_ALG_HANDLE& hCH, const TCHAR* prop_name) {
    DWORD sz_1 = 0;//BCRYPT_AUTH_TAG_LENGTH / BCRYPT_OBJECT_LENGTH
    DWORD dwStatus = BCryptGetProperty(hCH, prop_name, NULL, 0, &sz_1, 0x0);

    if (FAILED(dwStatus) || sz_1 <= 0)
        throw std::exception("BCryptGetProperty failed");

    std::vector<uint8_t> prop_bys(sz_1);
    dwStatus = BCryptGetProperty(hCH, prop_name, (PBYTE)prop_bys.data(), prop_bys.size(), &sz_1, 0x0);
    if (FAILED(dwStatus))
        throw std::exception("BCryptGetProperty failed2");

    return prop_bys;
}
  • Changing from std::vector to HeapAlloc
  • Changing around the BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO a bit
  • Changing the params for BCryptSetProperty
  • Using well written version in C++ from GitHub Pages
  • Trying 4+ fifferent ways of the code, including using Chat Bot GPT
dy1byipe

dy1byipe1#

所以我会把这个留给未来的人,我开始考虑填充给这个职位BCryptEncrypt returns STATUS_INVALID_PARAMETER on AES-GCM
我创建了一个字节数为X的向量,使用memcpy根据静态X大小复制了BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO
我没有看到任何填充,至少这将切断/畸形的数据,但我确实看到了一个值,不断改变每个调试在结构的末尾,似乎不断改变每次运行。我把它投回到信任,看看它是否畸形或任何似乎很好。我注意到在调试器中的一个字段,虽然我没有接触所谓的"dwFlags",它有一个随机值,它设置为每次运行。
设置:
密码验证码模式信息。dwFlags = 0;
修复的问题:D
在关于"dwFlags"的评论中也提到过,但我假设他指的是函数签名而不是结构,如果不是,那么我假设错了。无论哪种方式,问题都解决了!

相关问题