我有一个本机程序,该程序采用在命令行中传递的密码。该密码显示在服务器日志中,因此我想通过在输入命令行之前对其进行加密来对其进行混淆。然后,我将在程序中对其进行解密,并像以前一样使用它。我的想法是,我使用Powershell用密码创建SecureString,然后使用ConvertFrom-SecureString将其设置为可打印的文本字符串。然后,该字符串在命令行上传递给本机c++程序。从那里,我将其解码回二进制加密形式,然后将其解密回原始的纯文本密码。容易吧?
从很少的文档中,我认为ConvertFrom-SecureString进行Base64编码以使二进制SecureString inot可打印文本。谁能确认?
我使用ATL::Base64Decode()恢复二进制字节。比较原始和已解码的前20个字节时,这似乎起作用。
之后,我尝试解密SecureString字节。同样,一些文档似乎暗示使用机器密钥(或用户 session 密钥)完成SecureString加密。基于此,我试图使用DPAPI CryptUnprotectData方法进行解密。在这里,尽管我因“(0x8007000d)数据无效”而失败。这听起来像行得通吗?如果有的话,我在哪里走了?
继承人的解密方法...
// Decrypts an encoded and encrypted string with DPAPI and Machine Key, returns the decrypted string
static HRESULT Decrypt(CStringW wsEncryptedBase64, OUT CStringW& wsPlainText)
{
HRESULT hr = S_OK;
DATA_BLOB dbIn = { 0 };
DATA_BLOB dbOut = { 0 };
const wchar_t *pos = wsEncryptedBase64.GetBuffer(wsEncryptedBase64.GetLength());
dbIn.cbData = wsEncryptedBase64.GetLength() / 2;
dbIn.pbData = (byte*)malloc(dbIn.cbData * sizeof(byte));
int num = 0;
for (size_t i = 0; i < dbIn.cbData; i += 1)
{
swscanf_s(pos, L"%2hhx", &num);
dbIn.pbData[i] = num;
pos += sizeof(wchar_t);
}
if (::CryptUnprotectData(&dbIn, NULL, NULL, NULL, NULL,
CRYPTPROTECT_UI_FORBIDDEN, &dbOut))
{
wsPlainText = CStringW(reinterpret_cast< wchar_t const* >(dbOut.pbData), dbOut.cbData / 2);
}
else
{
hr = HRESULT_FROM_WIN32(::GetLastError());
if (hr == S_OK)
{
hr = SEC_E_DECRYPT_FAILURE;
}
}
return hr;
}
最佳答案
通过观察dotPeek中的二进制文件,我可以看出,ConvertFrom-String使用SecureStringToCoTaskMemUnicode将安全字符串有效负载转换为字节数组。该字节数组以十六进制形式返回,例如byte.ToString("x2)
。
这假定您使用的是您所说的DPAPI,而不在ConvertFrom-SecureString上使用Key或SecureKey参数。
因此,在您的C++程序中不要使用Base64Decode,只需将每两个字符解析为一个十六进制字节。然后在结果字节数组(填充到DATA_BLOB中)上调用CryptUnprotectData。
关于c++ - 将Powershell SecureString传递给C++程序?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32574728/