У меня есть собственная программа, которая принимает пароль, который передается в командной строке. Этот пароль отображается в журналах сервера, поэтому я хочу его запутать, зашифровав, прежде чем вводить в командную строку. Затем я расшифрую его в программе и использую как раньше. Идея состоит в том, чтобы использовать PowerShell для создания SecureString с паролем, а затем сделать его печатной текстовой строкой, используя ConvertFrom-SecureString. Эта строка затем передается в командной строке в собственную программу на С ++. Оттуда я декодирую его обратно в двоичную зашифрованную форму, а затем дешифрую обратно к исходному текстовому паролю. Легко ли?
Из скудной документации я думаю, что ConvertFrom-SecureString выполняет кодировку Base64, чтобы сделать двоичный текст SecureString пригодным для печати. Кто-нибудь может это подтвердить?
Я восстанавливаю двоичные байты, используя ATL :: Base64Decode (). это появляется работать при сравнении первых 20 байтов из оригинального и декодированного.
После этого я пытаюсь расшифровать байты SecureString. Снова появляется некоторая документация, которая подразумевает, что шифрование 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, как вы говорите, и не используете параметры Key или SecureKey в ConvertFrom-SecureString.
Так что в вашей программе на C ++ не используйте Base64Decode, просто анализируйте каждые два символа как шестнадцатеричный байт. Затем вызовите CryptUnprotectData для результирующего байтового массива (вставленного в DATA_BLOB).