Search code examples
c#asp.net-mvcencryptionurl-encoding

Encrypted string has a slash (/) in the result, which causes problems in a URL


I hunted around online to find a simple little encryption method that would take a string, encrypt it, and then decrypt it. The idea being that I have ID's I need in a URL that can't be in plan text.

The class I found workes great most of the time, but sometimes, I end up with an encrypted string that has a / in it:

OSprnGR/0os4DQpQsa0gIg==

As you can imagine, that causes problems when used in a URL. So I thought that if I just UrlEncode the string, that it would solve the problem.

It didn't.

I still get the same error even when the URL looks like this:

http://localhost:54471/BrokerDashboard/BuyingLeads/LeadView/OSprnGR%2f0os4DQpQsa0gIg%3d%3d

Instead of this:

http://localhost:54471/BrokerDashboard/BuyingLeads/LeadView/OSprnGR/0os4DQpQsa0gIg==

HTTP Error 404.0 - Not Found The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

Here's the class I'm using:

public static class Encryption
{
    public static string keyString { get { return "6C3A231C-57B2-4BA0-AFD6-306098234B11"; } }
    private static byte[] salt = Encoding.ASCII.GetBytes("somerandomstuff");

    public static string Encrypt(string plainText)
    {
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(keyString, salt);
        MemoryStream ms = new MemoryStream();
        StreamWriter sw = new StreamWriter(new CryptoStream(ms, new RijndaelManaged().CreateEncryptor(key.GetBytes(32), key.GetBytes(16)), CryptoStreamMode.Write));
        sw.Write(plainText);
        sw.Close();
        ms.Close();
        string beforeUrlEncoded = Convert.ToBase64String(ms.ToArray());
        string afterUrlEndcoded = HttpUtility.UrlEncode(beforeUrlEncoded);
        return afterUrlEndcoded;
    }

    public static string Decrypt(string encrypted)
    {
        //string urlDecoded = HttpUtility.UrlDecode(encrypted); // <--- Turns out you don't need this
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(keyString, salt);
        ICryptoTransform d = new RijndaelManaged().CreateDecryptor(key.GetBytes(32), key.GetBytes(16));
        byte[] bytes = Convert.FromBase64String(encrypted);
        return new StreamReader(new CryptoStream(new MemoryStream(bytes), d, CryptoStreamMode.Read)).ReadToEnd();
    }
}

EDIT:

Here's the route:

routes.MapRoute(
    name: "BrokerLead",
    url: "BrokerDashboard/BuyingLeads/LeadView/{id}"
);

Solution

  • The / character is reserved and cannot be used in the path portion. If this is the last segment of your url you could use the following routing to make it work (notice the {*id} segment):

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{*id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
    

    Another approach consists in replacing this character with some other when encrypting/decrypting but in general you should avoid special characters in the path portion of the url and simply put them as a query string where you can properly url encode everything.