Casey Crookston
Casey Crookston

Reputation: 13945

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}"
);

Upvotes: 3

Views: 4447

Answers (2)

Roman
Roman

Reputation: 12171

Maybe it is not the best way to solve the problem but it should work.

After this line:

string beforeUrlEncoded = Convert.ToBase64String(ms.ToArray());

You can replace slashes(/) by some other symbols (several symbols):

string replacement = "ItIsSlashReplacement";
beforeUrlEncoded = beforeUrlEncoded.Replace("/", replacement);

Now you will get string without redundant /. I.e, you have encoded string "abc/dce". After replacement you will have "abcItIsSlashReplacementdce" - without /.

Then when you need to decode string you should reverse your replacement:

string replacement = "ItIsSlashReplacement";
string originalEncodedString = stringWithReplacement.Replace(replacement, "/");

You get "abcItIsSlashReplacementdce", restore original - "abc/dce" and then decode it.

NOTE: You can choose as replacement some string and encode it to base64. But string should be chosen by the way so after decoding it shouldn't contain /.

Upvotes: 2

Darin Dimitrov
Darin Dimitrov

Reputation: 1038770

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.

Upvotes: 6

Related Questions