In other words, beginners always have had difficulty in implementing a reliable yet flexible method for securing cookies. I have used the following code often and I am sure this will help anyone looking for a quick-fix solution to secure cookies.
The basic architecture is to create static methods to which you pass a cookie and get a encrypted version in return. It also conveniently retrieves the Algorithm to use as well as the key to encrypt/decrypt from the web.config file and can be adapted to retrieve/generate the key in other ways.
Step 1: Start off with our class.
- using System.Security.Cryptography; //and other...
- public class Security
- {
- //If you dont want ur methods to be static then use this and instantiate an object before use
- //byte[] Key;
- //string AlgorithmName;
- public Security()
- {
- //If you dont want ur methods to be static then use this
- //char[] chars = { ',' };
- //string[] splits = ConfigurationManager.AppSettings["CookieSecurityKey"].Split(chars);
- //AlgorithmName = splits[0];
- //Key = new byte[Int32.Parse(splits[1])];// = KEY_64;
- //for (int i = 2; i < Key.Length + 2; i++)
- // Key[i - 2] = byte.Parse(splits[i].Trim());
- }
- ...
You can store the key/algoritm name in the web.config like this:
- <appsettings>
- <!--First Item - algo name, second item - key size, third till end - key values-->
- <!--Possible Algorithms(valid key sizes) - DES(8), TripleDES(16,24), RC2(5,16), Rijndael(16,24,32)-->
- <!--Example: <add key ="CookieSecurityKey" value="RC2, 55, 2, 66, 23, 16, 118">-->
- <add key="CookieSecurityKey" value="DES, 8, 91, 161, 38, 16, 7, 24, 28, 222"></add>
- </appsettings>
Step 2: Create the basic methods that encode/decode a piece of string
- public static string Encode(string value, Byte[] key, string AlgorithmName)
- {
- // Convert string data to byte array
- byte[] ClearData = System.Text.Encoding.UTF8.GetBytes(value);
- // Now create the algorithm from the provided name
- SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
- Algorithm.Key = key; //you can apply your own key mechs here
- MemoryStream Target = new MemoryStream();
- // Generate a random initialization vector (IV), helps to prevent brute-force
- Algorithm.GenerateIV();
- Target.Write(Algorithm.IV, 0, Algorithm.IV.Length);
- // Encrypt information
- CryptoStream cs = new CryptoStream(Target, Algorithm.CreateEncryptor(), CryptoStreamMode.Write);
- cs.Write(ClearData, 0, ClearData.Length);
- cs.FlushFinalBlock();
- // Convert the encrypted stream back to string
- return Convert.ToBase64String(Target.GetBuffer(), 0, (int)Target.Length);
- }
- public static string Decode(string value, Byte[] key, string AlgorithmName)
- {
- // Convert string data to byte array
- byte[] ClearData = Convert.FromBase64String(value);
- // Create the algorithm
- SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
- Algorithm.Key = key;
- MemoryStream Target = new MemoryStream();
- // Read IV and initialize the algorithm with it
- int ReadPos = 0;
- byte[] IV = new byte[Algorithm.IV.Length];
- Array.Copy(ClearData, IV, IV.Length);
- Algorithm.IV = IV;
- ReadPos += Algorithm.IV.Length;
- // Decrypt information
- CryptoStream cs = new CryptoStream(Target, Algorithm.CreateDecryptor(), CryptoStreamMode.Write);
- cs.Write(ClearData, ReadPos, ClearData.Length - ReadPos);
- cs.FlushFinalBlock();
- // Get the bytes from the memory stream and convert them to text
- return System.Text.Encoding.UTF8.GetString(Target.ToArray());
- }
Step 3: Create the methods that encode/decode the cookie
- public static HttpCookie EncodeCookie(HttpCookie cookie)
- {
- if (cookie == null) return null;
- //get key and algorithm from web.config/appsettings
- //Comment this section if you do now what this method to be static
- char[] chars = { ',' };
- string[] splits = ConfigurationManager.AppSettings["CookieEncodingKey"].Split(chars);
- string AlgorithmName = splits[0];
- byte[] Key = new byte[Int32.Parse(splits[1])];// = KEY_64;
- for (int i = 2; i < Key.Length + 2; i++)
- Key[i - 2] = byte.Parse(splits[i].Trim());
- HttpCookie eCookie = new HttpCookie(cookie.Name);
- for (int i = 0; i < cookie.Values.Count; i++)
- {
- string value = HttpContext.Current.Server.UrlEncode(Encode(cookie.Values[i], Key, AlgorithmName));
- string name = HttpContext.Current.Server.UrlEncode(Encode(cookie.Values.GetKey(i), Key, AlgorithmName));
- eCookie.Values.Set(name, value);
- }
- return eCookie;
- }
- public static HttpCookie DecodeCookie(HttpCookie cookie)
- {
- if (cookie == null) return null;
- //Comment this section if you do now what this method to be static
- char[] chars = { ',' };
- string[] splits = ConfigurationManager.AppSettings["CookieEncodingKey"].Split(chars);
- string AlgorithmName = splits[0];
- byte[] Key = new byte[Int32.Parse(splits[1])];// = KEY_64;
- for (int i = 2; i < Key.Length + 2; i++)
- Key[i - 2] = byte.Parse(splits[i].Trim());
- HttpCookie dCookie = new HttpCookie(cookie.Name);
- for (int i = 0; i < cookie.Values.Count; i++)
- {
- string value = Decode(HttpContext.Current.Server.UrlDecode(cookie.Values[i]), Key, AlgorithmName);
- string name = Decode(HttpContext.Current.Server.UrlDecode(cookie.Values.GetKey(i)), Key, AlgorithmName);
- dCookie.Values.Set(name, value);
- }
- return dCookie;
- }
At this point you have the basis setup and you can use the class in your code.
Encoding Example:
- HttpCookie cookie = new HttpCookie("MySecureCookie");
- cookie["ID"] = "39369a0d-975e-4456-9ade-3f04639fd309"; //recommended: use some unique value to later check for fraudulent cookies while retrieving
- cookie["Name"] = username;
- cookie["Email"] = email;
- cookie = Security.EncodeCookie(cookie); //encode
- cookie.Expires = DateTime.Now.AddDays(90);
- Response.Cookies.Add(cookie);
- ...
Decoding Example:
- HttpCookie cookie = context.Request.Cookies["MySecureCookie"];
- cookie = Security.DecodeCookie(cookie); //decode
- if (cookie["ID"] == "39369a0d-975e-4456-9ade-3f04639fd309") cookieChecksOut = true;
- //process cookie
- ...
This code allows using a single generic implementation to use a variety of algorithms based on their merits and properties. I hope this will help a lot of beginners.