Pass Powershell SecureString to C++ program?

3

I have a native program that takes a password that is passed in on command line. That password is showing up in server logs so I want to obfuscate it by encrypting it before putting on the command line. I would then decrypt it in the program and use it as before. The idea is I use powershell to create a SecureString with the password, then make it a printable text string using ConvertFrom-SecureString. That string is then passed in on the command line to the native c++ program. From there, I decode it back to a binary excrypted form, and then decrypt it back to the original plain text password. Easy right?

From scant documentation, I think the ConvertFrom-SecureString does a Base64 encoding to make the binary SecureString inot printable text. Can anyone confirm that? I recover the binary bytes using ATL::Base64Decode(). This appears to work when comparing the first 20 bytes from orignal and decoded.

After that I'm trying to decrypt the SecureString bytes. Again some documentation appears to imply that the SecureString Encryption is done using Machine Key (or User Session Key). Based on this, I'm trying to decrypt using the DPAPI CryptUnprotectData method. Here, though I get an decrupt failure with "(0x8007000d) The data is invalid". Does this sound like it will work? If so any idea where I'm off course?

Heres the decrypt method ...

// 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;
}
c++
powershell
encryption
securestring
dpapi
asked on Stack Overflow Sep 14, 2015 by RyanL • edited Sep 15, 2015 by RyanL

1 Answer

1

From what I can tell looking at the binary in dotPeek, ConvertFrom-String is using SecureStringToCoTaskMemUnicode to convert the secure string payload to an array of bytes. That array of bytes is returned in hex form e.g. byte.ToString("x2).

This assumes that you are using DPAPI as you say and not use the Key or SecureKey parameters on ConvertFrom-SecureString.

So in your C++ program do not use Base64Decode, just parse every two chars as a hex byte. Then call CryptUnprotectData on the resulting byte array (stuffed into the DATA_BLOB).

answered on Stack Overflow Sep 15, 2015 by Keith Hill

User contributions licensed under CC BY-SA 3.0