将具有ANSI字符的SecureString转换为非托管字符串

问题描述

我正在尝试将libpng-dev内容直接复制到非托管内存中。 Microsoft建议使用securestringMarshal.securestringToBstr()Marshal.securestringToGlobalAllocAnsi()和相应的COM使用方法

我有一个Marshal.securestringToGlobalAllocUnicode(),其字符为“ 127”和“ 128”。因为ANSI使用8位编码,所以我希望将以下转换成非托管字符串是可行的:

securestring

但是'128'结果为'63'。 我可以使用 var securestring = new securestring(); securestring.AppendChar((char)127); securestring.AppendChar((char)128); IntPtr unmanagedString = Marshal.securestringToGlobalAllocAnsi(securestring); var b1 = Marshal.ReadByte(unmanagedString,0); // 127 var b2 = Marshal.ReadByte(unmanagedString,1); // 63 securestringToBstr()并忽略其他所有字节。这会起作用。但是我想理解为什么ANSI方法返回的是“ 63”而不是“ 128”。

我在.Net Framework 4.8中使用C#。

解决方法

字符串是char的序列,而不是字节。 (char)128代表Unicode codepoint U+0080,它在计算机的ANSI代码页的任何代码页中都没有表示,因此您会得到一个问号(ANSI 63)。
这与SecureString无关。通过Encoding.GetBytes / Encoding.GetString您将获得相同的结果。


在继续操作之前,请确保您已访问this


如果您确定安全字符串仅包含256以下的代码点,并且希望在ANSI中对这些代码点进行往返表示,则可以安排using codepage 28591

public static byte[] SecureStringToRoundtripAnsiByteArray(SecureString secureString)
{
    var buffer_ptr = Marshal.SecureStringToCoTaskMemUnicode(secureString);

    try
    {
        byte[] buffer = new byte[secureString.Length * sizeof(char)];
        Marshal.Copy(buffer_ptr,buffer,buffer.Length);

        try
        {
            return System.Text.Encoding.Convert(System.Text.Encoding.Unicode,System.Text.Encoding.GetEncoding(28591),buffer);
        }
        finally
        {
            Array.Clear(buffer,buffer.Length);
        }
    }
    finally
    {
        Marshal.ZeroFreeCoTaskMemUnicode(buffer_ptr);
    }
}
using (var secureString = new SecureString())
{
    for (int i = 0; i < 256; i++)
        secureString.AppendChar((char)i);

    secureString.MakeReadOnly();

    byte[] b = SecureStringToRoundtripAnsiByteArray(secureString);

    for (int i = 0; i < 256; i++)
        Console.WriteLine(b[i]);
}