将带有 ANSI 字符的 SecureString 转换为非托管字符串
Convert SecureString with ANSI-character to unmanaged string
我正在尝试将 SecureString
的内容直接复制到非托管内存中。
Microsoft 建议使用 Marshal.SecureStringToBSTR()
、Marshal.SecureStringToGlobalAllocAnsi()
、Marshal.SecureStringToGlobalAllocUnicode()
以及相应的 COM 使用方法。
我有一个 SecureString
,其中包含字符“127”和“128”。因为 ANSI 使用 8 位编码,所以我希望以下转换为非托管字符串会起作用:
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
但是“128”的结果是“63”。
我可以使用 SecureStringToBSTR()
或 SecureStringToGlobalAllocUnicode()
并省略所有其他字节。这行得通。但我想了解为什么 ANSI 方法 returns '63' 而不是 '128'.
我使用 C# 和 .Net Framework 4.8。
字符串是 char
的序列,而不是字节。 (char)128
表示 Unicode codepoint U+0080,它在您机器的 ANSI 代码页的任何代码页中都没有表示,因此您得到的是问号 (ANSI 63)。
这与 SecureString
s 无关。使用 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, 0, buffer.Length);
try
{
return System.Text.Encoding.Convert(System.Text.Encoding.Unicode, System.Text.Encoding.GetEncoding(28591), buffer);
}
finally
{
Array.Clear(buffer, 0, 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]);
}
我正在尝试将 SecureString
的内容直接复制到非托管内存中。
Microsoft 建议使用 Marshal.SecureStringToBSTR()
、Marshal.SecureStringToGlobalAllocAnsi()
、Marshal.SecureStringToGlobalAllocUnicode()
以及相应的 COM 使用方法。
我有一个 SecureString
,其中包含字符“127”和“128”。因为 ANSI 使用 8 位编码,所以我希望以下转换为非托管字符串会起作用:
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
但是“128”的结果是“63”。
我可以使用 SecureStringToBSTR()
或 SecureStringToGlobalAllocUnicode()
并省略所有其他字节。这行得通。但我想了解为什么 ANSI 方法 returns '63' 而不是 '128'.
我使用 C# 和 .Net Framework 4.8。
字符串是 char
的序列,而不是字节。 (char)128
表示 Unicode codepoint U+0080,它在您机器的 ANSI 代码页的任何代码页中都没有表示,因此您得到的是问号 (ANSI 63)。
这与 SecureString
s 无关。使用 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, 0, buffer.Length);
try
{
return System.Text.Encoding.Convert(System.Text.Encoding.Unicode, System.Text.Encoding.GetEncoding(28591), buffer);
}
finally
{
Array.Clear(buffer, 0, 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]);
}