سؤال

WPF's PasswordBox returns a SecureString, which hides the password from snoopers.

The problem is that you eventually have to get the value of the password, and the suggestions I've found on the net all involve copying the value into a string, which gets you back to the problem of snoopers.

IntPtr bstr = Marshal.SecureStringToBSTR(secureString);
string password = Marshal.PtrToStringBSTR(bstr);
Marshal.FreeBSTR(bstr);

But if you really think about it, you don't really need the value, as a string. I mean, what do you do with a password? You hash it and then compare the result to a saved hash, and see if they are the same.

In other words, you don't need to convert the SecureString into a string, you just need to be able to iterate over the individual characters in the string.

But how?

How do I loop over the individual characters in a BSTR, in C#, without converting it to a managed string?

EDITING: the solution, in case the link disappears:

The Marshall class provides methods that can extract individual bytes or ints from an IntPtr, at given offsets. A BSTR object contains an array of 16-bit characters, terminated by two null bytes. So you can access them by looping:

byte b = 1;
int i = 0;
while ((char)b != '\0')
{
    b = Marshal.ReadByte(bstr, i);
    // ...
    i += 2;
}

(I don't care for that flow control. I'd have used a do...while, rather than prepopulate b with a dummy value, or I'd have used a for(;;) loop, with internal breaks, or I'd have looped on the length, which I explain how to get, below.)

Also, I'd probably use:

short b = Marshal.ReadInt16(bstr, i);

Reading the entire unicode chars, instead of just the low bytes of each.

You can get the length of the BSTR with:

int len = Marshal.ReadInt32(bstr, -4);

This is the number of bytes, not including the nulls, not the number of chars.

Also - use:

Marshal.ZeroFreeBSTR(bstr);
هل كانت مفيدة؟

المحلول

http://weblogs.asp.net/pglavich/archive/2005/08/15/422525.aspx

This link shows how to use Marshal.SecureStringToBSTR(secretString) and assign it to a pointer and update the pointer to loop over the characters.

نصائح أخرى

This worked for me:

    static char GetChar(SecureString value, int idx)
    {
        IntPtr bstr = Marshal.SecureStringToBSTR(value);
        try
        {
            // Index in 2-byte (char) chunks
            //TODO: Some range validation might be good.
            return (char)Marshal.ReadByte(bstr, idx * 2);
        }
        finally
        {
            Marshal.FreeBSTR(bstr);
        }
    }

Try something like this I converted the VB code sample that lc had in the link to C# for you hope this helps to get you started

Char[] input = "Super Secret String".ToCharArray();
SecureString secret = new SecureString();

for (int idx = 0; idx <= input.Length - 1; idx++) {
    secret.AppendChar(FileSystem.input(idx));
}
SecurePassword.MakeReadOnly();

IntPtr pBStr = Marshal.SecureStringToBSTR(secret);

string output = Marshal.PtrToStringBSTR(pBStr);
Marshal.FreeBSTR(pBStr);

SHA512 sha = new SHA512Managed();
byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(output));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top