0

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?

3
  • Would the downvoter care to explain how this question is a "why isn't it working" question without desired outcome? I'm asking how to do something that I cannot find a way to do. I think I have specified clearly what I need. To create a new SecureString from unmanaged memory. Commented Sep 5, 2017 at 20:10
  • It's a curious oversight. I suppose the simplest way (without unmanaged code) is to call .AppendChar() in a loop over Marshal.ReadInt16() (assuming a Unicode string). There's also an unsafe constructor that takes a char* and a length. Note that the unmanaged memory should be zeroed and deallocated, otherwise there's not much point to you using a SecureString while all the data is still floating around in plain text. Commented Sep 5, 2017 at 20:16
  • Thanks @JeroenMostert, that did the trick! Commented Sep 5, 2017 at 20:36

1 Answer 1

1

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);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.