Mar*_*ond 24 .net c# securestring password-encryption
在.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;
}
Run Code Online (Sandbox Code Playgroud)
我相信这将正确地对字符串进行散列,并且在函数返回时将正确地从内存中擦除明文的任何副本,假设提供的散列函数表现良好并且不进行任何不是的输入副本擦洗自己.我在这里错过了什么吗?
Han*_*ant 14
我在这里错过了什么吗?
是的,你有一个相当基础的.当垃圾收集器压缩堆时,您无法清除留下的数组副本.Marshal.SecureStringToBSTR(ss)没问题,因为BSTR是在非托管内存中分配的,因此会有一个不会改变的可靠指针.换句话说,没有问题擦洗那一个.
你byte[] bytes
不过数组包含字符串的副本,是在GC堆上分配.你可能会使用散列[]数组引发垃圾收集.很容易避免但当然你几乎无法控制进程中的其他线程分配内存和引入集合.或者就此而言,代码开始运行时已经在进行的后台GC.
SecureString的要点是永远不要在垃圾收集的内存中拥有该字符串的明文副本.将其复制到托管数组会违反该保证.如果你想使这段代码安全,那么你将不得不编写一个hash()方法,该方法接受IntPtr并只读取该指针.
请注意,如果您的哈希需要匹配在另一台机器上计算的哈希,那么您不能忽略该机器将用于将字符串转换为字节的编码.
总是有可能使用非托管的CryptoApi或CNG函数。请记住,该SecureString
设计是针对非托管使用者设计的,该使用者要完全控制内存管理。
如果您要坚持使用C#,则应先固定临时阵列以防止GC移动,然后才有机会对其进行清理:
private static byte[] HashSecureString(SecureString input, Func<byte[], byte[]> hash)
{
var bstr = Marshal.SecureStringToBSTR(input);
var length = Marshal.ReadInt32(bstr, -4);
var bytes = new byte[length];
var bytesPin = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try {
Marshal.Copy(bstr, bytes, 0, length);
Marshal.ZeroFreeBSTR(bstr);
return hash(bytes);
} finally {
for (var i = 0; i < bytes.Length; i++) {
bytes[i] = 0;
}
bytesPin.Free();
}
}
Run Code Online (Sandbox Code Playgroud)