Base64 kodlamasının açıklaması
(akshaykhot.com)- Base64 kodlama, ikili veriyi ASCII metne dönüştürerek depolama ve aktarım sırasında verinin yanlış yorumlanma olasılığını azaltan bir yöntemdir
- Şifreleme değil, gösterim biçimini değiştirme olduğundan kodlanmış veri, orijinal metne ya da dosya verisine kolayca geri döndürülebilir
- 64 karakter 6 bit ile ifade edilebildiği için bir Base64 karakteri 6 bit veri taşır ve 3 bayt (24 bit) dört Base64 karakterine dönüştürülür
- HTML içindeki Data URLs, e-postada ikili veri aktarımı ve ham ikilinin sorun çıkarabildiği metin odaklı ağlar ya da URL'ler gibi ortamlarda kullanışlıdır
- Ruby, C#, PHP, JavaScript ve terminaldeki
base64komutu dahil olmak üzere birçok dil ve araç kodlama ve kod çözme işlevi sunar
Base64 neyi değiştirir
- Base64 kodlama, ikili veriyi metne, daha spesifik olarak ASCII metne dönüştürür
- Sonuç yalnızca aşağıdaki 64 karakteri kullanır
A-Za-z0-9+/
- Bu karakter kümesi,
<,>,\ngibi karakterlerin eski bilgisayarlar veya programlar tarafından yanlış yorumlandığı durumları önlemek için kullanılan güvenli bir karakter kümesidir "Ruby on Rails"ifadesi Base64 ile kodlandığındaUnVieSBvbiBSYWlscw==olur- Base64 şifreleme değildir
- Kodlanmış veri, orijinal metne kolayca geri döndürülebilir
- Veriyi gizlemez, yalnızca verinin gösterimini değiştirir
Base64'in kullanıldığı durumlar
- Data URLs, görsel gibi dosya verilerinin doğrudan HTML içine yerleştirilmesine izin verir ve bunun için Base64 ile kodlanmış metin kullanır
- Örnek biçim
data:[<mime type>][;charset=<charset>][;base64],<encoded data>şeklindedir - E-postada, sunucuların satır sonlarını değiştirebildiği ortamlarda bile ikili veriyi güvenle taşımak için Base64 uzun süredir kullanılmaktadır
- Görsel verisini doğrudan HTML kaynağına yerleştirirken
<ve>gibi karakterlerin etiket olarak yorumlanmaması için kodlama gerekir - Metin veya US-ASCII verisini işlemek üzere tasarlanmış ağlar üzerinden ikili veriyi depolarken ya da aktarırken de kullanılabilir
- URL içine yerleştirilmesi zor karakterler içeren veriyi iletirken de Base64 kullanılabilir
- Base ailesindeki kodlamalar, nesnelerin metin editörleriyle ele alınabilmesini sağladığı için birçok uygulamada kullanılır
Kodlama algoritması
- Base64 kodlama şu sırayla ilerler
- Metni ikili gösterime dönüştürür
- Bitleri 6'şar bitlik gruplara böler
- Her 6 bitlik grubu 0'dan 63'e kadar bir ondalık sayıya dönüştürür
- Bu sayıyı Base64 alfabesindeki karşılık gelen karaktere çevirir
- Son grubun bitleri eksikse
=veya==padding olarak eklenebilir - 64 karakteri ifade etmek için 6 bit gerekir
2^6 = 64- Tek bir Base64 değeri 6 bit veriyi temsil eder
- Bir bayt 8 bittir ve 8 ile 6'nın en yakın ortak katı 24'tür
- 24 bit, 3 bayttır
- 24 bit, dört adet 6 bitlik Base64 değeriyle ifade edilir
“Akshay” kodlama örneği
"Akshay", her karakter ASCII sayısına çevrilip ardından ikiliye dönüştürüldüğünde şu şekilde olur01000001 01101011 01110011 01101000 01100001 01111001
- Bu veri 6 bitlik gruplara ayrıldığında sonuç şöyledir
010000 010110 101101 110011 011010 000110 000101 111001
- Her grup ondalık sayıya çevrildiğinde şu değerler elde edilir
16 22 45 51 26 6 5 57
- Base64 alfabesine dönüştürüldüğünde şu karakterler ortaya çıkar
Q W t z a G F 5
- Dolayısıyla
"Akshay"ifadesinin Base64 karşılığıQWtzaGF5olur - Aynı şekilde görsel, PDF, metin ve video gibi dosyalar da ikiliye çevrilip ardından Base64 ile kodlanarak ASCII metin olarak saklanabilir veya aktarılabilir
Dillerde ve araçlarda kullanım
- Ruby,
Base64modülüyle kodlama ve kod çözme işlemlerini yaparBase64.encode64("Ruby on Rails")Base64.decode64(encoded)
- C#, bir dizeyi bayt dizisine dönüştürdükten sonra
Convert.ToBase64Stringile kodlar veSystem.Convert.FromBase64Stringile çözer - PHP, üst düzey
base64_encodevebase64_decodefonksiyonlarını sunar - JavaScript,
btoa()ile kodlar veatob()ile çözer - Terminalde de
base64komutuyla kodlama ve kod çözme yapılabilirecho "akshay" | base64komutuYWtzaGF5Cg==çıktısını üretirecho "YWtzaGF5Cg==" | base64 -dkomutuakshayçıktısını üretir
1 yorum
Hacker News yorumları
Burada metni şifrelemediğini vurguladığınız için teşekkürler. Pek çok junior geliştirici, şifrelemenin geri alınabilmesi için gizli bir değer gerektirdiği, hashingin geri alınamaz olduğu ve encodingin her zaman kolayca geri çevrilebildiği farkını çok geç öğrenip sıkıntı yaşıyor.
Çıktı rastgele görünse bile entropinin girdinin entropisiyle aynı olduğunu bilmek de önemli. Yani parolanızı daha güçlü yapmak için Base64 ile encode etmemelisiniz.
Parola tamamen rastgele üretilmişse Base64 encoding hiçbir işe yaramaz. Ama parola, sözlük kelimeleri ya da hatırlaması kolay kurallar gibi düşük entropili bir şemayla oluşturulmuşsa, saldırganın akıllı parola kırıcıya Base64 encoding kuralını da hesaba katacak şekilde ayar vermesi gerekir; bu da her denemeye fazladan bir işlem eklemek kadar bir güç katar.
Elbette böyle parola şemaları kullanmamak gerekir. “correct horse battery staple” türü parolaların yeterli olduğunu düşünüyorum.
Hashing’in güvenlik dışında da pek çok amacı vardır; bu yüzden hash kütüphaneleri de çeşitlidir. Güvenlik veya kripto ile ilgili amaçlarla hash kullanacaksanız, o amaca göre tasarlanmış bir hash kullanmalısınız. CRC hash hızlıdır, ama kullanıcı parolaları için iyi bir seçenek değildir.
Base64’ün ilginç yanlarından biri, herhangi bir string ile başlayıp encode etmeyi tekrar ederseniz sonucun baş kısmının giderek bir sabit noktaya yakınsamasıdır. Bunu Bash ile de görebilirsiniz.
10 yıldan da uzun süre önce tesadüfen keşfedip şifreli bir şey gibi tweetlemiştim [1]; biri bu konuda bir blog yazısı yazdı ve burada da paylaştı ama pek tartışma olmadı [2]. Başka biri Reddit /r/compsci’ye gönderince orada blog yazısını düzelten verimli bir tartışma çıktı [3]. Blog şu an yayında değil ama Internet Archive’da bir kopyası duruyor [4].
[1] https://twitter.com/p4bl0/status/298900842076045312
[2] https://news.ycombinator.com/item?id=5181256
[3] https://www.reddit.com/r/compsci/comments/18234a/the_base64_...
[4] https://web.archive.org/web/20130315082932/http://fmota.eu/b...
Bash ile encode ederken
-nseçeneğini kullanmalısınız:$ echo -n "abcde" |base64-nolmazsaechostring’in sonuna bir satır sonu karakteri ekler ve o karakter de encode edilir.echokullanmak yerine printf kullanmanız daha iyi olur. https://linux.die.net/man/1/printfbase64URL de var; URL’ler için güvenli olan farklı ASCII karakterleri kullanarak encode eder. Bazı geliştiriciler BASE64URL’ye doğrudan base64 diyebiliyor; bu da bilmeyenler için sorun yaratabilir.
https://datatracker.ietf.org/doc/html/rfc4648#section-5
~ve.karakterlerinin harf olmaması; bu yüzden encode edilmiş değere çift tıklayınca tamamı seçilmiyor. Kopyala-yapıştır yapmak istediğiniz birçok durumda gereksiz sürtünme yaratıyor.Base62 encoding (
0-9A-Za-z), base64url kadar neredeyse verimli ve URL güvenliğini korurken kopyala-yapıştırı daha kolay hale getirir. İnsanların okurken yaşayacağı belirsizliği azaltmak istiyorsanız Base58’e inebilirsiniz; ama genelde BaseXX encoding yapacak kadar uzun değerlerde kopyala-yapıştır yaygın olduğundan bu büyük bir sorun değildir.https://en.wikipedia.org/wiki/Base62
Padding’li Base64 string’leri her zaman 4’ün katı uzunluktadır; bu yüzden 4’ün katı olmayan bir string alırsanız aslında ne kadar padding olması gerektiğini ve son 3 byte’ın nasıl decode edileceğini anlayabilirsiniz.
Bu yüzden Base64’te baştan
==padding’ine neden ihtiyaç duyulduğu biraz kafamı karıştırıyor.Taban dönüşümü konusu ne zaman açılsa, keyfi taban dönüştürücümün reklamını utanmadan yapıyorum: https://convert.zamicol.com
“useful alphabets” altındaki base64, tabana göre tekrarlı bölme yapan “doğal” sayı tabanı; RFC’deki “bucket” dönüşüm yöntemi ise extras altında.
Bir şeyi encode ettiyseniz ve insanların bunu elle yazması gerekiyorsa https://en.wikipedia.org/wiki/Base32 öneririm.
Kötü fontlar yüzünden
lmi1mi,omuOmu0mı diye karıştırmak kadar sinir bozucu çok az şey var.Biraz daha titiz konuşursak, Base64’ün ikili veriyi ASCII karakterlerinin tamamına değil, ASCII’nin bir alt kümesine encode ettiğini söylemek daha doğru olur.
ASCII’de 128 kod noktası vardır; bunların 95’i yazdırılabilir karakter, 33’ü kontrol karakteridir. Base64 ise bunların yalnızca 64’ünü, padding dahil edilirse 65’ini kullanır.
Yazıda
=/==padding’in amacı ayrıntılı ele alınmamış; 6 bitlik gruplara tam bölünmeyen verilerin nasıl işlendiği de örnekle gösterilmemişKabaca anladığımı sanıyorum ama kesin bilmek istiyorum.
=ne zaman,==ne zaman kullanılır; her zaman eklenir mi yoksa eklenmediği durumlar da var mı;"5byte"gibi bir string’in artan bitleri tam olarak nasıl işlenir; decode ederken nelere dikkat etmek gerekir—kısa ve eksiksiz yanıtlayabilirsen iyi olurduBir Base64 karakteri 6 biti temsil ettiğinden, 3 baytlık bir veri bloğu Base64’te 4 karakterlik bir bloğa karşılık gelir. Bu yüzden Base64 verisini 4’er karakter halinde işlemek pratiktir
=, encode edilmiş string uzunluğunu 4’ün katına tamamlamak için gerektiğinde 0, 1 veya 2 tane eklenen padding’dir. Örneğin"543210"→"543210==","6543210"→"6543210=";"76543210"için padding gerekmez. Padding olarak 3 tane=gerekmez, çünkü 1 bayt veri bile en az 2 Base64 karakteri gerektirirArtan bitler 0 ile doldurulabilir; decoder da tam 1 bayt oluşturacak kadar bit olmadığını görüp bunları atabilir. Günümüzde çoğu durumda padding kesin zorunluluktan çok bir konvansiyon gibidir. Wikipedia maddesi oldukça ayrıntılı: https://en.wikipedia.org/wiki/Base64
Bir stream’in, dosyanın veya string’in sonundaki padding karakterleri, zaten işlenen uzunluktan çıkarılabildiği için katı anlamda şart değildir
Ancak padding’i ele alma biçimi epey inceliklidir ve bu farklar yüzünden ilginç implementasyon varyasyonları ortaya çıkmıştır: https://eprint.iacr.org/2022/361.pdf
Sonuçta 24 bitlik birimler halinde encode ediliyor. Veri bittiğinde kalan 24 bitlik kısım
Aile değil=ile doldurulur; çünküA, veri olarak000000anlamına gelir. Ben de anlamak için tamamını iki kez okudumBenim Base64 encoder shader’ım burada: https://github.com/Rezmason/excel_97_egg/blob/main/glsl/base...
GLSL’de yaklaşık 13 satıra kadar indirdim: https://github.com/Rezmason/excel_97_egg/blob/main/glsl/base...
Bir yan projenin Cursed Mode’unda kullanılıyor; WebGL framebuffer’ını Base64 ile encode edilmiş 640x480 piksel indeks renkli BMP olarak saniyede yaklaşık 15 kez render ediyor: https://rezmason.github.io/excel_97_egg/?cursed=1
Derine inmeye başlayınca ek olarak ilginç ayrıntılar var; bu ayrıntıların varyasyonları da şaşırtıcı derecede çok
Girdi verisinin uzunluğu tam olarak 3 baytın katı değilse, son 1 baytı veya 2 baytı encode etmek için 2 ya da 3 Base64 karakteri kullanılır. Bir Base64 karakteri 6 bit olduğundan, 8 bit veya 16 biti ifade etmek için 12 bit ya da 18 bit kullanılır; bunun sonucunda hiçbir şeyi encode etmeyen fazladan 4 bit veya 2 bit oluşur
RFC, encoder’ın bu bitleri 0 olarak ayarlamasını şart koşar; ancak decoder için yalnızca bu bitleri 0 olmayan girdileri reddedebileceği söylenir. Pratikte varsayılan olarak reddeden implementasyon neredeyse yok; bildiğim kadarıyla yalnızca Ruby, Rust ve Go bu tür girdilerde hata verecek şekilde ayarlanabiliyor. Python’da
validateseçeneği var ama bu bitleri doğrulamıyorBir diğer büyük fark da boşlukların ve Base64 olmayan karakterlerin nasıl işlendiği. Python dahil şaşırtıcı derecede çok implementasyon, girdideki rastgele karakterleri sessizce yok sayıyor. Alfabeyi yanlış seçerseniz bu sorun yaratıyor; örneğin Python’da
base64.standard_b64decode(base64.urlsafe_b64encode(b'\xFF\xFE\xFD\xFC'))hata vermeden sessizce yanlış çıktı üretiyorRuby’nin Base64 encoder’ının her 60 karakterde bir satır sonu eklemesi de ilginç. PEM dışında bu kadar kısa satır isteyen standart bir encoding yok; PEM de tam olarak 64 karakterlik satırlar istediğinden bu epey tuhaf bir tercih
Programlama dilleri ile bazı JavaScript kütüphaneleri arasındaki farkları özetleyen bir yazı yazdım [1]; ayrıca JS’e daha iyi bir Base64 ekleme çalışması da yürütüyorum [2]
[1] https://gist.github.com/bakkot/16cae276209da91b652c2cb3f612a...
[2] https://github.com/tc39/proposal-arraybuffer-base64