这是一个转发,因为我的上一个太多了,所以我打算简单点。
第二次调用BCryptDecrypt()
,返回0xc000000d
失败。我知道代码很糟糕,有很多故障点,但在我的测试中,这些故障点都没有失败。
我将其与c#版本的代码进行了比较,两者的调试器都显示它们具有相同的缓冲区值/返回值只是在第二次调用BCryptDecrypt()
时失败。
我的目标是使用该块中的密钥解密加密/加密文本块。使用AES-GCM我只想使用比特币。这是可能的,因为我有一个c#版本,我不想导入额外的库,如OpenSSL。
如果你想尝试,这里是Base64编码密钥,你需要从Base64解码,为"DPAPI"
跳过5个字节,然后调用CryptUnprotectData()
。
要解密/解码的值为(Base64 + AES-GCM):
RFBBUEkBAAAA0Iyd3wEV0RGMegDAT8KX6wEAAADeBU2aOO6lQ73DYvrL8hhAAAAAAAIAAAAAABBmAAAAAQAAIAAAALXsSijRcSAV3S8PSvKZXUddV2eE + nv5xtn8JaePfpjrAAAAAA6AAAAAAgAAIAAAAJ96r2xQdEkkXuEaGEcVG24QJSKXG9s14w/yS8gdO/CxMAAAABs64 + DTxkrQnkH1e3d0w/tOPIRrB1OBPrw4uxX4Q0AfYv6pyMZKXchhn1qol8bMvUAAAADisCS/m6UBBzMxVLBgpCvQsGIa6hYT/J8NGZuFOqydlstlxLBL2K8tCX550IoHtwuEA8EGJTxMsW6wh/0 h3vrn
(这是我的CTF/项目的密码/密钥,我允许它被解密/解码)
解密代码:
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"解码后的Base64密钥:
//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);
其余的代码(以防我在其他地方做错了什么)
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;
}
- 从
std::vector
更改为HeapAlloc
- 改变
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO
位 - 修改
BCryptSetProperty
的参数 - 在GitHub Pages中使用c++编写的良好版本
- 尝试4+种不同的代码方式,包括使用聊天机器人GPT
所以我将把这个留给未来的人,我开始研究填充给出这篇文章BCryptEncrypt在AES-GCM上返回STATUS_INVALID_PARAMETER
我创建了一个具有X字节量的矢量,使用基于静态X大小的memcpy复制了BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO
我看到没有填充至少会切断/畸形的数据,但我确实看到一个值,不断改变每次调试在结构体的末尾,似乎不断改变每次运行。我把它交还给信托基金看它是否有毛病,看起来还好。我确实注意到调试器中有一个字段,虽然我没有触摸它,但它叫做dwflag;,它有一个随机值设置为每次运行。
:
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO。dwFlags = 0;
修复:D
关于" dwflag "的评论中也提到了这一点。但我假设他指的是函数签名,而不是结构,如果不是,那么我假设错了。