Monday, September 3, 2007

Easy Reversible Data ASP.NET Encryption

Sometimes your web application requires knowledge of the user's password where you still want to key the data in a protected format.   At other times you have data stored in a database that needs to be protected just as much as your passwords needs to be.  Reversible encryption is often called symmetric/asymmetric cryptography as compared to one-way hashing such MD5 that many systems use to store passwords.

Have you ever wanted to use encryption/decryption of data in .Net, but were too intimidated by the various encryption classes in .Net?  You may have noticed that the .Net Membership Provider system provides an easy to use, built in system for encryption/decryption of passwords, requiring you only to generate keys used in the machineKey settings of the machine.config.  You may have wanted to use the same system to encrypt/decrypt other data.  The good news is that with minimal effort you can.  While the MembershipProvider class does not have public methods for encrypting/decrypting data it has protected methods that are almost as good.  All you need to do is inherit from MembershipProvider and expose the protected methods as public, and voila!  The job is just about done.

/// <summary>
/// Sample code that exposes the protected DecryptPassword and EncryptPassword as public
/// Note: MembershipProvider is an abstract class with methods to implement.  You can also
/// inherit from SqlMembershipProvider if all you want is just the encryption methods
/// </summary>
public class MyMembershipProvider : System.Web.Security.MembershipProvider
{
     /// <summary>
     /// Allows public access to protected member 
     /// </summary>
     /// <param name="encodedPassword"></param>
     /// <returns></returns>
     public new byte[] DecryptPassword(byte[] encodedPassword)
     {
         return base.DecryptPassword(encodedPassword);
     }

     /// <summary>
     /// Allows public access to protected member
     /// </summary>
     /// <param name="password"></param>
     /// <returns></returns>
     public new byte[] EncryptPassword(byte[] password)
     {
          return base.EncryptPassword(password);
     }
}

// Sample code to encrypt/decrypt data
MyMembershipProvider myMembershipProvider = new MyMembershipProvider();
string testString = "text to ecrypt";
// Use base64 string when storing data in a varchar instead of a blob.
string encryptedData = Convert.ToBase64String(
     myMembershipProvider.EncryptPassword(ASCIIEncoding.ASCII.GetBytes(testString)));
string decryptedValue = ASCIIEncoding.ASCII.GetString(    
     myMembershipProvider.DecryptPassword(Convert.FromBase64String(encryptedData)));
Debug.Assert(string.Equals(testString, decryptedValue));

If you want to use encryption methods that we just exposed in the MembershipProvider subclass, you have to provide a static encryption key.  ASP.NET uses auto-generated encryption keys by default so you will need to generate an encryption key or you will get an exception.  Information about how to the set up the machineKey can be found in DevelopmentNow's article ASP.NET machineKey Generator.   A live demo also by DevelopmentNow.com will generate a machineKey for you although you can run the code on your local development machine (recommended for a production server).  You may also want to lookup the machineKey element documentation  on MSDN.

As a final thought, you may be thinking, well I am not really using the MembershipProvider at all or I am not using reversible encryption on login passwords.  Isn't there a method I can call on the MachineKey section of the config?  The answer is that there is and but the problem is it that the EncryptOrDecryptData method is internal so you can't call it.  From the debugging call stack and from Lutz Roeder's .Net Reflector you can see that the MembershipProvider is actually calling this method.

Links