Encrypting Data in .NET Applications

I’ve had several people ask me lately about encrypting data in .NET.  I’m not sure why the question has come up a lot recently, but it’s definitely something good to know if you have any sensitive data that needs to be stored.  .NET provides two main encryption roads that you can travel down including symmetric encryption and asymmetric encryption.  Symmetric encryption relies upon a private key to encrypt and decrypt while asymmetric encryption relies upon a public key to encrypt and a private key to decrypt.  Symmetric encryption provides the best performance while asymmetric encryption provides the best security in situations where keys need to be exchanged between different parties.  If you need to encrypt and decrypt data directly within an application symmetric encryption works fine as long as other prying eyes can’t get their hands on the private key (or your source code). 

I have a fairly straightforward encryption/decryption class named Encryptor that I use when I need to perform symmetric encryption in my web applications.  The class relies upon a symmetric algorithm called Rijndael that can be used to encrypt and decrypt data. 

While I’m not going to provide a detailed discussion of what the class does I’m happy to post it here for anyone who needs that type of functionality.  Keep in mind that you’ll need to update the password and salt values to whatever you need to use in your applications and should consider dynamically grabbing the password from a secured data store as opposed to hard-coding it in the source code (especially if you’ll be shipping the assembly…people can disassemble it using tools like Reflector).  The salt acts as a type of junk data that is used in constructing the password and can also be used to pad encrypted data with bogus bytes so that hackers don’t know which part of the data is valid and which part is junk.

using System;
using System.IO;
using System.Security.Cryptography;

namespace YourApp.Model.Helpers {
    
    internal class Encryptor 
    {
        internal static string Decrypt(string cipherText)
        { 
            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_Pwd, _Salt); 
            byte[] decryptedData = Decrypt(cipherBytes, pdb.GetBytes(32), pdb.GetBytes(16)); 
            return System.Text.Encoding.Unicode.GetString(decryptedData); 
        } 

        private static byte[] Decrypt(byte[] cipherData, byte[] Key, byte[] IV) { 
            MemoryStream ms = new MemoryStream(); 
            CryptoStream cs = null;
            try {
                Rijndael alg = Rijndael.Create(); 
                alg.Key = Key; 
                alg.IV = IV; 
                cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write); 
                cs.Write(cipherData, 0, cipherData.Length); 
                cs.FlushFinalBlock();
                return ms.ToArray();
            }
            catch {
                return null;
            }
            finally {
                cs.Close(); 
            }
        }

        public static string Encrypt(string clearText)
        {
            byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_Pwd, _Salt);
            byte[] encryptedData = Encrypt(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
            return Convert.ToBase64String(encryptedData);
        }


        private static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV)
        {
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = null;
            try
            {
                Rijndael alg = Rijndael.Create();
                alg.Key = Key;
                alg.IV = IV;
                cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
                cs.Write(clearData, 0, clearData.Length);
                cs.FlushFinalBlock();
                return ms.ToArray();
            }
            catch
            {
                return null;
            }
            finally
            {
                cs.Close();
            }
        }

        static string _Pwd = "Your_Password_Goes_Here"; //Be careful storing this in code unless it’s secured and not distributed
        static byte[] _Salt = new byte[] {0x45, 0xF1, 0x61, 0x6e, 0x20, 0x00,  0x65, 0x64, 0x76, 0x65, 0x64, 0x03, 0x76};
    }
}

To use the class to encrypt data (and get back a Base64 encoded string) the following code can be written:

string creditCardNumber = Encryptor.Encrypt(cust.CreditCardNumber);

 

Logo

For more information about onsite, online and video training, mentoring and consulting solutions for .NET, SharePoint or Silverlight please visit http://www.thewahlingroup.com/.

Published Thursday, May 21, 2009 1:08 PM by dwahlin
Filed under: ,

Comments

# re: Encrypting Data in .NET Applications

Thursday, May 21, 2009 7:02 PM by nisarkhan

how would you Decrypt?, the one above is a private or is that suppose to be Public ?

thanks for the code.

# re: Encrypting Data in .NET Applications

Friday, May 22, 2009 12:09 AM by dwahlin

nisarkhan:  The first Decrypt method is marked as internal and that's what you'd call from within the same .NET assembly.  If you need to call it outside of the assembly then you'd need to mark it as public.  Since I use it within my Model layer assembly (it's just a helper class) I marked it as internal so that no other external code can decrypt data.

# re: Encrypting Data in .NET Applications

Friday, May 22, 2009 12:44 AM by Eric

Any reason for choosing Rijndael over the RijndaelManaged class?

# re: Encrypting Data in .NET Applications

Friday, May 22, 2009 3:15 AM by dwahlin

Eric:

The Rijndael.Create() call actually instantiates RijndaelManaged behind the scenes.  I don't really need the flexibility for this example, but by using the abstract Rijndael class directly it's possible to have different classes other than the default instantiated behind the scenes.