views:

1255

answers:

2

All reservations about unsecuring your SecureString by creating a System.String out of it aside, how can it be done?

How can I convert an ordinary System.Security.SecureString to System.String?

I'm sure many of you who are familiar with SecureString are going to respond that one should never transform a SecureString to an ordinary .NET string because it removes all security protections. I know. But right now my program does everything with ordinary strings anyway, and I'm trying to enhance its security and although I'm going to be using an API that returns a SecureString to me I am not trying to use that to increase my security.

I'm aware of Marshal.SecureStringToBSTR, but I don't know how to take that BSTR and make a System.String out of it.

For those who may demand to know why I would ever want to do this, well, I'm taking a password from a user and submitting it as an html form POST to log the user into a web site. So... this really has to be done with managed, unencrypted buffers. If I could even get access to the unmanaged, unencrypted buffer I imagine I could do byte-by-byte stream writing on the network stream and hope that that keeps the password secure the whole way. I'm hoping for an answer to at least one of these scenarios.

Thanks!

+3  A: 

Dang. right after posting this I found the answer deep in this article. But if anyone knows how to access the IntPtr unmanaged, unencrypted buffer that this method exposes, one byte at a time so that I don't have to create a managed string object out of it to keep my security high, please add an answer. :)

static String SecureStringToString(SecureString value)
{
    IntPtr bstr = Marshal.SecureStringToBSTR(value);

    try
    {
        return Marshal.PtrToStringBSTR(bstr);
    }
    finally
    {
        Marshal.FreeBSTR(bstr);
    }
}
Andrew Arnott
+2  A: 

But if anyone knows how to access the IntPtr unmanaged, unencrypted buffer that this method exposes, one byte at a time so that I don't have to create a managed string object out of it to keep my security high, please add an answer. :)

Use Marshal.ReadByte(IntPtr, Int32).

To read a BSTR directly from an IntPtr, do something like this:

int length = Marshal.ReadInt32(intPtr, -4);
for(int i=0;i<length;i+=2){
  short unicodeChar = Marshal.ReadInt16(intPtr, i);
  // handle unicodeChar
}

The BSTR format is documented here.

Rasmus Faber