Bagaimana cara mencapai pengkodean aman URL Base64 di C #?

105

Saya ingin mencapai pengkodean aman URL Base64 di C #. Di Jawa, kami memiliki kesamaanCodec perpustakaan yang memberi saya string yang dikodekan URL yang aman. Bagaimana saya bisa mencapai hal yang sama menggunakan C #?

byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes("StringToEncode");
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);

Kode di atas mengubahnya menjadi Base64, tetapi itu pad ==. Apakah ada cara untuk mencapai pengkodean aman URL?

Vishvesh Phadnis
sumber
Tidak bisakah kamu menggunakan Url.Encodestring in BASE64?
Di namespace mana kelas Url ada di c #?
Vishvesh Phadnis
Coba lihat: msdn.microsoft.com/en-us/library/… Anda perlu referensi System.Webperakitan.
Ini mengubah = menjadi% 3D. Saya tidak menginginkan itu.
Vishvesh Phadnis
3
Jadi apa yang kamu maksud dengan url safe? %3Dapakah url aman.

Jawaban:

182

Biasanya hanya menukar alfabet untuk digunakan di url, jadi tidak perlu% -encoding; hanya 3 dari 65 karakter yang bermasalah - +, /dan =. penggantian yang paling umum adalah -di tempat +dan _di tempat /. Adapun padding: hapus saja (the =); Anda dapat menyimpulkan jumlah padding yang dibutuhkan. Di ujung lain: balikkan saja prosesnya:

string returnValue = System.Convert.ToBase64String(toEncodeAsBytes)
        .TrimEnd(padding).Replace('+', '-').Replace('/', '_');

dengan:

static readonly char[] padding = { '=' };

dan untuk membalikkan:

string incoming = returnValue
    .Replace('_', '/').Replace('-', '+');
switch(returnValue.Length % 4) {
    case 2: incoming += "=="; break;
    case 3: incoming += "="; break;
}
byte[] bytes = Convert.FromBase64String(incoming);
string originalText = Encoding.ASCII.GetString(bytes);

Pertanyaan yang menarik, bagaimanapun, adalah: apakah ini pendekatan yang sama yang digunakan "pustaka codec umum"? Ini tentu akan menjadi hal pertama yang masuk akal untuk diuji - ini adalah pendekatan yang cukup umum.

Marc Gravell
sumber
1
Dalam Codec Umum mereka menggunakan Karakter [0-9a-zA-Z_-] untuk mode aman url.
Vishvesh Phadnis
ini juga disebutkan di halaman wiki untuk Base64 di bawah aplikasi URL. en.wikipedia.org/wiki/Base64
wonster
2
Anda juga memiliki fungsi ' stackoverflow.com/questions/1886686/… ' yang melakukan semua kerja keras untuk Anda.
toy4fun
1
Mengapa kita tidak membutuhkan: case 1: incoming + = "==="; istirahat; ?
alex da franca
5
@alexdafranca karena tidak akan pernah memiliki mod panjang 4 dari 1. 3x8 bit menjadi 4x6 bit (dan masing-masing 6 bit adalah salah satu dari 64 karakter dalam alfabet yang dipilih), 0x8 bit dikodekan sebagai 0x6 bit tanpa padding, 1x8 bit dikodekan sebagai 2x6 bit dengan ==padding, 2x8 dikodekan sebagai 3x6 dengan =padding, 3x8 dikodekan sebagai 4x6 tanpa padding lalu disejajarkan sehingga berulang. Tidak ada yang pernah dikodekan menjadi 1x6 bit, jadi Anda tidak perlu ===padding.
George Helyar
83

Anda dapat menggunakan kelas Base64UrlEncoderdari namespace Microsoft.IdentityModel.Tokens.

const string StringToEncode = "He=llo+Wo/rld";

var encodedStr = Base64UrlEncoder.Encode(StringToEncode);
var decodedStr = Base64UrlEncoder.Decode(encodedStr);

if (decodedStr == StringToEncode)
    Console.WriteLine("It works!");
else
    Console.WriteLine("Dangit!");
Jerome
sumber
1
Ini jauh lebih bersih daripada jawaban yang diterima. Ada kerugian?
taktak004
18
Sekadar catatan: Microsoft.IdentityModel.Tokens adalah paket NuGet yang harus diunduh.
Uber Schnoz
Saya berasumsi dengan namanya bahwa ini bukan lintas platform. Apakah itu masalahnya?
Brandon S.
8

Berdasarkan jawaban di sini dengan beberapa peningkatan kinerja, kami telah menerbitkan implementasi base64 aman-url yang sangat mudah digunakan ke NuGet dengan kode sumber yang tersedia di GitHub (berlisensi MIT).

Penggunaannya semudah

var bytes = Encoding.UTF8.GetBytes("Foo");
var encoded = UrlBase64.Encode(bytes);
var decoded = UrlBase64.Decode(encoded);
Mahmoud Al-Qudsi
sumber
Luar biasa terima kasih. Dari bunga mengapa Anda memilih untuk "string".Replaceuntuk encodemetode, tetapi loop dengan Menggantikan panduan untuk decode?
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
@ ᴍᴀᴛᴛʙᴀᴋᴇʀ Saya perlu mengunjunginya kembali dan menjalankan beberapa tolok ukur, tetapi itu karena kita menambahkan yang terakhir sehingga itu diwakili oleh daftar karakter yang dapat bertambah alih-alih string yang tidak dapat diubah.
Mahmoud Al-Qudsi
Kelas lain dengan mengembalikan type = string sebagai gantinya: github.com/vndevpro/architecture-common/blob/master/…
hazjack
8

Untuk mendapatkan pengkodean seperti base64 yang aman untuk URL, tetapi bukan "base64url" menurut RFC4648, gunakan System.Web.HttpServerUtility.UrlTokenEncode(bytes)untuk mengenkode, dan System.Web.HttpServerUtility.UrlTokenDecode(bytes)untuk mendekode.

Karanvir Kang
sumber
6
Ini tidak memberikan standar yang sesuai dengan pengkodean Base64 aman URL menurut RFC4648. Lihat juga Tanya Jawab ini . Gunakan dengan hati-hati.
Artjom B.
1

Solusi paling sederhana: (tanpa bantalan)

private static string Base64UrlEncode(string input) {
    var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
    // Special "url-safe" base64 encode.
    return Convert.ToBase64String(inputBytes)
      .Replace('+', '-') // replace URL unsafe characters with safe ones
      .Replace('/', '_') // replace URL unsafe characters with safe ones
      .Replace("=", ""); // no padding
  }

Penghargaan diberikan kepada: Tholle

Ashi
sumber
0

Berikut adalah metode lain untuk memecahkan kode base64 aman-url yang dikodekan dengan cara yang sama dengan Marc. Saya hanya tidak mengerti mengapa4-length%4 berhasil (berhasil).

Sebagai berikut, hanya panjang bit asal yang merupakan kelipatan persekutuan dari 6 dan 8, base64 tidak menambahkan "=" ke hasil.

1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8 
1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6
                "=="            "="

Jadi kita bisa melakukan sebaliknya, jika panjang bit hasil tidak habis dibagi 8, maka ditambahkan:

base64String = base64String.Replace("-", "+").Replace("_", "/");
var base64 = Encoding.ASCII.GetBytes(base64String);
var padding = base64.Length * 3 % 4;//(base64.Length*6 % 8)/2
if (padding != 0)
{
    base64String = base64String.PadRight(base64String.Length + padding, '=');
}
return Convert.FromBase64String(base64String);
kegembiraan
sumber
0

Menggunakan mesin kriptografi Microsoft di UWP.

uint length = 32;

IBuffer buffer = CryptographicBuffer.GenerateRandom(length);
string base64Str = CryptographicBuffer.EncodeToBase64String(buffer)
                   // ensure url safe
                   .TrimEnd('=').Replace('+', '-').Replace('/', '_');

return base64Str;
visc
sumber
0

Jawaban Karanvir Kang bagus dan saya memilihnya. Namun, itu meninggalkan karakter ganjil di akhir string (menunjukkan jumlah karakter padding yang dihapus). Inilah solusi saya.

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
Joshcodes
sumber