It's a well known fact that C# string
is pretty insecure, it's not pinned in RAM, the Garbage Collector can move it, copy it, leave multiple traces of it in RAM and the RAM can be swapped and be available as a file to be read, not mentioning several other known facts.
In order to mitigate this Microsoft came up with SecureString
. The thing is: what is the proper way of using it?
I ask this because sooner or later you will have to extract the inner string. And yes, SecureString
does allow us to write one char
at a time and gives us some other minor usages while hiding it's secret, but sometimes we need the whole string at once or something like it. So far all implementations I see use a regular string
at the end, with the extracted and decrypted content from the SecureString
which I think (or hope) it's avoidable in some cases even though it might involve some complicated code to get around a .NET string
.
In my case I use a library for password hashing called BCrypt. It uses a regular string
for calculating the hashes, which I think is far from ideal. I didn't find any libraries that would accept a SecureString
directly, so I don't have much of an option but use it.
Currently I run code such as this:
SecureString password; // This usually comes from a PasswordBox Property
IntPtr passwordBSTR = Marshal.SecureStringToBSTR(password);
string insecurePassword = Marshal.PtrToStringBSTR(passwordBSTR);
Marshal.ZeroFreeBSTR(passwordBSTR);
passwordBSTR = default(IntPtr);
password.Clear();
// Use the insecurePassword....usually as:
bool result = BCrypt.Net.BCrypt.Verify(insecurePassword, user.Password); // This hashes the provided password and compares it with another BCrypt hash.
insecureString = string.Empty; // hoping for the GC to act now, fingers crossed.
// use result and etc...
This way the password raw string
will be copied multiple times for the BCrypt
method and probably even more times inside it.
This makes some questions arise in my mind:
1 - Are BSTR
strings like C
strings in the sense of memory management? Are they pinned in RAM and I can manipulate them and erase them as I see fit so it will be more secure to use them in C# or interop it with a C++ code so I can eliminate a lot of my .NET string
manipulations (like verifying if the password string is null or white space or has the correct length or has the desired password strength)?
2 - If question's #1 answer is "yes" then should I invest some time to pass the BSTR string to a interop C++ code to calculate it's hash and verify?
3 - Is my later code correct or am I missing something on SecureString
manipulation?
Just to be clear: My main intent with this question is to evaluate if I should pass all my password handling code to C++ from my C# (probably using C++/CLI or interop) to achieve a more secure code than what C# has to offer. This scenario really concerns me for password string hashing were multiple strings will be created and copied with the user's secret information scattered all over the RAM.
As an example: I could make a method like:
public string SecureHash(SecureString password)
And this method will extract the SecureString
value and pass it as a BSTR
string (or other extraction option, I honestly don't know the benefits between them) to a C++ hashing method, so we can control all the places our password sits in memory.
I ask this to not have a huge work refactoring my code and in the end discover it was all for nothing because I was using SecureStrings
wrongly all the time and there are already solutions for this, or a false sense of security, as it happens sometimes, since I am not aware of how BSTR
strings are implemented in memory or the other SecureStrings
extraction options (Unicode, ANSI and etc).