在.NET中,我们有SecureString类,在您开始尝试使用它之前,它都是非常好的,因为(例如)对字符串进行哈希处理,则需要纯文本。给定一个采用字节数组并输出字节数组的哈希函数,我在这里编写了一个函数,该函数将对SecureString进行哈希处理。
private static byte[] HashSecureString(SecureString ss, Func<byte[], byte[]> hash)
{
// Convert the SecureString to a BSTR
IntPtr bstr = Marshal.SecureStringToBSTR(ss);
// BSTR contains the length of the string in bytes in an
// Int32 stored in the 4 bytes prior to the BSTR pointer
int length = Marshal.ReadInt32(bstr, -4);
// Allocate a byte array to copy the string into
byte[] bytes = new byte[length];
// Copy the BSTR to the byte array
Marshal.Copy(bstr, bytes, 0, length);
// Immediately destroy the BSTR as we don't need it any more
Marshal.ZeroFreeBSTR(bstr);
// Hash the byte array
byte[] hashed = hash(bytes);
// Destroy the plaintext copy in the byte array
for (int i = 0; i < length; i++) { bytes[i] = 0; }
// Return the hash
return hashed;
}
我相信这将正确地对字符串进行哈希处理,并在函数返回时正确地从内存中清除明文的任何副本,前提是所提供的哈希函数行为良好且不会对输入的任何副本进行复制擦洗自己。我在这里错过了什么吗?
最佳答案
是的,您有一个相当基本的观点。当垃圾收集器压缩堆时,您无法清理留下的数组副本。 Marshal.SecureStringToBSTR(ss)可以,因为BSTR分配在非托管内存中,因此将具有不会更改的可靠指针。换句话说,擦洗那个没有问题。
但是,您的byte[] bytes
数组包含字符串的副本,并在GC堆上分配。您很可能使用hashed []数组引发垃圾回收。轻松避免,但当然您几乎无法控制进程中分配内存和引发集合的其他线程。或就此而言,在您的代码开始运行时已经在运行的后台GC。
SecureString的重点是永远不要在垃圾回收内存中拥有字符串的明文副本。将其复制到托管阵列违反了该保证。如果要确保此代码的安全,则必须编写一个采用IntPtr且仅读取该指针的hash()方法。
请注意,如果您的哈希需要与在另一台计算机上计算的哈希匹配,则您不能忽略该计算机将字符串转换为字节所使用的编码。
关于c# - 在.NET中散列SecureString,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14293344/