Giriş uzunluğu 3'e bölünemiyorsa neden base64 kodlaması doldurma gerektiriyor?


106

Base64 kodlamada doldurmanın amacı nedir? Aşağıdaki wikipedia'dan alıntıdır:

"Kodlanmış çıktıyı 4 karakterlik bir tam sayı katına (veya kodlanmamış ikili metin 3 baytın katı olmadığında eşdeğer olarak) zorlamak için kullanılabilecek ek bir ped karakteri tahsis edilir; bu dolgu karakterleri daha sonra kod çözme sırasında atılmalıdır, ancak Girdi ikili uzunluğu 3 baytın katı olmayacağı zaman şifrelenmemiş metnin etkin uzunluğunun hesaplanmasına yine de izin verir (son dolgu olmayan karakter normalde kodlanır, böylece temsil ettiği son 6 bitlik blok sıfır olur. - en az anlamlı bitleri üzerine basıldığında, kodlanmış akışın sonunda en fazla iki ped karakteri oluşabilir. "

Herhangi bir dizeyi base64 kodlayabilen ve herhangi bir base64 kodlu dizeyi çözebilen bir program yazdım. Dolgu hangi sorunu çözer?

Yanıtlar:


220

Dolgu işleminin gereksiz olduğu sonucunuz doğrudur. Girdinin uzunluğunu kodlanmış dizinin uzunluğundan net bir şekilde belirlemek her zaman mümkündür.

Bununla birlikte, dolgu, base64 ile kodlanmış dizelerin, örneğin çok basit bir ağ protokolünde olabileceği gibi, ayrı dizilerin uzunluklarının kaybolacağı şekilde birleştirildiği durumlarda yararlıdır.

Eğer unpadded dizeleri birleştirilmiş, her bireyin dizinin sonunda tek bayt sayısı hakkında bilgiler kaybolur, çünkü orijinal verileri kurtarmak imkansız. Bununla birlikte, yastıklı diziler kullanılırsa, belirsizlik olmaz ve bir bütün olarak dizinin kodu doğru bir şekilde çözülebilir.

Düzenleme: Bir Örnek

Kelimeleri base64 ile kodlayan, birleştiren ve bir ağ üzerinden gönderen bir programımız olduğunu varsayalım. "I", "AM" ve "TJM" yi kodlar, sonuçları doldurma olmadan bir araya toplar ve iletir.

  • Ikodlar SQ( SQ==dolgu ile)
  • AMkodlar QU0( QU0=dolgu ile)
  • TJMkodlar VEpN( VEpNdolgu ile)

Yani iletilen veriler SQQU0VEpN. Alıcı base64 I\x04\x14\xd1Q), amaçlanan yerine bunu çözer IAMTJM. Sonuç anlamsızdır çünkü gönderen, kodlanmış sırada her kelimenin nerede bittiği hakkındaki bilgileri yok etmiştir. Gönderen SQ==QU0=VEpNbunun yerine göndermiş olsaydı , alıcı bunu vermek için birleştirilecek üç ayrı base64 dizisi olarak deşifre edebilirdi IAMTJM.

Neden Dolgu ile Rahatsız Edilmeli?

Neden protokolü her kelimenin önüne bir tamsayı uzunluğuyla eklemek için tasarlamıyorsunuz? Daha sonra alıcı, akışın kodunu doğru bir şekilde çözebilir ve doldurmaya gerek kalmaz.

Kodlamaya başlamadan önce kodladığımız verilerin uzunluğunu bildiğimiz sürece bu harika bir fikir . Peki ya kelimeler yerine canlı bir kameradan video parçalarını kodluyorsak? Her parçanın uzunluğunu önceden bilmeyebiliriz.

Protokol doldurma kullanıyorsa, bir uzunluk iletmeye hiç gerek kalmayacaktır. Veriler, kameradan geldikçe kodlanabilir, her parça doldurma ile sonlandırılabilir ve alıcı akışın kodunu doğru bir şekilde çözebilir.

Açıkçası bu çok uydurma bir örnek, ama belki de dolgunun bazı durumlarda neden yararlı olabileceğini gösteriyor.


24
+1 "çünkü açıklanamayan bir nedenden ötürü ayrıntı ve fazlalıktan hoşlandığımız için" mantıklı bir cevap veren tek cevap.
geçersiz

1
Bu, belirgin şekilde kodlanmış, ancak kod çözüldükten sonra bölünmez bir şekilde birleştirilmesi beklenen parçalar için sorunsuz çalışır. U0FNSQ == QU0 = gönderirseniz, cümleyi yeniden kurabilirsiniz, ancak cümleyi oluşturan kelimeleri kaybedersiniz. Hiç yoktan iyidir sanırım. Özellikle, GNU base64 programı birleştirilmiş kodlamaları otomatik olarak işler.
Marcelo Cantos

2
Ya kelimelerin uzunluğu 3'ün katı ise? Bu aptalca birleştirme yöntemi, dolgunun kaldırılmasını değil, bilgileri (kelimelerin sonlarını) yok eder.
GreenScape

2
Base64 birleştirme, kodlayıcıların, yığın boyutlarını üç katına hizalama yükü olmadan büyük parçaları paralel olarak işlemesine olanak tanır. Benzer şekilde, bir uygulama ayrıntısı olarak, üçün katı olmayan bir boyuttaki dahili bir veri tamponunu temizlemesi gereken bir kodlayıcı olabilir.
Andre D

2
Bu cevap, "SQ == QU0 = VEpN" gibi bir şeyi sadece bir kod çözücüye vererek çözebileceğini düşünmeni sağlayabilir. Aslında yapamazsınız gibi görünüyor, örneğin javascript ve php'deki uygulamalar bunu desteklemiyor. Birleştirilmiş bir dizeyle başlayarak, ya bir seferde 4 baytı çözmeniz ya da karakterleri doldurduktan sonra dizeyi bölmeniz gerekir. Görünüşe göre bu uygulamalar, bir dizenin ortasında olsalar bile dolgu karakterlerini yok sayıyor.
Roman

40

İlgili bir notta, işte sizin için oluşturduğum gelişigüzel temel dönüştürme için bir temel dönüştürücü. Zevk almak! https://convert.zamicol.com/

Dolgu Karakterleri nedir?

Dolgu karakterleri uzunluk gereksinimlerini karşılamaya yardımcı olur ve hiçbir anlam taşımaz.

Ondalık Doldurma Örneği: Tüm dizelerin 8 karakter uzunluğunda rastgele gereksinimi göz önüne alındığında, 640 sayısı, hiçbir anlam taşımadıkları için dolgu karakterleri olarak önceki 0'ları kullanarak bu gereksinimi karşılayabilir, "00000640".

İkili Kodlama

Byte Paradigması: Bayt, fiili standart ölçü birimidir ve herhangi bir kodlama şeması, baytlarla ilgili olmalıdır.

Base256 bu paradigmaya tam olarak uyuyor. Bir bayt, base256'daki bir karaktere eşittir.

Base16 , onaltılık veya onaltılık, her karakter için 4 bit kullanır. Bir bayt, iki base16 karakteri temsil edebilir.

Base64 , base256 ve base16'dan farklı olarak, bayt paradigmasına (ve base32'ye) eşit şekilde uymaz. Tüm base64 karakterler, tam bayttan 2 bit kısa olmak üzere 6 bit olarak temsil edilebilir.

Bayt paradigmasına karşı base64 kodlamasını bir kesir olarak temsil edebiliriz: karakter başına 6 bit , bayt başına 8 bit üzerinde . Azaltılmış bu kesir, 4 karakter üzerinden 3 bayttır.

Her 4 base64 karakter için 3 bayt olan bu oran, base64'ü kodlarken takip etmek istediğimiz kuraldır. Base64 kodlaması, her baytın kendi başına durabildiği base16 ve base256'nın aksine , yalnızca 3 baytlık paketlerle bile ölçüm yapmayı vaat edebilir.

Öyleyse , kodlama, dolgu karakterleri olmadan gayet iyi çalışabilmesine rağmen neden doldurma teşvik ediliyor?

Bir akışın uzunluğu bilinmiyorsa veya bir veri akışının tam olarak ne zaman sona erdiğini bilmek faydalı olabilirse, dolgu kullanın. Dolgu karakterleri, bu fazladan noktaların boş olması gerektiğini ve herhangi bir belirsizliği ortadan kaldıracağını açıkça belirtir. Uzunluk dolguyla bilinmese bile veri akışınızın nerede bittiğini bilirsiniz.

Bir karşı örnek olarak, JOSE gibi bazı standartlar karakterlerin doldurulmasına izin vermez. Bu durumda, eksik bir şey varsa, kriptografik bir imza çalışmaz veya diğer base64 olmayan karakterler eksik olur ("." Gibi). Uzunluk ile ilgili varsayımlar yapılmamasına rağmen, dolguya gerek yoktur çünkü yanlış bir şey varsa, işe yaramaz.

Ve bu tam olarak base64 RFC'nin söylediği şeydir ,

Bazı durumlarda, temel olarak kodlanmış verilerde dolgu ("=") kullanılması gerekli değildir veya kullanılmaz. Genel durumda, taşınan verilerin boyutuyla ilgili varsayımlar yapılamadığında, doğru kodu çözülmüş verileri elde etmek için doldurma gereklidir.

[...]

Taban 64 [...] 'deki doldurma adımı, yanlış bir şekilde uygulanırsa, kodlanmış verilerde önemli olmayan değişikliklere yol açar. Örneğin, girdi 64 temel kodlaması için sadece bir sekizli ise, o zaman ilk sembolün altı bitinin tümü kullanılır, ancak sonraki sembolün sadece ilk iki biti kullanılır. Bu ped bitleri, aşağıdaki doldurma açıklamasında açıklanan uyumlu kodlayıcılar tarafından sıfıra AYARLANMALIDIR. Bu özellik tutmazsa, temel kodlamalı verilerin kanonik temsili yoktur ve birden çok temel kodlamalı dizginin kodu aynı ikili veriye çözülebilir. Bu özellik (ve bu belgede ele alınan diğerleri) geçerli olursa, kanonik bir kodlama garanti edilir.

Dolgu, base64 kodlamasının kodunu hiçbir bit kayıp olmadan çözmemizi sağlar. Dolgu olmadan, artık üç bayt demetinde ölçümün açık bir onayı yoktur. Dolgu olmadan, genellikle yığınınızdaki TCP, sağlama toplamları veya diğer yöntemler gibi ek bilgiler olmadan orijinal kodlamanın tam olarak yeniden üretilmesini garanti edemeyebilirsiniz.

Örnekler

RFC 4648 örnek formu ( http://tools.ietf.org/html/rfc4648#section-8 )

"BASE64" işlevi içindeki her karakter bir bayt (base256) kullanır. Daha sonra bunu base64'e çeviririz.

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.)

İşte oynayabileceğiniz bir kodlayıcı: http://www.motobit.com/util/base64-decoder-encoder.asp


17
-1 Sayı sistemlerinin nasıl çalıştığına dair güzel ve kapsamlı bir gönderi, ancak kodlama olmadan mükemmel çalışacakken neden doldurmanın kullanıldığını açıklamıyor .
Matti Virkkunen

2
Soruyu okudun mu? Doğru şekilde çözmek için dolguya ihtiyacınız yoktur .
Navin

3
Sanırım bu yanıt, burada belirtilen nedeni açıkladı: "artık orijinal kodlamanın ek bilgi olmadan tam olarak yeniden üretilmesini garanti edemeyiz". Gerçekten çok basit, dolgu, kodlamanın tamamını aldığımızı bize bildirir. Her 3 bayta sahip olduğunuzda, devam edip onu çözmenin uygun olduğunu güvenle varsayabilirsiniz, endişelenmeyin, uğultu ... belki bir bayt daha gelecek ve muhtemelen kodlamayı değiştirecektir.
Didier A.

@DidierA. Bir base64 alt dizesinde 3 bayt daha olmadığını nasıl anlarsınız? A'nın kodunu çözmek char*için dizenin boyutuna veya boş sonlandırıcıya ihtiyacınız vardır. Dolgu gereksizdir. Dolayısıyla, OP'nin sorusu.
Navin

4
@Navin Eğer base64 byte'ın kodunu çözüyorsanız, uzunluğu bilmiyorsunuz, 3 byte'lık doldurma ile, her 3 byte aldığınızda 4 karakteri akışın sonuna kadar işleyebileceğinizi bilirsiniz. Bu olmadan, geriye dönmeniz gerekebilir, çünkü bir sonraki bayt, önceki karakterin değişmesine neden olabilir, bu nedenle, yalnızca akışın sonuna ulaştığınızda doğru bir şekilde kodunu çözdüğünüzden emin olabilirsiniz. Yani, çok kullanışlı değil, ancak isteyebileceğiniz birkaç uç durumu var.
Didier A.

3

Günümüzde bunun pek bir faydası yok. Öyleyse buna orijinal tarihsel amacın ne olabileceği sorusu olarak bakalım .

Base64 kodlaması, 1993 tarihli RFC 1421'de ilk kez ortaya çıktı . Bu RFC aslında e-postayı şifrelemeye odaklanmıştır ve base64, küçük bir bölüm 4.3.2.4'te açıklanmıştır .

Bu RFC, doldurmanın amacını açıklamaz. Asıl amaçtan bahsetmemiz gereken en yakın şey şu cümle:

Tam kodlama kuantumu her zaman bir mesajın sonunda tamamlanır.

Birleştirme (buradaki en iyi cevap) veya dolgu için açık bir amaç olarak uygulama kolaylığı önermez. Bununla birlikte, açıklamanın tamamı dikkate alındığında, bunun kod çözücünün girişi 32 bitlik birimlerde ( "quanta" ) okumasına yardımcı olması amaçlanmış olabileceğini varsaymak mantıksız değildir . Bunun bugün hiçbir faydası yok, ancak 1993'te güvenli olmayan C kodu, bu özellikten çok büyük olasılıkla yararlanacaktı.


1
Dolgu olmadığında, ilk dizenin uzunluğu üçün katı olmadığında iki dizgeyi birleştirme girişimi genellikle görünüşte geçerli bir dizge verir, ancak ikinci dizenin içeriği yanlış bir şekilde çözülür. Dolgu eklemek bunun gerçekleşmemesini sağlar.
supercat

1
@supercat Hedef bu olsaydı, her base64 dizesini tek bir "=" ile bitirmek daha kolay olmaz mıydı? Ortalama uzunluk daha kısa olur ve yine de hatalı birleştirmeleri önler.
Roman Starkov

2
Ortalama uzunluğu ile b'Zm9vYmFyZm9vYg==' b'Zm9vYmFyZm9vYmE=' b'Zm9vYmFyZm9vYmFy' b'Zm9vYmFyZm9vYmFyZg==' b'Zm9vYmFyZm9vYmFyZm8=' b'Zm9vYmFyZm9vYmFyZm9v' aynı b'Zm9vYmFyZm9vYg=' b'Zm9vYmFyZm9vYmE=' b'Zm9vYmFyZm9vYmFy=' b'Zm9vYmFyZm9vYmFyZg=' b'Zm9vYmFyZm9vYmFyZm8=' b'Zm9vYmFyZm9vYmFyZm9v='
Scott
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.