Twitter Updates

    follow me on Twitter

    Thursday, November 01, 2007

    Tamper Proof Query String (written in C#)

    Original CP article - http://www.codeproject.com/aspnet/TamperProofQueryString.asp

    This is the few changes that I did to the Helper function to have this working

    static public string encode(string value)
    {
    return System.Web.HttpUtility.UrlEncode(TamperProofStringEncode(value, System.Configuration.ConfigurationManager.AppSettings["TamperProofKey"]).Replace('+', '@'));
    }

    static public string decode(string value)
    {
    return TamperProofStringDecode(System.Web.HttpUtility.UrlDecode(value).Replace('@', '+'), System.Configuration.ConfigurationManager.AppSettings["TamperProofKey"]);
    }


    The URLDecode() problem


    The URLDecode() method of System.Web.HttpUtility does not behave in an intuitive fashion when called repeatedly. For example: calling UrlEncode() with the string "abc+=" results in "abc%2b%3d". The first call to URLDecode() with "abc%2b%3d" correctly results in "abc+=". Calling UrlDecode() again with "abc+=" results in "abc =" - the '+' was replaced with a space. Why is this a problem at all? This is a problem because some .NET Framework methods silently call URLDecode(). My testing shows that the results from Response.QueryString[] is URL-decoded even though nothing is mentioned in the documentation. To avoid this problem, I recommend replacing all the '+' characters with '@' in the Base64 output string. The '@' character is URL safe and does not change when multiple calls are made to UrlDecode().


    using System;

    namespace Common.SharedClass
    {
    public class TamperProofQueryString
    {
    #region TamperProofStringEncode
    static public string TamperProofStringEncode(string value, string key)
    {
    System.Security.Cryptography.MACTripleDES mac3des = new System.Security.Cryptography.MACTripleDES();
    System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
    mac3des.Key = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(key));
    return System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(value)) + System.Convert.ToChar("-") + System.Convert.ToBase64String(mac3des.ComputeHash(System.Text.Encoding.UTF8.GetBytes(value)));
    }
    #endregion

    #region TamperProofStringDecode
    //Function to decode the string
    //Throws an exception if the data is corrupt
    static public string TamperProofStringDecode(string value, string key)
    {
    String dataValue = string.Empty;
    String calcHash = string.Empty;
    String storedHash = string.Empty;

    System.Security.Cryptography.MACTripleDES mac3des = new System.Security.Cryptography.MACTripleDES();
    System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
    mac3des.Key = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(key));

    try
    {
    dataValue = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(value.Split(System.Convert.ToChar("-"))[0]));
    storedHash = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(value.Split(System.Convert.ToChar("-"))[1]));
    calcHash = System.Text.Encoding.UTF8.GetString(mac3des.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dataValue)));

    if (storedHash != calcHash)
    {
    //Data was corrupted
    throw new ArgumentException("Hash value does not match");
    //This error is immediately caught below
    }

    }
    catch (System.Exception)
    {
    throw new ArgumentException("Invalid TamperProofString");
    }
    return dataValue;
    }
    #endregion

    #region encode
    static public string encode(string value)
    {
    return System.Web.HttpUtility.UrlEncode(TamperProofStringEncode(value, System.Configuration.ConfigurationManager.AppSettings["TamperProofKey"]).Replace('+', '@'));
    }
    #endregion

    #region decode
    static public string decode(string value)
    {
    return TamperProofStringDecode(System.Web.HttpUtility.UrlDecode(value).Replace('@', '+'), System.Configuration.ConfigurationManager.AppSettings["TamperProofKey"]);
    }
    #endregion
    }
    }