124

I want to base64 encode data to put it in a URL and then decode it within my HttpHandler.

I have found that Base64 Encoding allows for a '/' character which will mess up my UriTemplate matching. Then I found that there is a concept of a "modified Base64 for URL" from wikipedia:

A modified Base64 for URL variant exists, where no padding '=' will be used, and the '+' and '/' characters of standard Base64 are respectively replaced by '-' and '_', so that using URL encoders/decoders is no longer necessary and has no impact on the length of the encoded value, leaving the same encoded form intact for use in relational databases, web forms, and object identifiers in general.

Using .NET I want to modify my current code from doing basic base64 encoding and decoding to using the "modified base64 for URL" method. Has anyone done this?

To decode, I know it starts out with something like:

string base64EncodedText = base64UrlEncodedText.Replace('-', '+').Replace('_', '/');

// Append '=' char(s) if necessary - how best to do this?

// My normal base64 decoding now uses encodedText

But, I need to potentially add one or two '=' chars to the end which looks a little more complex.

My encoding logic should be a little simpler:

// Perform normal base64 encoding
byte[] encodedBytes = Encoding.UTF8.GetBytes(unencodedText);
string base64EncodedText = Convert.ToBase64String(encodedBytes);

// Apply URL variant
string base64UrlEncodedText = base64EncodedText.Replace("=", String.Empty).Replace('+', '-').Replace('/', '_');

I have seen the Guid to Base64 for URL StackOverflow entry, but that has a known length and therefore they can hardcode the number of equal signs needed at the end.

0

5 Answers 5

181

Also check class HttpServerUtility with UrlTokenEncode and UrlTokenDecode methods that is handling URL safe Base64 encoding and decoding.

Note 1: The result is not a valid Base64 string. Some unsafe characters for URL are replaced.

Note 2: The result differs from the base64url algorithm in RFC4648, it replaces the '=' padding with '0', '1' or '2' depending on how many equal signs it replaced to make the value safe for a query parameter.

///<summary>
/// Base 64 Encoding with URL and Filename Safe Alphabet using UTF-8 character set.
///</summary>
///<param name="str">The origianl string</param>
///<returns>The Base64 encoded string</returns>
public static string Base64ForUrlEncode(string str)
{
    byte[] encbuff = Encoding.UTF8.GetBytes(str);
    return HttpServerUtility.UrlTokenEncode(encbuff);
}
///<summary>
/// Decode Base64 encoded string with URL and Filename Safe Alphabet using UTF-8.
///</summary>
///<param name="str">Base64 code</param>
///<returns>The decoded string.</returns>
public static string Base64ForUrlDecode(string str)
{
    byte[] decbuff = HttpServerUtility.UrlTokenDecode(str);
    return Encoding.UTF8.GetString(decbuff);
}
Sign up to request clarification or add additional context in comments.

3 Comments

Won't this use % encoding for every / + and = ? This is not as efficient as the other answer
No, it replaces equal signs used for padding in the end with a number and substitutes plus and slash with minus and underscore.
Note that UrlTokenEncode is not strictly base64url, as it replaces the '=' padding with '0', '1' or '2' depending on how many equal signs it replaced.
86

This ought to pad it out correctly:-

 base64 = base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');

10 Comments

Won't this add up to three '=' chars? It appears that there will only be 0, 1, or 2 of these.
@Kirk: If it adds 3 characters then the base64 string is already corrupt. I guess it would be a good idea to validate the string, it should only contain the characters expected and Length % 4 != 3.
Hmmm. In trying this out, it isn't doing the trick. Still looking for answers. The number of equal signs just isn't panning out properly.
Oops needed to invert the modulo.
@AnthonyWJones 'it should only contain the characters expected and Length % 4 != 1', right?
|
41

Not enough points to comment, but in case it helps, the code snippet that Sushil found in the link provided RFC 7515 JSON Web Signature works for when encoding Base 64 as a parameter in URL.

Copied snippet below for those that are lazy:

    static string Base64UrlEncode(byte[] arg)
    {
        string s = Convert.ToBase64String(arg); // Regular base64 encoder
        s = s.Split('=')[0]; // Remove any trailing '='s
        s = s.Replace('+', '-'); // 62nd char of encoding
        s = s.Replace('/', '_'); // 63rd char of encoding
        return s;
    }

    static byte[] Base64UrlDecode(string arg)
    {
        string s = arg;
        s = s.Replace('-', '+'); // 62nd char of encoding
        s = s.Replace('_', '/'); // 63rd char of encoding
        switch (s.Length % 4) // Pad with trailing '='s
        {
            case 0: break; // No pad chars in this case
            case 2: s += "=="; break; // Two pad chars
            case 3: s += "="; break; // One pad char
            default: throw new System.Exception(
              "Illegal base64url string!");
        }
        return Convert.FromBase64String(s); // Standard base64 decoder
    }

2 Comments

this is compatible with Xamarin for not using System.Web
Exactly what I was looking for! Really good option for Xamarin without having to pull in a library.
21

I hit here while looking for code to do encode/decode for base64url encoding which is little different than base64 as explained in the question.

Found c# code snippet in this document. JSON Web Signature ietf draft

1 Comment

This was the only solution that worked for me when parsing a message in the GMail API v1 (Message.Raw)
5

In comparison to the accepted answer, here is how you would fundamentally decode a base64 encoded url, using C#:

Decode:

string codedValue = "base64encodedUrlHere";

string decoded;
byte[] buffer =  Convert.FromBase64String(codedValue);
decoded = Encoding.UTF8.GetString(buffer);

2 Comments

maybe if you provide more details and comparison to the accepted answer you might get an upvote - thanks
It's not a base64-encoded URL, but base64url-encoded data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.