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