Code for decoding/encoding a modified base64 URL (in ASP.NET Framework)

99,531

Solution 1

This ought to pad it out correctly:-

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

Solution 2

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

Solution 3

Not enough points to comment, but in case it helps, the code snippet that Sushil found in the link provided (JSON Web Signature ietf draft) 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
    }

Solution 4

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

Solution 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);
Share:
99,531
Kirk Liemohn
Author by

Kirk Liemohn

I focus on SharePoint, Office 365, and Azure development and integration. I have a history of integrating products with SharePoint. My focus lately has been around Office 365 and Azure.

Updated on February 19, 2022

Comments

  • Kirk Liemohn
    Kirk Liemohn about 2 years

    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.

  • AaronLS
    AaronLS over 14 years
    Bah, you beat me. I'll just delete my post cause it looks almost like I copied you :)
  • Kirk Liemohn
    Kirk Liemohn over 14 years
    Won't this add up to three '=' chars? It appears that there will only be 0, 1, or 2 of these.
  • AnthonyWJones
    AnthonyWJones over 14 years
    @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.
  • Kirk Liemohn
    Kirk Liemohn over 14 years
    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.
  • AnthonyWJones
    AnthonyWJones over 14 years
    Oops needed to invert the modulo.
  • Praesagus
    Praesagus about 14 years
    Your tip was the glorious end to an multi hour and hair tuft search for the answer. thanks
  • Evan Nagle
    Evan Nagle almost 13 years
    in this example, what is base64? If it's a System.String, then I'm not sure how this would work, because what you end up with depends on the encoding used to get the bytes. In this particular example, you might get away with it because he's using UTF8, but with Unicode this won't work.
  • AnthonyWJones
    AnthonyWJones almost 13 years
    @Ben: Yes the variable base64 in this example is of type string. I think you may be a little confused though, at what point is Unicode a problem? Bear in mind the sample code above is purely to include the appropriate padding of "=" to the end of the string to ensure it can be decoded correctly.
  • Evan Nagle
    Evan Nagle almost 13 years
    @AnthonyWJones: Unicode (or any multi-byte encoding) is a problem because you would be padding the wrong number of bytes. You can tell this by inspection, but I discovered it after trying your solution. I could not make the above work when I was using Encoding.Unicode to get the bytes. To solve the problem in an encoding-agnostic way, you have to pad the array of bytes you feed to Convert.ToBase64String, rather than the original string.
  • AnthonyWJones
    AnthonyWJones almost 13 years
    @Ben: My padding code occurs after a) the original string has been converted to bytes and b) after those bytes have been converted to a form of Base64. This is indicated by the input variable being called "base64" and the nature of the question. In reality this question boils down to "How do I pad a string with a specific character to make its character length a multiple of a specified integer". It just so happens that the context is using "=" to pad a base64-esq string to multiples of 4.
  • Evan Nagle
    Evan Nagle almost 13 years
    @AnthonyWJones Ok, thanks for the clarification. It wasn't clear to me until now that you were padding an already-encoded string. The problem I was working on was the one of padding a string before encoding so as to avoid having '=' characters in the encoded result.
  • user1601201
    user1601201 almost 12 years
    Won't this use % encoding for every / + and = ? This is not as efficient as the other answer
  • Fredrik Haglund
    Fredrik Haglund almost 12 years
    No, it replaces equal signs used for padding in the end with a number and substitutes plus and slash with minus and underscore.
  • ladenedge
    ladenedge over 11 years
    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.
  • blueling
    blueling over 10 years
    @AnthonyWJones 'it should only contain the characters expected and Length % 4 != 1', right?
  • HeyZiko
    HeyZiko about 9 years
    This was the only solution that worked for me when parsing a message in the GMail API v1 (Message.Raw)
  • Mauricio Gracia Gutierrez
    Mauricio Gracia Gutierrez over 8 years
    maybe if you provide more details and comparison to the accepted answer you might get an upvote - thanks
  • Reza Mortazavi
    Reza Mortazavi over 6 years
    this is compatible with Xamarin for not using System.Web
  • Sleeping_Giant
    Sleeping_Giant over 5 years
    Exactly what I was looking for! Really good option for Xamarin without having to pull in a library.
  • TimTIM Wong
    TimTIM Wong about 3 years
    It's not a base64-encoded URL, but base64url-encoded data.