Codice per decodificare / codificare un URL base64 modificato


113

Voglio codificare i dati in base64 per inserirli in un URL e quindi decodificarli nel mio HttpHandler.

Ho scoperto che la codifica Base64 consente un carattere "/" che rovinerà la mia corrispondenza UriTemplate. Poi ho scoperto che esiste un concetto di "Base64 modificato per URL" da wikipedia:

Esiste un Base64 modificato per la variante URL, in cui non verrà utilizzato alcun riempimento "=" e i caratteri "+" e "/" di Base64 standard sono rispettivamente sostituiti da "-" e "_", in modo che l'utilizzo di codificatori / decodificatori URL non è più necessario e non ha alcun impatto sulla lunghezza del valore codificato, lasciando intatta la stessa forma codificata per l'uso in database relazionali, moduli web e identificatori di oggetti in generale.

Utilizzando .NET desidero modificare il mio codice corrente passando dalla codifica e decodifica base64 di base all'utilizzo del metodo "base64 modificato per URL". Qualcuno l'ha fatto?

Per decodificare, so che inizia con qualcosa del tipo:

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

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

// My normal base64 decoding now uses encodedText

Ma, ho bisogno di aggiungere potenzialmente uno o due caratteri "=" alla fine che sembra un po 'più complessa.

La mia logica di codifica dovrebbe essere un po 'più semplice:

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

Ho visto il Guid a Base64 per la voce StackOverflow URL , ma ha una lunghezza nota e quindi possono codificare il numero di segni di uguale necessari alla fine.


@ Kirk: modifica la mia risposta con una matematica testata.
AnthonyWJones

Risposte:


69

Questo dovrebbe riempirlo correttamente: -

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

11
Bah, mi hai battuto. Eliminerò il mio post perché sembra quasi di averti copiato :)
AaronLS

3
Non verranno aggiunti fino a tre caratteri "="? Sembra che ci saranno solo 0, 1 o 2 di questi.
Kirk Liemohn

1
@ Kirk: se aggiunge 3 caratteri, la stringa base64 è già danneggiata. Immagino che sarebbe una buona idea convalidare la stringa, dovrebbe contenere solo i caratteri previsti e la lunghezza% 4! = 3.
AnthonyWJones

Hmmm. Nel provare questo, non sta facendo il trucco. Sto ancora cercando risposte. Il numero di segni di uguale non funziona correttamente.
Kirk Liemohn

2
@AnthonyWJones "dovrebbe contenere solo i caratteri previsti e la lunghezza% 4! = 1 ", giusto?
blueling

173

Controlla anche la classe HttpServerUtility con i metodi UrlTokenEncode e UrlTokenDecode che gestiscono la codifica e la decodifica Base64 sicura per gli URL.

Nota 1: il risultato non è una stringa Base64 valida. Alcuni caratteri non sicuri per l'URL vengono sostituiti.

Nota 2: il risultato è diverso dall'algoritmo base64url 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);
}

Grazie per il consiglio. Lo proverò la prossima volta!
Kirk Liemohn,

12
Il tuo consiglio è stato la gloriosa fine di una ricerca di più ore e ciuffi di capelli per la risposta. grazie
Praesagus

Non userà la codifica% per ogni / + e =? Questo non è efficiente come l'altra risposta
JoelFan

No, sostituisce i segni di uguale usati per il riempimento alla fine con un numero e sostituisce il più e la barra con meno e trattino basso.
Fredrik Haglund,

15
Nota che UrlTokenEncodenon è strettamente base64url , poiché sostituisce il riempimento "=" con "0", "1" o "2" a seconda di quanti segni di uguale ha sostituito.
Ladenedge

28

Non ci sono abbastanza punti per commentare, ma nel caso in cui aiuti, lo snippet di codice che Sushil ha trovato nel collegamento fornito (JSON Web Signature ietf bozza) funziona per la codifica di Base 64 come parametro nell'URL.

Snippet copiato di seguito per coloro che sono pigri:

    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
    }

questo è compatibile con Xamarin per non usare System.Web
Reza Mortazavi

Esattamente quello che stavo cercando! Ottima opzione per Xamarin senza dover inserire una libreria.
Sleeping_Giant

19

Ho premuto qui mentre cercavo il codice per codificare / decodificare per la codifica base64url che è leggermente diversa da base64 come spiegato nella domanda.

Trovato frammento di codice c # in questo documento. Bozza ietf di firma web JSON


2
Questa era l'unica soluzione che funzionava per me durante l'analisi di un messaggio nell'API GMail v1 (Message.Raw)
HeyZiko

5

In confronto alla risposta accettata, ecco come decodificheresti fondamentalmente un URL con codifica base64, usando C #:

Decodificare:

string codedValue = "base64encodedUrlHere";

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

forse se fornisci maggiori dettagli e confronti con la risposta accettata potresti ottenere un voto positivo - grazie
Mauricio Gracia Gutierrez
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.