Mengapa pengkodean base64 memerlukan bantalan jika panjang input tidak habis dibagi 3?

110

Apa tujuan padding dalam pengkodean base64. Berikut ekstrak dari wikipedia:

"Karakter pad tambahan dialokasikan yang dapat digunakan untuk memaksa keluaran yang dikodekan menjadi kelipatan integer 4 karakter (atau ekuivalen jika teks biner yang tidak dikodekan bukan kelipatan 3 byte); karakter pengisi ini kemudian harus dibuang saat mendekode tetapi masih memungkinkan penghitungan panjang efektif teks yang tidak dikodekan, ketika panjang biner masukannya tidak akan menjadi kelipatan 3 byte (karakter non-pad terakhir biasanya dikodekan sehingga blok 6-bit terakhir yang diwakilinya akan menjadi nol -ditambahkan pada bit yang paling tidak signifikan, paling banyak dua karakter pad dapat muncul di akhir aliran yang dikodekan). "

Saya menulis sebuah program yang dapat menyandikan string base64 dan memecahkan kode string yang disandikan base64. Masalah apa yang dipecahkan padding?

Anand Patel
sumber

Jawaban:

227

Kesimpulan Anda bahwa padding tidak perlu adalah benar. Itu selalu memungkinkan untuk menentukan panjang input dengan jelas dari panjang urutan yang dikodekan.

Namun, padding berguna dalam situasi di mana string yang dikodekan base64 digabungkan sedemikian rupa sehingga panjang urutan individu hilang, seperti yang mungkin terjadi, misalnya, dalam protokol jaringan yang sangat sederhana.

Jika belum diisi string yang tidak digabungkan, data asli tidak dapat dipulihkan karena informasi tentang jumlah byte ganjil di akhir setiap urutan individu hilang. Namun, jika urutan berlapis digunakan, tidak ada ambiguitas, dan urutan secara keseluruhan dapat diterjemahkan dengan benar.

Edit: Ilustrasi

Misalkan kita memiliki program yang menyandikan kata-kata dengan base64, menggabungkannya dan mengirimkannya melalui jaringan. Ini mengkodekan "I", "AM" dan "TJM", menyatukan hasil tanpa padding dan mengirimkannya.

  • Idikodekan ke SQ( SQ==dengan padding)
  • AMdikodekan ke QU0( QU0=dengan padding)
  • TJMdikodekan ke VEpN( VEpNdengan padding)

Jadi data yang dikirimkan adalah SQQU0VEpN. Penerima base64-menerjemahkan ini sebagai I\x04\x14\xd1Q)bukan yang dimaksudkan IAMTJM. Hasilnya tidak masuk akal karena pengirim telah menghancurkan informasi tentang di mana setiap kata berakhir dalam urutan yang dikodekan. Jika pengirim mengirim SQ==QU0=VEpNsebagai gantinya, penerima bisa saja mendekodekan ini sebagai tiga urutan base64 terpisah yang akan digabungkan untuk diberikan IAMTJM.

Mengapa Repot dengan Padding?

Mengapa tidak merancang protokol untuk mengawali setiap kata dengan panjang bilangan bulat? Kemudian penerima dapat mendekode aliran dengan benar dan tidak perlu ada padding.

Itu ide yang bagus, selama kita tahu panjang data yang kita enkode sebelum kita mulai mengkodekannya. Tetapi bagaimana jika, alih-alih kata-kata, kami menyandikan potongan video dari kamera langsung? Kita mungkin tidak mengetahui panjang setiap potongan sebelumnya.

Jika protokol menggunakan bantalan, tidak perlu mengirimkan panjang sama sekali. Data dapat dikodekan saat masuk dari kamera, setiap bagian diakhiri dengan bantalan, dan penerima akan dapat memecahkan kode aliran dengan benar.

Jelas itu adalah contoh yang dibuat-buat, tapi mungkin ini menggambarkan mengapa padding mungkin bisa membantu dalam beberapa situasi.

TJM
sumber
25
+1 Satu-satunya jawaban yang benar-benar memberikan jawaban yang masuk akal selain "karena kami menyukai verbositas dan redundansi untuk beberapa alasan yang tidak dapat dijelaskan".
Tidak valid
1
Ini berfungsi dengan baik untuk potongan yang dienkode dengan jelas, tetapi diharapkan untuk digabungkan secara tak terlihat setelah decoding. Jika Anda mengirim U0FNSQ == QU0 =, Anda dapat merekonstruksi kalimat tersebut, tetapi Anda kehilangan kata-kata yang membentuk kalimat tersebut. Lebih baik daripada tidak sama sekali, kurasa. Khususnya, program GNU base64 secara otomatis menangani pengkodean bersambung.
Marcelo Cantos
2
Bagaimana jika panjang kata adalah kelipatan 3? Cara penggabungan bodoh ini menghancurkan informasi (akhir kata), bukan menghilangkan padding.
GreenScape
2
Penggabungan Base64 memungkinkan pembuat enkode memproses potongan besar secara paralel tanpa beban menyelaraskan ukuran potongan menjadi kelipatan tiga. Demikian pula, sebagai detail implementasi, mungkin ada pembuat enkode di luar sana yang perlu membersihkan buffer data internal dengan ukuran yang bukan kelipatan tiga.
Andre D
2
Jawaban ini dapat membuat Anda berpikir bahwa Anda dapat mendekode sesuatu seperti "SQ == QU0 = VEpN" hanya dengan memberikannya ke decoder. Sebenarnya sepertinya Anda tidak bisa, misalnya implementasi di javascript dan php tidak mendukung ini. Dimulai dengan string gabungan, Anda harus mendekode 4 byte sekaligus atau memisahkan string setelah memasukkan karakter. Sepertinya implementasi tersebut mengabaikan karakter padding, bahkan saat karakter tersebut berada di tengah string.
Roman
40

Pada catatan terkait, berikut adalah konverter dasar untuk konversi dasar sewenang-wenang yang saya buat untuk Anda. Nikmati! https://convert.zamicol.com/

Apa itu Karakter Padding?

Karakter padding membantu memenuhi persyaratan panjang dan tidak memiliki arti.

Contoh Pengisi Desimal: Mengingat persyaratan arbitrer, semua string memiliki panjang 8 karakter, angka 640 dapat memenuhi persyaratan ini menggunakan 0 sebelumnya sebagai karakter pengisi karena tidak memiliki arti, "00000640".

Pengkodean Biner

Paradigma Byte: Byte adalah unit pengukuran standar de facto dan skema encoding apa pun harus berhubungan kembali dengan byte.

Base256 sangat cocok dengan paradigma ini. Satu byte sama dengan satu karakter di base256.

Base16 , heksadesimal atau heksadesimal, menggunakan 4 bit untuk setiap karakter. Satu byte dapat mewakili dua karakter base16.

Base64 tidak cocok secara merata ke dalam paradigma byte (begitu pula base32), tidak seperti base256 dan base16. Semua karakter base64 dapat direpresentasikan dalam 6 bit, 2 bit pendek dari byte penuh.

Kita dapat merepresentasikan pengkodean base64 versus paradigma byte sebagai pecahan: 6 bit per karakter lebih dari 8 bit per byte . Pengurangan fraksi ini adalah 3 byte lebih dari 4 karakter.

Rasio ini, 3 byte untuk setiap 4 karakter base64, adalah aturan yang ingin kami ikuti saat mengenkode base64. Pengkodean Base64 hanya dapat menjanjikan pengukuran dengan bundel 3 byte, tidak seperti base16 dan base256 di mana setiap byte dapat berdiri sendiri.

Begitu mengapa padding didorong meskipun pengkodean dapat berfungsi dengan baik tanpa karakter padding?

Jika panjang aliran tidak diketahui atau jika mungkin berguna untuk mengetahui secara pasti kapan aliran data berakhir, gunakan padding. Karakter padding mengkomunikasikan secara eksplisit bahwa titik ekstra tersebut harus kosong dan mengesampingkan ambiguitas. Bahkan jika panjangnya tidak diketahui dengan padding, Anda akan tahu di mana aliran data Anda berakhir.

Sebagai contoh tandingan, beberapa standar seperti JOSE tidak mengizinkan karakter pengisi. Dalam kasus ini, jika ada sesuatu yang hilang, tanda tangan kriptografik tidak akan berfungsi atau karakter non base64 lainnya akan hilang (seperti "."). Meskipun asumsi tentang panjang tidak dibuat, padding tidak diperlukan karena jika ada sesuatu yang salah tidak akan berhasil.

Dan inilah yang dikatakan base64 RFC,

Dalam beberapa situasi, penggunaan padding ("=") dalam data yang dikodekan basis tidak diperlukan atau digunakan. Dalam kasus umum, ketika asumsi tentang ukuran data yang diangkut tidak dapat dibuat, padding diperlukan untuk menghasilkan data yang diterjemahkan dengan benar.

[...]

Langkah padding dalam basis 64 [...] jika tidak diterapkan dengan benar, menyebabkan perubahan non-signifikan dari data yang dikodekan. Misalnya, jika input hanya satu oktet untuk pengkodean basis 64, maka enam bit dari simbol pertama digunakan, tetapi hanya dua bit pertama dari simbol berikutnya yang digunakan. Bit pad ini HARUS disetel ke nol dengan enkoder yang sesuai, yang dijelaskan dalam deskripsi tentang pengisi di bawah. Jika properti ini tidak berlaku, tidak ada representasi kanonik dari data yang dikodekan basis, dan beberapa string yang dikodekan basis dapat didekodekan ke data biner yang sama. Jika properti ini (dan properti lain yang dibahas dalam dokumen ini) berlaku, encoding kanonik dijamin.

Padding memungkinkan kita untuk memecahkan kode pengkodean base64 dengan janji tidak ada bit yang hilang. Tanpa padding tidak ada lagi pengakuan eksplisit untuk pengukuran dalam bundel tiga byte. Tanpa padding, Anda mungkin tidak dapat menjamin reproduksi yang tepat dari pengkodean asli tanpa informasi tambahan biasanya dari tempat lain dalam tumpukan Anda, seperti TCP, checksum, atau metode lain.

Contoh

Berikut adalah contoh formulir RFC 4648 ( http://tools.ietf.org/html/rfc4648#section-8 )

Setiap karakter di dalam fungsi "BASE64" menggunakan satu byte (base256). Kami kemudian menerjemahkannya ke base64.

BASE64("")       = ""           (No bytes used. 0%3=0.)
BASE64("f")      = "Zg=="       (One byte used. 1%3=1.)
BASE64("fo")     = "Zm8="       (Two bytes. 2%3=2.)
BASE64("foo")    = "Zm9v"       (Three bytes. 3%3=0.)
BASE64("foob")   = "Zm9vYg=="   (Four bytes. 4%3=1.)
BASE64("fooba")  = "Zm9vYmE="   (Five bytes. 5%3=2.)
BASE64("foobar") = "Zm9vYmFy"   (Six bytes. 6%3=0.)

Berikut ini pembuat enkode yang dapat Anda mainkan: http://www.motobit.com/util/base64-decoder-encoder.asp

Zamicol
sumber
17
-1 Ini adalah posting yang bagus dan menyeluruh tentang cara kerja sistem bilangan, tetapi tidak menjelaskan mengapa padding digunakan ketika encoding akan bekerja dengan sempurna tanpanya.
Matti Virkkunen
2
Apakah Anda membaca pertanyaan itu? Anda tidak perlu padding untuk mendekode dengan benar.
Navin
3
Saya pikir jawaban ini sebenarnya menjelaskan alasan seperti yang dinyatakan di sini: "kami tidak dapat lagi menjamin reproduksi yang tepat dari pengkodean asli tanpa informasi tambahan". Sangat sederhana, padding memberi tahu kami bahwa kami menerima pengkodean lengkap. Setiap kali Anda memiliki 3 byte, Anda dapat dengan aman berasumsi bahwa tidak apa-apa untuk melanjutkan dan mendekodekannya, Anda tidak perlu khawatir, hum ... mungkin satu byte lagi akan datang mungkin mengubah pengkodean.
Didier A.
@Tokopedia Bagaimana Anda tahu bahwa tidak ada 3 byte lagi dalam substring base64? Untuk memecahkan kode a char*, Anda memerlukan ukuran string atau terminator null. Padding berlebihan. Makanya, pertanyaan OP.
Navin
4
@Navin Jika Anda melakukan streaming decoding byte base64, Anda tidak tahu panjangnya, dengan padding 3 byte, Anda tahu bahwa setiap kali Anda mendapat 3 byte, Anda dapat memproses 4 karakter tersebut, hingga Anda mencapai akhir streaming. Tanpanya, Anda mungkin perlu mundur, karena byte berikutnya dapat menyebabkan karakter sebelumnya berubah, oleh karena itu Anda hanya dapat memastikan bahwa Anda mendekodekannya dengan benar setelah Anda mencapai akhir aliran. Jadi, ini tidak terlalu berguna, tetapi memiliki beberapa kasus tepi di mana Anda mungkin menginginkannya.
Didier A.
3

Tidak banyak manfaatnya di zaman modern ini. Jadi mari kita lihat ini sebagai pertanyaan tentang apa yang asli tujuan sejarah .

Pengkodean Base64 muncul pertama kali di RFC 1421 tertanggal 1993. RFC ini sebenarnya difokuskan pada mengenkripsi email, dan base64 dijelaskan dalam satu bagian kecil 4.3.2.4 .

RFC ini tidak menjelaskan tujuan padding. Yang paling dekat kita harus menyebutkan tujuan aslinya adalah kalimat ini:

Kuantum pengkodean penuh selalu diselesaikan di akhir pesan.

Ini tidak menyarankan penggabungan (jawaban teratas di sini), atau kemudahan implementasi sebagai tujuan eksplisit untuk padding. Namun, mengingat seluruh deskripsi, bukan tidak beralasan untuk mengasumsikan bahwa ini mungkin dimaksudkan untuk membantu decoder membaca input dalam unit 32-bit ( "quanta" ). Itu tidak menguntungkan hari ini, namun pada tahun 1993 kode C yang tidak aman kemungkinan besar akan benar-benar memanfaatkan properti ini.

Roman Starkov
sumber
1
Dengan tidak adanya padding, upaya untuk menggabungkan dua string ketika panjang string pertama bukanlah kelipatan dari tiga akan sering menghasilkan string yang tampaknya valid, tetapi konten string kedua akan salah mendekode. Menambahkan bantalan memastikan hal itu tidak terjadi.
supercat
1
@supercat Jika itu tujuannya, bukankah akan lebih mudah untuk mengakhiri setiap string base64 hanya dengan satu "="? Panjang rata-rata akan lebih pendek, dan masih akan mencegah penggabungan yang salah.
Roman Starkov
2
Panjang rata-rata b'Zm9vYmFyZm9vYg==' b'Zm9vYmFyZm9vYmE=' b'Zm9vYmFyZm9vYmFy' b'Zm9vYmFyZm9vYmFyZg==' b'Zm9vYmFyZm9vYmFyZm8=' b'Zm9vYmFyZm9vYmFyZm9v' adalah sama dengan b'Zm9vYmFyZm9vYg=' b'Zm9vYmFyZm9vYmE=' b'Zm9vYmFyZm9vYmFy=' b'Zm9vYmFyZm9vYmFyZg=' b'Zm9vYmFyZm9vYmFyZm8=' b'Zm9vYmFyZm9vYmFyZm9v='
Scott