In .NET, the SecureString type exists to prevent leaking secrets in memory. I want to create a hash from the contents of a SecureString, without putting the contents in memory in a place where I can't delete them. I have come up with the following solution, where I pinvoke the winapi crypto functions to calculate a hash over a BSTR. Does this approach make any sense? Doesn't this put the secret somewhere in memory where I can't delete it?
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool Crypt...(...);
static byte[] CreateHashForSecureString(SecureString ss)
{
IntPtr hProv = IntPtr.Zero;
CryptAcquireContext(ref hProv, null, null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
IntPtr hHash = IntPtr.Zero;
CryptCreateHash(hProv, CALG_SHA1, IntPtr.Zero, 0, ref hHash);
var bstr = Marshal.SecureStringToBSTR(ss);
var len = (uint)Marshal.ReadInt32(bstr, -4);
CryptHashData(hHash, bstr, len, 0);
Marshal.ZeroFreeBSTR(bstr);
byte[] pbData = new byte[20];
uint length = (uint)pbData.Length;
CryptGetHashParam(hHash, HP_HASHVAL, pbData, ref length, 0);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return pbData;
}
I am aware that error handling is missing. I am also aware that using SecureString is often more hasle than it's worth. I am particularly looking for whether this is the right approach to this problem.