Marshal Unmanaged Unicode String in COM Task Allocator Memory to SecureString

224 views Asked by At

I an working with API calls to advapi32.dll for managing Windows Saved Credentials in order to automate certain windows applications which can use saved credentials, which is working fine.

I am trying to update my code to use SecureString for password throughout, as I have no need to interact with the text contained in passwords at any point so it should be more secure if my application never holds the password in plain text.

I am able to marshal a SecureString to COM task allocator memory to pass to the API calls with:

var unmanagedPassword = Marshal.SecureStringToCoTaskMemUnicode(userCredential.Password);

However, when it comes to reading that information back into the application, I cannot find a way to marshal such an unmanaged string back into a SecureString without copying the string into managed memory, be it as a string or byte array.

Is there a safe way to do this that I am overlooking?

1

There are 1 answers

0
Ashigore On BEST ANSWER

Big thanks to Jeroen Mostert for his comments which lead to this solution, which should be about as safe as is possible.

As Jeroen described, each character is read as a short and appended to a new SecureString one at a time.

Unmanaged strings in Task Allocator memory are null terminated, hence reading characters until getting 0. Unmanaged binary strings are length prefixed and so would require a slight modification of the code below.

    var outString = new SecureString();
    outString.AppendChar('p');
    outString.AppendChar('a');
    outString.AppendChar('s');
    outString.AppendChar('s');
    outString.AppendChar('w');
    outString.AppendChar('o');
    outString.AppendChar('r');
    outString.AppendChar('d');
    var ptr = Marshal.SecureStringToCoTaskMemUnicode(outString);

    var inString = new SecureString();
    var i = 0;
    short c;

    while ((c = Marshal.ReadInt16(ptr, i)) != 0)
    {
        inString.AppendChar((char)c);
        i += 2;
    }

    Marshal.ZeroFreeCoTaskMemUnicode(ptr);