Kode untuk mendekode / menyandikan URL base64 yang dimodifikasi

113

Saya ingin menyandikan data base64 untuk memasukkannya ke dalam URL dan kemudian mendekodekannya dalam HttpHandler saya.

Saya telah menemukan bahwa Pengkodean Base64 memungkinkan karakter '/' yang akan mengacaukan pencocokan UriTemplate saya. Kemudian saya menemukan bahwa ada konsep "Base64 yang dimodifikasi untuk URL" dari wikipedia:

Ada Base64 yang dimodifikasi untuk varian URL, di mana tidak ada padding '=' yang akan digunakan, dan karakter '+' dan '/' dari Base64 standar masing-masing diganti dengan '-' dan '_', sehingga menggunakan encoders / decoder URL tidak lagi diperlukan dan tidak berdampak pada panjang nilai yang dikodekan, membiarkan bentuk enkode yang sama tetap utuh untuk digunakan dalam database relasional, formulir web, dan pengidentifikasi objek secara umum.

Menggunakan .NET Saya ingin mengubah kode saya saat ini dari melakukan pengkodean dan penguraian base64 dasar menjadi menggunakan metode "base64 yang dimodifikasi untuk URL". Apakah ada yang melakukan ini?

Untuk memecahkan kode, saya tahu itu dimulai dengan sesuatu seperti:

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

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

// My normal base64 decoding now uses encodedText

Tapi, saya perlu menambahkan satu atau dua karakter '=' ke bagian akhir yang terlihat sedikit lebih kompleks.

Logika pengkodean saya seharusnya sedikit lebih sederhana:

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

Saya telah melihat Panduan ke Base64 untuk entri URL StackOverflow, tetapi itu memiliki panjang yang diketahui dan oleh karena itu mereka dapat melakukan hardcode jumlah tanda yang sama yang dibutuhkan di bagian akhir.

Kirk Liemohn
sumber
@ Kirk: Sesuaikan jawaban saya dengan matematika yang diuji.
AnthonyWJones

Jawaban:

69

Ini harus menjelaskannya dengan benar: -

 base64 = base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');
AnthonyWJones
sumber
11
Bah, Anda mengalahkan saya. Saya hanya akan menghapus posting saya karena sepertinya saya menyalin Anda :)
AaronLS
3
Tidakkah ini akan menambahkan hingga tiga karakter '='? Tampaknya hanya akan ada 0, 1, atau 2 dari ini.
Kirk Liemohn
1
@Kirk: Jika menambahkan 3 karakter maka string base64 sudah rusak. Saya kira itu akan menjadi ide yang baik untuk memvalidasi string, itu seharusnya hanya berisi karakter yang diharapkan dan Panjang% 4! = 3.
AnthonyWJones
Hmmm. Dalam mencoba ini, itu tidak berhasil. Masih mencari jawaban. Jumlah tanda yang sama tidak terlihat dengan benar.
Kirk Liemohn
2
@AnthonyWJones 'seharusnya hanya berisi karakter yang diharapkan dan Panjang% 4! = 1 ', bukan?
blueling
173

Periksa juga kelas HttpServerUtility dengan metode UrlTokenEncode dan UrlTokenDecode yang menangani pengodean dan dekode Base64 URL yang aman.

Catatan 1: Hasilnya bukan string Base64 yang valid. Beberapa karakter yang tidak aman untuk URL diganti.

Catatan 2: Hasil berbeda dari algoritma base64url di 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
sumber
Terima kasih atas tipnya. Saya akan mencobanya lain kali!
Kirk Liemohn
12
Tip Anda adalah akhir yang gemilang untuk pencarian multi jam dan rambut jambul untuk jawabannya. terima kasih
Praesagus
Bukankah ini akan menggunakan% pengkodean untuk setiap / + dan =? Ini tidak seefisien jawaban lain
JoelFan
Tidak, itu menggantikan tanda yang sama yang digunakan untuk padding pada akhirnya dengan angka dan menggantikan plus dan slash dengan minus dan garis bawah.
Fredrik Haglund
15
Perhatikan bahwa UrlTokenEncodeini tidak hanya base64url , karena menggantikan '=' padding dengan '0', '1' atau '2' tergantung pada berapa banyak tanda yang sama yang diganti.
ladenedge
28

Tidak cukup poin untuk dikomentari, tetapi jika itu membantu, cuplikan kode yang ditemukan Sushil di tautan yang disediakan (draf ietf Tanda Tangan Web JSON) berfungsi saat mengenkode Base 64 sebagai parameter di URL.

Cuplikan yang disalin di bawah untuk mereka yang malas:

    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
sumber
ini kompatibel dengan Xamarin karena tidak menggunakan System.Web
Reza Mortazavi
Persis apa yang saya cari! Pilihan yang sangat bagus untuk Xamarin tanpa harus membuka perpustakaan.
Sleeping_Giant
19

Saya menekan di sini sambil mencari kode untuk melakukan encode / decode untuk pengkodean base64url yang sedikit berbeda dari base64 seperti yang dijelaskan dalam pertanyaan.

Ditemukan c # cuplikan kode dalam dokumen ini. Draf ietf Tanda Tangan Web JSON

Sushil
sumber
2
Ini adalah satu-satunya solusi yang berhasil bagi saya saat mengurai pesan di GMail API v1 (
Message.Raw
5

Dibandingkan dengan jawaban yang diterima, berikut adalah cara Anda mendekode url yang dikodekan base64, menggunakan C #:

Membaca sandi:

string codedValue = "base64encodedUrlHere";

string decoded;
byte[] buffer =  Convert.FromBase64String(codedValue);
decoded = Encoding.UTF8.GetString(buffer);
Chris Halcrow
sumber
mungkin jika Anda memberikan detail lebih lanjut dan perbandingan dengan jawaban yang diterima, Anda mungkin mendapatkan suara positif - terima kasih
Mauricio Gracia Gutierrez