2

I'm trying to find a way to place a number in a URL and/or cookie and currently the only method I have is using regular hex encoding (00-01-...-FF). I was going to use Base64 but discovered that it's not safe in URLs or cookies.

What is an encoding similar to base64 I can use that is URL and cookie safe? (using only 0-9,a-z,A-Z) Also, bonus points for their being an encoder/decoder for the encoding in the .Net library :)

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • Is the "number" always an integer? – Samuel Edwin Ward Nov 16 '11 at 19:02
  • 1
    Does the client need to decode the number as well or is this just along for the ride? You could always [UrlEncode](http://msdn.microsoft.com/en-us/library/system.web.httputility.urlencode.aspx) the resulting Base64'd string. (I've used that method when passing encrypted data around) – Joshua Nov 16 '11 at 20:35
  • @Josh I just preferred not to waste space(and make things ugly) by URL encoding it. and Sam no, it is a varying amount of bytes – Earlz Nov 16 '11 at 20:50

2 Answers2

1

Why not use Base64, but convert the + and / characters to - and _, respectively? See http://en.wikipedia.org/wiki/Base64#Variants_summary_table for a description.

This is pretty commonly used, perhaps most famously by YouTube for their video ids.

This code turns a 64-bit value into a base64 encoded key, using that conversion:

    public static string Base64EncodeKey(ulong key)
    {
        // get bytes
        byte[] keyBytes = BitConverter.GetBytes(key);

        // get base64 value
        string keyString = Convert.ToBase64String(keyBytes);

        // The base64 encoding has a trailing = sign, and + and - characters.

        // Strip the trailing =.
        keyString = keyString.Substring(0, keyString.Length - 1);

        // convert + to - (dash) and / to _ (underscore)
        keyString = keyString.Replace('+', '-');
        keyString = keyString.Replace('/', '_');

        return keyString;
    }

The reverse turns the encoded key back to a ulong:

    public static ulong Base64DecodeKey(string keyString)
    {
        // convert - to +, and _ to /
        keyString = keyString.Replace('-', '+');
        keyString = keyString.Replace('_', '/');

        // add the trailing =
        keyString += '=';

        // convert to bytes
        byte[] keyBytes = Convert.FromBase64String(keyString);

        // get the encoded key
        ulong encodedKey = BitConverter.ToUInt64(keyBytes, 0);
        return encodedKey;
    }

You can do something similar with 32-bit keys.

Update:

I see that you said there's a varying number of bytes. If you know that the value is always 32 bits or less (or 64 bits or less), you're probably better off using the technique I described above. If you really need to encode a varying length string, you can still use the modified base64 encoding scheme that replaces + and / with - and _. See RFC 4648 for other recommendations.

Community
  • 1
  • 1
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • isn't the padding there for a reason? Like this: http://stackoverflow.com/questions/1228701/code-for-decoding-encoding-a-modified-base64-url – Earlz Nov 16 '11 at 23:08
  • @Earlz: Whereas the padding is important in the general case, there's no reason for it if you know how long your data is. Base64 encoding a 32-bit value will always require a padding character. Since you know that the padding character will always be required, there's no reason not to remove it, as long as you're careful to add it back before decoding. – Jim Mischel Nov 17 '11 at 00:19
0

For an easy way to do this, use HttpServerUtility.UrlTokenEncode() and UrlTokenDecode().

byte[] plainTextBytes = Encoding.UTF8.GetBytes(originalString);
string encodedString = HttpServerUtility.UrlTokenEncode(plainTextBytes);


byte[] decodedBytes = HttpServerUtility.UrlTokenDecode(encodedString);
string originalStringCopy = Encoding.UTF8.GetString(decodedBytes);

Thanks to Fredrik Haglund for his answer here: https://stackoverflow.com/a/1789179/24315

Community
  • 1
  • 1
Neil
  • 7,227
  • 5
  • 42
  • 43