3

コマンドラインで渡されるパスワードを受け取るネイティブプログラムがあります。そのパスワードはサーバー ログに表示されるため、コマンド ラインに入力する前に暗号化して難読化したいと考えています。次に、プログラムでそれを復号化し、以前と同じように使用します。アイデアは、powershell を使用してパスワードで SecureString を作成し、ConvertFrom-SecureString を使用して印刷可能なテキスト文字列にすることです。その文字列は、コマンド ラインでネイティブの C++ プログラムに渡されます。そこから、バイナリの暗号化された形式にデコードし、元のプレーン テキストのパスワードに復号化します。簡単でしょ?

わずかなドキュメントから、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;
}
4

1 に答える 1

1

dotPeek のバイナリを見ると、ConvertFrom-String は SecureStringToCoTaskMemUnicode を使用して、セキュリティで保護された文字列ペイロードをバイト配列に変換していることがわかります。そのバイト配列は、16 進形式で返されますbyte.ToString("x2)

これは、あなたが言うように DPAPI を使用していて、ConvertFrom-SecureString で Key または SecureKey パラメーターを使用していないことを前提としています。

したがって、C++ プログラムでは Base64Decode を使用せず、2 文字ごとに 16 進バイトとして解析してください。次に、結果のバイト配列 (DATA_BLOB に詰め込まれたもの) で CryptUnprotectData を呼び出します。

于 2015-09-15T03:36:39.473 に答える