Zakładając, że chcesz korzystać z tablicy bajtów i pozbyć się go tak szybko, jak skończysz, należy upakować całą operację tak, że czyści się po sobie:
public static T Process<T>(this SecureString src, Func<byte[], T> func)
{
IntPtr bstr = IntPtr.Zero;
byte[] workArray = null;
GCHandle handle = GCHandle.Alloc(workArray, GCHandleType.Pinned);
try
{
/*** PLAINTEXT EXPOSURE BEGINS HERE ***/
bstr = Marshal.SecureStringToBSTR(src);
unsafe
{
byte* bstrBytes = (byte*)bstr;
workArray = new byte[src.Length * 2];
for (int i = 0; i < workArray.Length; i++)
workArray[i] = *bstrBytes++;
}
return func(workArray);
}
finally
{
if (workArray != null)
for (int i = 0; i < workArray.Length; i++)
workArray[i] = 0;
handle.Free();
if (bstr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstr);
/*** PLAINTEXT EXPOSURE ENDS HERE ***/
}
}
A oto jak wygląda przypadek użycia:
private byte[] GetHash(SecureString password)
{
using (var h = new SHA256Cng()) // or your hash of choice
{
return password.Process(h.ComputeHash);
}
}
Żadnych muz, bez zamieszania, żadnego zwykłego tekstu nie pozostającego w pamięci.
Należy pamiętać, że tablica bajtów przekazana do func()
zawiera nieprzetworzone wyświetlanie Unicode tekstu jawnego, co nie powinno stanowić problemu w przypadku większości aplikacji kryptograficznych.
W przeciwieństwie do ciągów ANSI C, BSTRy mogą zawierać znaki puste, więc skanowanie pod kątem zerowych jest nieprawidłowe. Wystarczy użyć elementu Długość źródłowego SecureString (pomnóż przez 2, aby uzyskać liczbę bajtów). –