When reading and validating URL parameters you probably came across the situation that you wanted to hide some values for security reasons. Such a situations happen very often eg. when confirming email address of an user by sending validation link or by validating payment callback etc.
One of the solutions is to encrypt Url parameters using DES algorithm. DES it’s a symmetric algorithm that allows you to encrypt and decrypt values using shared public key. It is advisable to change public key from time to time for security reasons.
Below are two helper methods needed to encrypt and decrypt values:
/// <summary>
/// Encrypts an string using provided public key (DES)
/// </summary>
/// <param name="stringToEncrypt">String to be encrypted</param>
/// <param name="sEncryptionKey">Public key</param>
/// <returns>string</returns>
public static string DES_encrypt(string stringToEncrypt, string sEncryptionKey)
{
if (stringToEncrypt.Length <= 3) { throw new Exception("Invalid input string"); }
byte[] key = { };
byte[] IV = { 10, 20, 30, 40, 50, 60, 70, 80 }; //defining vectors
byte[] inputByteArray;
key = Encoding.UTF8.GetBytes(sEncryptionKey.Substring(0, 8));
using (var des = new DESCryptoServiceProvider())
{
inputByteArray = Encoding.UTF8.GetBytes(stringToEncrypt);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, des.CreateEncryptor(key, IV), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
}
}
}
and
/// <summary>
/// Decrypts an string using provided public key (DES)
/// </summary>
/// <param name="stringToDecrypt">String to be decrypted</param>
/// <param name="sEncryptionKey">Public key</param>
/// <returns>string</returns>
public static string DES_decrypt(string stringToDecrypt, string sEncryptionKey)
{
if (stringToDecrypt.Length <= 3) { throw new Exception("Invalid input string"); }
byte[] key = { };
byte[] IV = { 10, 20, 30, 40, 50, 60, 70, 80 };//defining vectors
byte[] inputByteArray = new byte[stringToDecrypt.Length];
key = Encoding.UTF8.GetBytes(sEncryptionKey.Substring(0, 8));
using (var des = new DESCryptoServiceProvider())
{
inputByteArray = Convert.FromBase64String(stringToDecrypt.Replace(" ", "+"));
using (var ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(key, IV), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
var encoding = Encoding.UTF8;
return encoding.GetString(ms.ToArray());
}
}
}
}
In real life scenario when sending validation email we are simply encrypting our parametrized string the way shown bellow:
var urlParam = txtEmail.Text + ";" + userID + ";" + DateTime.Now.ToString();
var encryptedParam = Encryption.DES_encrypt(urlParam, "12345678");
//send confirmation email with link: https://www.myadress.com/validate.aspx?sid=encryptedParam
When someone clicks the link and comes to our page we need to decrypt values and read the data.
var encryptedParam = Request["sid"];
var decryptedParam = Encryption.DES_decrypt(encryptedParam, "12345678");
var email = decryptedParam.Split(';')[0];
var userID = decryptedParam.Split(';')[1];
var dateSent = DateTime.Parse(decryptedParam.Split(';')[2]);
As you probably have noticed, we use same public key to encrypt and decrypt values. In our situation the public key is safe because it is only stored on our server and is not being sent across the network.
For the above functions to be fully functional you need implement basic validation. It is also a good practice to add timestamp date to encrypted string so we can ensure the data was sent within defined time frame, lets say within last 5 minutes. After that the data will expire and wont be accepted by our application.
DES it’s quite save and efficient algorithm that you can use in your daily programming. It should be suitable in most case scenarios, unless you are building banking system 🙂