2

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);
4

3 回答 3

3

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

此链接显示如何使用 Marshal.SecureStringToBSTR(secretString) 并将其分配给指针并更新指针以循环字符。

于 2012-07-12T19:15:25.113 回答
0

这对我有用:

    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);
        }
    }
于 2016-02-25T01:29:37.347 回答
-1

尝试这样的事情我将lc在链接中的VB代码示例转换为C#,希望这有助于您入门

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));
于 2012-07-12T19:15:47.117 回答