2 回答

TA貢獻1811條經驗 獲得超4個贊
我找到了一種方法來按照我想要的方式做到這一點。我這里的代碼還沒有完成(在失敗的情況下需要更好的異常處理和內存管理),但這里是:
[DllImport("kernel32.dll")]
static extern void RtlZeroMemory(IntPtr dst, int length);
public unsafe static byte[] HashNew(this SecureString secureString, HashAlgorithm hashAlgorithm)
{
IntPtr bstr = Marshal.SecureStringToBSTR(secureString);
int maxUtf8BytesCount = Encoding.UTF8.GetMaxByteCount(secureString.Length);
IntPtr utf8Buffer = Marshal.AllocHGlobal(maxUtf8BytesCount);
// Here's the magic:
char* utf16CharsPtr = (char*)bstr.ToPointer();
byte* utf8BytesPtr = (byte*)utf8Buffer.ToPointer();
int utf8BytesCount = Encoding.UTF8.GetBytes(utf16CharsPtr, secureString.Length, utf8BytesPtr, maxUtf8BytesCount);
Marshal.ZeroFreeBSTR(bstr);
var utf8Bytes = new byte[utf8BytesCount];
GCHandle utf8BytesPin = GCHandle.Alloc(utf8Bytes, GCHandleType.Pinned);
Marshal.Copy(utf8Buffer, utf8Bytes, 0, utf8BytesCount);
RtlZeroMemory(utf8Buffer, utf8BytesCount);
Marshal.FreeHGlobal(utf8Buffer);
try
{
return hashAlgorithm.ComputeHash(utf8Bytes);
}
finally
{
for (int i = 0; i < utf8Bytes.Length; i++)
{
utf8Bytes[i] = 0;
}
utf8BytesPin.Free();
}
}
它依賴于獲取指向原始 UTF-16 字符串和 UTF-8 緩沖區的指針,然后Encoding.UTF8.GetBytes(Char*, Int32, Byte*, Int32)用于將轉換保留在非托管內存中。

TA貢獻1993條經驗 獲得超6個贊
有沒有考慮GC.Collect()
在獲得hash后調用?
根據GC.Collect上的MSDN:
強制立即對所有代進行垃圾收集。使用此方法嘗試回收所有無法訪問的內存。它執行所有代的阻塞垃圾收集。
所有對象,無論它們在內存中的時間有多長,都被考慮收集;但是,不會收集托管代碼中引用的對象。使用此方法強制系統嘗試回收最大量的可用內存。
從我在您的代碼中看到的,它不應該保留對轉換中使用的對象的任何引用。這一切都應該由 GC 收集和處理。
- 2 回答
- 0 關注
- 289 瀏覽
添加回答
舉報