SecureString class in .Net V2 (Part 2)
A couple of days ago I blogged about the SecureString class in .Net V2. I mentioned briefly about some of its features and why it exists, then proceeded to measure some of the cost of its functionality in terms of performance. I took some liberties with how I was accessing the SecureString contents to make it simple to measure performance.
Eric Newton rightly posted a comment regarding that accessing the SecureString contents in this manner made it insecure and makes using it a waste of time. So this post is not about performance, and is an attempt to address that comment and is probably closer to how the SecureString is going to be used.
Basically, the SecureString holds its contents encrypted. Anytime you place the contents into a regular string, it ceases to be secure as the runtime/GC then manages that unencrypted instance and will keep copies, in memory in plain text, or maybe the swap file and makes it easy to snoop on.
So whats the point of the SecureString if you can't get its contents back for easy usage? Well, one way is to never marshall it back into a regular string, but instead compare/use a character at a time using the BSTR pointer, ensuring that you use the "marshalled" plain text contents of the string as quickly as possible, then clear out that section once you are done. A code example might look like :
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace junk1
{
class Program
{
static void Main(string[] args)
{
// Yes, this text is held insecurely in memory
string TEXTDATA = "This is some sensitive info";
using (System.Security.SecureString secretString = new System.Security.SecureString())
{
// Add the text from our insecure string into our SecureString
// Normally, you WOULD NOT keep a string in memory for this purpose but it makes this
// Demo a little shorter and easier to read.
foreach (char c in TEXTDATA)
secretString.AppendChar(c);
Console.WriteLine("Marshalling...");
// Marshall the secure string to a BSTR pointer
IntPtr ptr = Marshal.SecureStringToBSTR(secretString);
try
{
byte b = 1;
int i = 0;
// Loop through until we hit the string terminator '\0'
while (((char)b) != '\0')
{
b = Marshal.ReadByte(ptr, i);
Console.Write((char)b);
i = i + 2; // BSTR is unicode and occupies 2 bytes
}
Console.WriteLine("\nDone.");
}
finally
{
// Free AND ZERO OUT our marshalled BSTR pointer to our securetext
Marshal.ZeroFreeBSTR(ptr);
}
}
Console.ReadLine();
}
}
}
This little code snippet shows how we marshall a SecureString into a BSTR string pointer. From here we can iterate through the character contents, comparing them or in this case, writing them to the console. Once we are finished with it, we want to free the BSTR and zero out its contents to make sure no one or nothing can read those contents. This is why we wrap it in a try...finally to ensure it gets freed and zero'ed out.
Granted, its not the nicest code but I hate making simple blog entries too long winded.
Note: I am incrementing the pointer offset by 2 each time as its a unicode string and each character occupies 2 bytes.
Update: No one picked it up initially, but the SecureString uses unmanaged resources, and like all good objects that do this, it implements the IDisoposable interface. I have modified the code above to utilise this interface via a 'using' statement.