SecureString in NET v1.1

Every time you need to store sensitive data your first thought use to be encryption.  You probably gather that data from the store, decrypt it and put it on a managed string in order to be consumed by some API (ie. ConnectionStrings properties and the like). However you should know that this kind of pattern is susceptible to disclosure by anyone who can read your process memory since your data is not encrypted anymore. Also, this same scenario will be seen whenever you process gets swapped out to disk, so all your unencrypted data will be placed in your swap file. As you may already know, the standard System.String is by no means intended to store sensitive data for several reasons, most of them listed in this Shawn's post. The most important of these reasons is the immutability of the managed string object.The recommended solution before Whidbey (a.k.a VS 2005) was to use a byte array.  Since byte arrays can be pinned down, encrypted, and zeroed out, many of the above concerns were solved.  Whidbey will be introducing a new class, SecureString, which helps to make this all easier for you. This class will address all the mentioned issues by holding an encrypted version of your data (using DPAPI), and will be only unencrypted when accessed (later we‘ll see how).And now let’s see the good part. If you don’t want to wait till Whidbey RTM appears, I developed a similar class (same public interface) that will mimics the SecureString version in Whidbey but for .NET v1.1. However you should know that like its Whidbey counterpart, since SecureString uses DPAPI, you should need the required service packs (usually better than sp3) on Windows 98, ME and Windows 2000.  

Downloads

You can download the sample usage along with the NCrypto cryptography library from the Sourceforge site.  The specific example is under the “TestSecureString” folder. You will find many other projects that test the rest of the NCrypto classes.

SecureString Description

Since the internal implementation uses a pinned byte array, the garbage collector will not move the encrypted string around in memory and you will be able to destroy and release this memory by using the implemented IDisposable interface. This class also provides a feature that lets you lock the internal data down as read only, preventing other code from modifying your string.The class provides two constructors. The default one will build be constructed without an existing character array, and data can be copied in one character at a time. The other constructor will receive a pointer to a character array, and the length of that array.  When constructed this way, the class will make a copy of your array, allowing you to zero out your insecure copy. Whether you create a SecureString instance from a char pointer or just a new empty one, you may add or modify data in your string with the following methods.  For instance, you may add one char at a time with “AppendChar()”, insert new chars with “InsertAt()”, remove at the specified position with “RemoveAt()”, and modify at certain position with “SetAt()” method as well as a Length property.  You may also lock down your string with “MakeReadOnly()” and IsReadOnly() methods.  Finally, you will destroy every trace of your string with Clear(), Dispose(), and the finalizer.

The Sample

One of the most common scenarios for this class will be the credentials gathering from the UI and later use by the application. The following example will show the use of UICredentialsHelper class of the NCrypto library mentioned above. This class provide access to a feature provided by Windows XP and Windows Server 2003 called "Stored User Names and Passwords" to associate a set of credentials with a single Windows user account, storing those credentials using the Data Protection API (DPAPI). Using these APIs will provide you with a consistent user interface and will allow you to automatically support the caching of these credentials by the operating system. The “PromptForSecureCredentials” method returns an instance of the “SecureCredential” class that will hold, as you might guess, the password data inside a SecureString. The next figure shows a very simple usage of this class.
 using( SecureCredential credentials =                                   UICredentialsHelper.PromptForSecureCredentials(                                                     "SecureCredentials",                                                     "Enter your credentials" ) ){      if( credentials == null )      {            return;      }       // Make some use of these credentials.      // ...} 
 When the PromptForSecureCredentials” method is called, you will see a dialog like the one in the figure that will prompt you for your credentials, that is your username and password. The password will never be stored in a managed string so you will have complete control of this sensitive data when in transit (memory volatile store). The option to remember your password will be safely stored by the OS using (you guess it) DAPI.  

 

SecureString to Managed String

Getting data out of the SecureString is not as straightforward as you may image at first glance but it can be done with the help of the some static methods. These methods are the same that you will find in the Marshal class of Whidbey and has been extended to provide methods that convert a SecureString into a BSTR or a raw block of ANSI or Unicode memory.  However we don’t have these methods in v1.1 so I added some of these methods with the same signature to my version of SecureString. In this figure you have a sample usage of “SecureStringToGlobalAllocUni” that will return a pointer to the Unicode unencrypted data in memory. Once you're done using the unprotected string, you need to make sure to erase that copy. You can do that with the help of “ZeroFreeGlobalAllocUni” method.
 IntPtr ustr = SecureString.SecureStringToGlobalAllocUni( credentials.Password ); try{      // WARNING: This managed string will remain in memory until      // collected by the GC.      string clearTextPwd = Marshal.PtrToStringUni( ustr );      Console.WriteLine( "Pwd: {0}", clearTextPwd );}finally{      // Once you're done using the unprotected string, you need       // to make sure to erase that copy.      SecureString.ZeroFreeGlobalAllocUni( ustr );} 
As Shawn posted in his blog, SecureString will only continue to become more useful as more and more APIs begin to use it. An interesting use in Whidbey was posted here. In an ideal world, eventually you'd be able to go end-to-end with your SecureString never being converted to a standard String. However this is not possible with much of the current APIs out there (like the ConnectionString sample mentioned above).

It's also important to remember that you won't necessarily have to convert to a String like the last sample showed. For instance, if the final use of the string is in native code, than it can be passed through without ever becoming a managed string and hitting the problem where the GC can move it about in memory.
Hopefully this samples and classes will give you a good idea of how to handle sensitive data that is usually packed in a typical managed string. Enjoy it! This posting is provided "AS IS" with no warranties, and confers no rights. 

23 Comments

Comments have been disabled for this content.