Code zum Decodieren / Codieren einer modifizierten base64-URL

113

Ich möchte base64-Daten codieren, um sie in eine URL einzufügen, und sie dann in meinem HttpHandler dekodieren.

Ich habe festgestellt, dass die Base64-Codierung ein '/' Zeichen zulässt, das meinen UriTemplate-Abgleich durcheinander bringt. Dann fand ich heraus, dass es ein Konzept einer "modifizierten Base64 für URL" von Wikipedia gibt:

Es gibt eine modifizierte Base64 für URL-Variante, bei der kein Auffüllen '=' verwendet wird und die Zeichen '+' und '/' von Standard Base64 jeweils durch '-' und '_' ersetzt werden, sodass URL-Encoder / -Decoder verwendet werden ist nicht mehr erforderlich und hat keinen Einfluss auf die Länge des codierten Werts, sodass dasselbe codierte Formular für die Verwendung in relationalen Datenbanken, Webformularen und Objektkennungen im Allgemeinen intakt bleibt.

Verwenden von .NET Ich möchte meinen aktuellen Code von der grundlegenden Base64-Codierung und -Decodierung zur Verwendung der Methode "Modified Base64 for URL" ändern. Hat jemand das getan?

Zum Entschlüsseln weiß ich, dass es mit etwas beginnt wie:

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

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

// My normal base64 decoding now uses encodedText

Aber ich muss möglicherweise ein oder zwei '=' Zeichen am Ende hinzufügen, was etwas komplexer aussieht.

Meine Codierungslogik sollte etwas einfacher sein:

// 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('/', '_');

Ich habe die Guid to Base64 für den URL StackOverflow-Eintrag gesehen, aber diese hat eine bekannte Länge und daher können sie die Anzahl der am Ende benötigten Gleichheitszeichen fest codieren.

Kirk Liemohn
quelle
@ Kirk: Passen Sie meine Antwort mit getesteter Mathematik an.
AnthonyWJones

Antworten:

69

Dies sollte es richtig ausfüllen: -

 base64 = base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');
AnthonyWJones
quelle
11
Bah, du hast mich geschlagen. Ich werde nur meinen Beitrag löschen, weil es fast so aussieht, als hätte ich dich kopiert :)
AaronLS
3
Addiert das nicht drei '=' Zeichen? Es scheint, dass es nur 0, 1 oder 2 davon geben wird.
Kirk Liemohn
1
@Kirk: Wenn 3 Zeichen hinzugefügt werden, ist die base64-Zeichenfolge bereits beschädigt. Ich denke, es wäre eine gute Idee, die Zeichenfolge zu validieren. Sie sollte nur die erwarteten Zeichen und die Länge% 4 enthalten! = 3.
AnthonyWJones
Hmmm. Beim Ausprobieren reicht es nicht aus. Immer noch auf der Suche nach Antworten. Die Anzahl der Gleichheitszeichen ist einfach nicht richtig.
Kirk Liemohn
2
@AnthonyWJones 'es sollte nur die erwarteten Zeichen und die Länge% 4! = 1 ' enthalten, oder?
Blueling
173

Überprüfen Sie auch die Klasse HttpServerUtility mit den Methoden UrlTokenEncode und UrlTokenDecode, die die URL-sichere Base64-Codierung und -Decodierung verarbeiten.

Hinweis 1: Das Ergebnis ist keine gültige Base64-Zeichenfolge. Einige unsichere Zeichen für die URL werden ersetzt.

Hinweis 2: Das Ergebnis unterscheidet sich vom base64url-Algorithmus in RFC4648.

///<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);
}
Fredrik Haglund
quelle
Danke für den Tipp. Ich werde das nächste Mal versuchen!
Kirk Liemohn
12
Ihr Tipp war das glorreiche Ende einer mehrstündigen Suche nach der Antwort. danke
Praesagus
Wird dies nicht die% -Codierung für jedes / + und = verwenden? Dies ist nicht so effizient wie die andere Antwort
JoelFan
Nein, es ersetzt Gleichheitszeichen, die am Ende zum Auffüllen verwendet werden, durch eine Zahl und ersetzt Plus und Schrägstrich durch Minus und Unterstrich.
Fredrik Haglund
15
Beachten Sie, dass dies UrlTokenEncodenicht ausschließlich base64url ist , da es die Auffüllung '=' durch '0', '1' oder '2' ersetzt, je nachdem, wie viele Gleichheitszeichen es ersetzt hat.
Beladung
28

Nicht genug Punkte zum Kommentieren, aber falls es hilft, funktioniert das Code-Snippet, das Sushil in dem bereitgestellten Link gefunden hat (JSON Web Signature ietf-Entwurf), für die Codierung von Base 64 als Parameter in der URL.

Kopierter Ausschnitt unten für diejenigen, die faul sind:

    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
    }
Stefan Zvonar
quelle
Dies ist kompatibel mit Xamarin, da System.Web
Reza Mortazavi
Genau das, wonach ich gesucht habe! Wirklich gute Option für Xamarin, ohne eine Bibliothek aufrufen zu müssen.
Sleeping_Giant
19

Ich habe hier auf der Suche nach Code zum Codieren / Decodieren für die base64url-Codierung getroffen, der sich kaum von der in der Frage erläuterten base64 unterscheidet.

C # -Code-Snippet in diesem Dokument gefunden. JSON Web Signature ietf Entwurf

Sushil
quelle
2
Dies war die einzige Lösung, die für mich beim Parsen einer Nachricht in der GMail API v1 (Message.Raw)
funktioniert hat
5

Im Vergleich zur akzeptierten Antwort würden Sie eine base64-codierte URL mit C # grundlegend dekodieren :

Dekodieren:

string codedValue = "base64encodedUrlHere";

string decoded;
byte[] buffer =  Convert.FromBase64String(codedValue);
decoded = Encoding.UTF8.GetString(buffer);
Chris Halcrow
quelle
Wenn Sie mehr Details und einen Vergleich mit der akzeptierten Antwort angeben, erhalten Sie möglicherweise eine positive Bewertung - danke
Mauricio Gracia Gutierrez