.NET 2.0 Symmetric Encryption Code Sample
One of the most common problems when developing any web site if the need to use Symmetric Encryption to save some data in the Cookie so that it can be looped back to the user's session / identity. .NET provides a very robust mechanism in which this can be achieved and supports the most well-known of both, Symmetric and Asymmetric encryption algorithms. This MSDN article does a phenomenal job of explaining the nittie-gritties of the various algorithms available and the different scenarios in which one should use them.
Though the CryptoSampleCSSample.msi provides some samples as to how to achieve this. It fails to address one of the most common scenarios of storing the IV (the Initialization Vector) and the Key in an app.config (for Windows / Console Applications) and in web.config (for Web Applications).
This complete code demonstrates how to pickup IV and Key from the web.config / app.config and then use the values in encrypting and decrypting text values. The key thing to note is that the string needs to be converted using:
Convert.FromBase64String(IV)
NOTE: The IV and Key can be generated by using the CryptoSampleCS.exe provided in the MSDN Article mentioned above.
First, the app.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="IV" value="SuFjcEmp/TE="/>
<add key="Key" value="KIPSToILGp6fl+3gXJvMsN4IajizYBBT"/>
</appSettings>
</configuration>
Now the full code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Configuration;
public class CryptoHelper
{
//private readonly string IV = "SuFjcEmp/TE=";
private readonly string IV = string.Empty;
//private readonly string Key = "KIPSToILGp6fl+3gXJvMsN4IajizYBBT";
private readonly string Key = string.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="CryptoHelper"/> class.
/// </summary>
public CryptoHelper()
{
IV = ConfigurationManager.AppSettings["IV"];
Key = ConfigurationManager.AppSettings["Key"];
}
/// <summary>
/// Gets the encrypted value.
/// </summary>
/// <param name="inputValue">The input value.</param>
/// <returns></returns>
public string GetEncryptedValue(string inputValue)
{
TripleDESCryptoServiceProvider provider = this.GetCryptoProvider();
// Create a MemoryStream.
MemoryStream mStream = new MemoryStream();
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream cStream = new CryptoStream(mStream,
provider.CreateEncryptor(),CryptoStreamMode.Write);
// Convert the passed string to a byte array.: Bug fixed, see update below!
// byte[] toEncrypt = new ASCIIEncoding().GetBytes(inputValue);
byte[] toEncrypt = new UTF8Encoding().GetBytes(inputValue);
// Write the byte array to the crypto stream and flush it.
cStream.Write(toEncrypt, 0, toEncrypt.Length);
cStream.FlushFinalBlock();
// Get an array of bytes from the
// MemoryStream that holds the
// encrypted data.
byte[] ret = mStream.ToArray();
// Close the streams.
cStream.Close();
mStream.Close();
// Return the encrypted buffer.
return Convert.ToBase64String(ret);
}
/// <summary>
/// Gets the crypto provider.
/// </summary>
/// <returns></returns>
private TripleDESCryptoServiceProvider GetCryptoProvider()
{
TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();
provider.IV = Convert.FromBase64String(IV);
provider.Key = Convert.FromBase64String(Key);
return provider;
}
/// <summary>
/// Gets the decrypted value.
/// </summary>
/// <param name="inputValue">The input value.</param>
/// <returns></returns>
public string GetDecryptedValue(string inputValue)
{
TripleDESCryptoServiceProvider provider = this.GetCryptoProvider();
byte[] inputEquivalent = Convert.FromBase64String(inputValue);
// Create a new MemoryStream.
MemoryStream msDecrypt = new MemoryStream();
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream csDecrypt = new CryptoStream(msDecrypt,
provider.CreateDecryptor(),
CryptoStreamMode.Write);
csDecrypt.Write(inputEquivalent, 0, inputEquivalent.Length);
csDecrypt.FlushFinalBlock();
csDecrypt.Close();
//Convert the buffer into a string and return it.
return new UTF8Encoding().GetString(msDecrypt.ToArray());
}
}
Update: JT Carvalho emailed me about a bug in the code above.
"You are encoding the crypted value with AsciiEncoding and decoding it with UTF8Encoding, so in some special chars (like portuguese chars) they will not match.
I think encoding it with UTF8Encoding it will resolve this."
Thanks for pointing this out and thanks for the fix as well!