A Reusable Secure Login Form

For the impatient, source and binaries and quick explanation available at: http://code.msdn.microsoft.com/UtilsCommonViews/

How many of the last ten projects you implemented had a login form of some kind? Thanks to all those wonderful apis that you coded applications against, probably the majority of them did. Now try to remember how many of those login forms used strings for storing passwords in memory and how many saved the password to a settings file in plain text. I know most of my small utilities did and I’m not proud of it, but it happened and I’m almost sure you have some of those lying around in your src folder.

Anyway, today I had a couple of hours of spare time and decided to implement a reusable secure login form. My goals were to use SecureString for storing the password in memory and encrypt the username and password in a settings file for storing them between the sessions. I started off with a little research about the components I’d need to use.

SecureString is a class that was introduced in .NET Framework 2.0. Why not simply use a string for storing a password? Well let’s have the MSDN do the explaining:

An instance of the System.String class is both immutable and […] cannot be programmatically […] deleted from computer memory. Consequently […] there is a risk the information [stored in it] could be revealed after it is used […].

A SecureString object is similar to a String object in that it has a text value. However, the value of a SecureString object is automatically encrypted, can be modified until your application marks it as read-only, and can be deleted from computer memory by either your application or the .NET Framework garbage collector.

That’s a great scenario for our password. Next up I found this great secure textbox control that handles the user input into a SecureString object. The original control and source can de downloaded at: http://www.theglavs.com/DownloadItem.aspx?FileID=46. (Thanks to Glav and Dominik Zemp who created or extended the control.)

Then I wrote this simple extension method to get the characters of the contents of the SecureString because it can get quite dirty to do it inline. It uses requires execution of unmanaged code and some marshalling.

public static Char[] GetCharacters(this SecureString secureString) {
    if (secureString == null) throw new ArgumentNullException("secureString");

    lock (secureString) {
        char[] _chars = new char[secureString.Length];
        IntPtr _ptrToChars = IntPtr.Zero
        try {
            _ptrToChars = Marshal.SecureStringToBSTR(secureString);
            Marshal.Copy(_ptrToChars, _chars, 0, secureString.Length);
        }
        finally {
            if (_ptrToChars != IntPtr.Zero)
                Marshal.ZeroFreeBSTR(_ptrToChars);
        }

        return _chars;
    }
}

The second feature was to encrypt the username and password in a file. I looked at encrypting the configuration file but decided against that path and went with encrypting the data using the ProtectedData API (in System.Security.Cryptography). It’s a simple call to the static method:

ProtectedData.Protect(byte[] data, byte[] entropy, DataProtectionScope);

The entropy specifies a kind of salt for your application and the DataProtectionScope can be set so that only the current user can decrypt the data or to local machine. The library will save a file UserData.bin to the local application directory (including the calling assemblies name). Additionally I decided to encrypt the file using the FileInfo.Encrypt method. This works only on NTFS, so the library will currently only work on NTFS systems. Now that I’ve written that sentence I think I’ll make that optional in the next release.Which brings me to the release and the source code. I want to try out MSDN code gallery so I’ve published the project here: http://code.msdn.microsoft.com/UtilsCommonViews/

Using the library is very simple:

LoginController _loginController = new LoginController();
_loginController.GetCredentials();

string _username = _loginController.Username;
char[] _password = _loginController.Password; // _password needs to be zero'ed a.s.a.p. after usage

That last comment is important. If you don’t zero out that char array, the password will be floating around in memory.

Comments, suggestions are of course welcome! Here or in the MSDN code gallery.

Note: The project uses another utility library (Utils.Extensions) of mine that I’ve built-up over the last weeks that contains a few extension methods for common stuff I was missing in the BCL. The source is not clean enough yet for publishing but it’s in the pipe. For now it’s only available in this project as a release dll.

Technorati Tags: .net,Windows Forms,Libraries,SecureString