Base64-Kodierung in Bash: Ein vollständiger Leitfaden
Sie haben Bytes und Sie brauchen einen String. Eine Textdatei, die in einem JSON-Body leben muss. Ein Bild, das in eine Konfigurations-Zeile muss. Ein Token, das durch eine URL, eine Umgebungsvariable oder einen HTTP-Header reisen wird. Ein privater Schlüssel, der in einen Zertifikat-Speicher gehört. Das ist der tägliche Job der Base64-Kodierung in der Shell, und die Antwort der Shell ist ein einzelnes, kleines, bemerkenswert portables Kommando.
Der Tausch in einem Atemzug: Base64 schreibt jeweils drei Bytes roher Daten als vier Zeichen aus einem Alphabet von 64 Zeichen um (A-Z, a-z, 0-9, plus + und /) und polstert das Ende mit ein oder zwei =-Zeichen aus, wenn die Anzahl der Bytes kein Vielfaches von drei ist. Die Startseite dieser Site erklärt das Format in voller Länge, hier verbringen wir unsere Zeit damit, den Text zu produzieren, den richtigen Dialekt für das Ziel zu wählen und die Größen-Rechnung mit offenen Augen zu bezahlen. Eine Zahl für die Hosentasche: Die kodierte Form ist normalerweise etwa ein Drittel größer als das Original, vier Zeichen pro drei Bytes, und sie kommt immer wieder vor.
Die Besetzung ist klein. Das base64-Kommando aus coreutils (GNU oder die neuere Rust-uutils-Familie), basenc aus derselben Familie für den URL-sicheren Dialekt, openssl base64 für Maschinen ohne coreutils, das BusyBox-Applet für Embedded-Systeme und die BSD-Variante auf macOS. Fünf Werkzeuge, ein Job, ein paar Flags, die sich zu wissen lohnen.
Wählen Sie Ihren Kodierer
Alle diese lesen Bytes von der Standard-Eingabe oder einer Datei und schreiben Text auf die Standard-Ausgabe, also passen sie alle in dieselben Pipelines. Die Unterschiede sind der Default-Zeilenumbruch und die verfügbaren Dialekte:
| Werkzeug | Wo es lebt | Default-Zeilenumbruch | Greifen Sie zu, wenn |
|---|---|---|---|
base64 (coreutils) |
Linux, und macOS via Homebrew | 76 Zeichen | die Standard-Wahl; -w 0 für eine Zeile hinzufügen |
basenc (GNU coreutils) |
Linux mit coreutils | 76 Zeichen | Sie --base64url, base32, base16 oder einen der Kumpel brauchen |
openssl base64 |
überall, wo OpenSSL installiert ist | 64 Zeichen | coreutils fehlt; -A für eine Zeile |
busybox base64 |
Alpine, embedded Linux | 76 Zeichen | minimale Systeme; dieselben Flags in einem kleineren Körper |
base64 (BSD/macOS) |
macOS, die BSDs | keiner (eine lange Zeile) | natives macOS-Arbeiten; -b setzt die Breite |
Lesen Sie die Umbruch-Spalte zweimal, denn das ist der stille Unterschied zwischen den Familien. Coreutils und BusyBox umbrechen standardmäßig bei 76, OpenSSL bei 64, und das BSD-Werkzeug umbreicht gar nicht. Keines davon ist falsch; sie haben einfach unterschiedliche Konventionen geerbt (MIME sagt 76, PEM sagt 64, und das BSD-Werkzeug ist schlicht älter als die Umbruch-Gewohnheit). Wenn es dem Konsument etwas ausmacht, setzen Sie die Breite explizit und verlassen Sie sich nie auf den Default.
Zuerst Text: Der unsichtbare Zeilenumbruch
Kodierung von Text in der Shell beginnt mit einer Falle: echo fügt ein Zeilenende hinzu. Die fünf Buchstaben "hello" werden zum Zeitpunkt, an dem sie durch echo laufen, zu sechs Bytes, und das sechste Byte reitet mit in die Ausgabe, unsichtbar und für immer:
echo "hello" | base64
Das gibt aGVsbG8K aus, und das letzte Zeichen kodiert das Zeilenende. Die Lösung ist die, die Sie für Text benutzen sollten, bei dem die Anzahl der Bytes zählt: printf mit Format, ohne Dekoration:
printf '%s' "hello" | base64
Jetzt ist die Ausgabe aGVsbG8=, genau fünf Bytes' wert, und das letzte Zeichen ist ein Padding-Zeichen statt eines lebendigen Bytes. Dieselbe Regel gilt für Here-Strings, die wie echo ein abschließendes Zeilenende anhängen: base64 <<< "hello" gibt Ihnen wieder die aGVsbG8K-Version. Im Zweifel fragen Sie sich, welches das letzte Byte ist, bevor Sie es kodieren.
Wenn Sie etwas auf einer einzelnen Zeile haben wollen, fügen Sie -w 0 hinzu (oder die Vettern von -w 0 unten), was auch das abschließende Zeilenende entfernt, das das Kommando andernfalls ausgeben würde:
printf '%s' "hello world and more" | base64 -w 0
Das ist eine saubere, ununterbrochene Zeile ohne abschließendes Zeilenende, bereit, ohne weitere Zeremonie in eine URL, einen JSON-Wert oder eine Konfigurationsdatei zu fallen.
Dateien und die Umbruch-Breite
Dateien sind der häufige Fall, und jede Implementation nimmt ein FILE-Argument an, das die Bytes ganz von der Quoting-Maschinerie der Shell fernhält:
base64 -w 0 report.pdf > report.b64
Ohne -w 0 trifft die Ausgabe umgebrochen bei 76 Zeichen ein, was genau das ist, was ein MIME-Konsument will:
base64 report.pdf > report.mime.b64
Die Breite ist ein Regler, den Sie pro Konsument einstellen. Sechsundsiebzig ist die MIME-Konvention aus RFC 2045, vierundsechzig ist die PEM-Konvention, die von Zertifikaten und Schlüsseln benutzt wird, und null bedeutet eine ununterbrochene Zeile für URLs und APIs:
base64 -w 64 key.bin | head -2
Wenn der Konsument auf Windows lebt und CRLF-Zeilenenden erwartet, konvertieren Sie nach dem Umbruch, nicht vorher:
base64 -w 76 attachment.bin | sed 's/$/\r/' > attachment.crlf.b64
Für den OpenSSL-Weg ist das Äquivalent des Ein-Zeilen-Modus das -A-Flag, das auch das abschließende Zeilenende unterdrückt:
openssl base64 -A < report.pdf
Bevor Sie eine umgebrochene Datei verschicken, kostet ein Größen-Sanity-Check nichts und fängt erstaunlich viele Fehler (eine doppelt kodierte Datei, eine Datei mit dem falschen Input kodiert):
wc -c report.pdf
base64 report.pdf | wc -c
Die zweite Zahl sollte etwa vier Drittel der ersten sein, plus ein Byte pro umgebrochener Zeile für die Zeilenenden. Wenn sie weit daneben liegt, halten Sie an und schauen Sie, was Sie dem Kodierer tatsächlich gefüttert haben.
URL-sicheres Base64: Die zwei unangenehmen Zeichen austauschen
Zwei Zeichen im Standard-Alphabet, + und /, sind die Problemkinder: Ein + in dem Query-String einer URL bedeutet Leerzeichen, ein / kann wie ein Pfadtrenner aussehen, und beide erzwingen Percent-Encoding, sobald der String in eine URL, ein Cookie oder einen Dateinamen eintritt. RFC 4648, Abschnitt 5, löst das mit einem Dialekt, der genau diese zwei Zeichen durch - und _ ersetzt und das Padding weglässt, denn eine URL muss selten die exakte Byte-Länge anzeigen.
Das Shell-Rezept ist Tausch plus Trim, ein Lauf durch tr für das Alphabet und einer zum Entfernen des Paddings:
printf '\376\117\202' | base64 -w 0 | tr '+/' '-_' | tr -d '='
Diese drei Bytes kodieren normalerweise zu /k+C, was in einer URL hässlich wäre. Die Pipeline verwandelt es in _k-C, vier Zeichen, die überall reisen können. Der Tausch ist positionell, also ist die Richtung leicht zu verwechseln: Kodieren geht mit tr '+/' '-_' (Plus wird Strich, Slash wird Unterstrich), und die Umkehrung, die zum Dekodieren gehört, geht mit tr '_-' '/+'. Eine verwechselte Richtung gibt keinen Fehler, sie produziert nur andere Bytes, und das ist die schlimmste Art von Bug, die man ausliefern kann.
Der Dialekt zählt, wann immer der String die Kontrolle der Shell verlässt: JWT-Segmente, Tokens in Query-Strings, Werte in Cookies oder Dateinamen und jede Kennung, die ein anderes System als Teil einer URL liest. Das basenc von GNU erzeugt den Dialekt nativ, mit dem Padding noch an Ort und Stelle:
printf '%s' "hello" | basenc --base64url
Streichen Sie das Padding mit tr -d '=', wenn der Konsument die gestrichene Form will, wie die meisten.
Ein JWT in der Shell prägen
JSON Web Tokens sind der am meisten sichtbare Konsument von URL-sicherem Base64 in der API-Welt. Ein kompaktes JWT ist drei base64url-Segmente, die durch Punkte verbunden sind: der Header, der Payload und die Signatur, gemäß RFC 7515. Die ersten beiden sind reines JSON, und die Signatur ist ein binärer Digest der ersten beiden Segmente, verbunden durch einen Punkt, genau die Art von Sache, bei der openssl gut ist.
key="supersecretkey"
h=$(printf '%s' '{"alg":"HS256","typ":"JWT"}' | base64 -w 0 | tr '+/' '-_' | tr -d '=')
p=$(printf '%s' '{"sub":"42","name":"homer"}' | base64 -w 0 | tr '+/' '-_' | tr -d '=')
s=$(printf '%s' "$h.$p" | openssl dgst -sha256 -hmac "$key" -binary | base64 -w 0 | tr '+/' '-_' | tr -d '=')
printf '%s.%s.%s\n' "$h" "$p" "$s"
Das gibt ein kompaktes HS256-JWT aus, das jede Standard-Bibliothek auf jeder Plattform akzeptiert. Achten Sie auf die Arbeitsteilung: Der Base64-Teil ist das Alphabet, der openssl dgst -sha256 -hmac-Teil ist die Kryptographie, und das Verbinden mit Punkten ist das Format. Halten Sie die drei Jobs im Kopf getrennt, und die Pipeline bleibt offensichtlich.
Drei Feld-Vorsichtsmaßnahmen. Erstens wird der MAC über den ASCII-Text der ersten beiden Segmente plus den Punkt berechnet, also müssen die Segmente zum Zeitpunkt des Signierens schon in ihrer finalen base64url-Form sein. Neu-Umbrechen oder Neu-Polstern nach dem Signieren bricht das Token. Zweitens bleibt der Schlüssel aus dem Token heraus: Die Signatur beweist, wer signiert hat, und der Schlüssel hält das Geheimnis geheim. Drittens ist Prägen in einem Shell-Skript ein Werkzeug für Testen und Automatisierung, kein Ersatz für den Server, der diese Tokens tatsächlich ausstellt und verifiziert, und ein Token, mit alg: none geprägt, beweist überhaupt nichts.
Data-URIs: Dateien, die in Strings reiten
RFC 2397 definiert das data:-URL-Schema, und seine Base64-Form erlaubt es einer Datei, in einer URL zu leben: data:, dann ein optionaler Medientyp, dann ;base64, wenn der Payload Base64-kodiert ist, dann ein Komma, dann die Daten. Lassen Sie den Medientyp aus, und der Default ist text/plain;charset=US-ASCII, was eine Fußangel ist, die sich zu kennen lohnt, denn die meisten meinen ein Bild oder ein JSON-Dokument, nicht ASCII-Text.
printf 'data:text/plain;base64,%s\n' "$(printf '%s' "hi there" | base64 -w 0)"
Das gibt data:text/plain;base64,aGkgdGhlcmU= aus, eine komplette, in sich geschlossene URL, die ein Browser gern anzeigt. Für ein Bild dieselbe Form mit einem echten Medientyp:
printf 'data:image/png;base64,%s\n' "$(base64 -w 0 icon.png)" > icon.uri
Fügen Sie das Ergebnis in das src eines HTML-img-Tags oder in ein CSS-background ein, und das Bild reist mit dem Dokument, ohne zweite HTTP-Anfrage. Die Fallen drehen sich alle um Größe: Der RFC selbst sagt, dass das Schema nur für kurze Werte nützlich ist, Browser verhängen ihre eigenen URL-Längen-Grenzen, jedes inline gesetzte Byte kostet 33 Prozent Aufschlag auf die eigene Größe des Bildes, und eine Seite voller Data-URIs ist eine Seite ohne Caching-Geschichte für diese Bilder. Für kleine Icons und einmalig eingebettete Grafiken ist es ein Genuss, für eine Foto-Bibliothek ist es eine Steuer.
Secrets, Config und Umgebungsvariablen
Base64 taucht in der Config- und Secrets-Arbeit aus einem bestimmten Grund auf: Es verwandelt beliebige Bytes, inklusive Leerzeichen, Anführungszeichen und Zeilenenden, in einen String, der ein export, eine Konfigurations-Zeile oder ein JSON-Feld übersteht, ohne jegliche Quoting-Akrobatik. Kubernetes ist das am meisten sichtbare Beispiel: Jedes Feld unter dem .data eines Secrets ist Base64, also ist das Erzeugen eines Secrets in der Shell einfach Kodierung:
kubectl create secret generic app --from-literal=password='s3cret'
Der API-Server speichert das Passwort als czNjcmV0 unter .data, und jeder Node mit Zugang zum Secret kann es mit einem einzigen Dekodieren zurücklesen. Dieselbe Bewegung funktioniert für Ihre eigenen Konfigurationsdateien:
export API_TOKEN_B64=$(printf '%s' "$API_TOKEN" | base64 -w 0)
Oder, für eine Datei, die die Anwendung beim Start liest:
printf 'token=%s\n' "$(printf '%s' "$API_TOKEN" | base64 -w 0)" >> app.conf
Jetzt kommt die Warnung, die an eine Wand gehört: Base64 ist Kodierung, nicht Verschlüsselung. Der Sicherheitsabschnitt von RFC 4648 ist dabei unmissverständlich, er merkt an, dass die Kodierung "optisch Informationen verbirgt, die sich sonst leicht erkennen ließen, wie Passwörter, aber keine rechnerische Vertraulichkeit bietet", und dass genau dieses Missverständnis echte Sicherheitsvorfälle verursacht hat, als jemand einen "geschützten" Protokoll-Austausch in einen Bug-Report kopierte und versehentlich die Credentials preisgab. Wenn der Wert geheim sein muss, verschlüsseln Sie ihn (und Base64-kodieren Sie dann den Chiffretext für die Speicherung); wenn Base64 alles ist, was Sie haben, behandeln Sie den kodierten Wert im Moment, in dem er den Bildschirm verlässt, als Klartext.
Unicode, Charsets und die Bytes darunter
Der Kodierer liest Bytes, keine Zeichen, und die Shell gibt ihm die Bytes, die die Locale und die Kommandos erzeugt haben. Für UTF-8-Text ist das meist genau das, was Sie wollen: Das é in héllo ist schon zwei Bytes, c3 a9, und die Kodierung trägt sie einfach mit:
printf 'h\xc3\xa9llo' | base64
Das gibt aMOpbGxv aus, und ein UTF-8-Konsument auf der anderen Seite bekommt héllo wieder, Byte für Byte. Die Schwierigkeit beginnt, wenn die Quelle kein UTF-8 ist. Eine Latin-1-Datei mit demselben Wort hält das einzelne Byte e9 für das é, und diese Bytes geradeaus zu kodieren, produziert Text, den nur ein Latin-1-Konsument zurücklesen kann. Erst konvertieren, dann kodieren:
iconv -f ISO-8859-1 -t UTF-8 note.txt | base64 -w 0
Zwei weitere Byte-Ebene-Fakten. Ein UTF-8-BOM, drei Bytes am Anfang einer Datei, kodiert zu 77u/ und wird für immer am Anfang Ihrer dekodierten Ausgabe sitzen, außer Sie streifen ihn zuerst:
sed '1s/^\xef\xbb\xbf//' file.txt | base64 -w 0
Und die Locale ändert nie die Kodierung selbst, denn der Kodierer ist eine Byte-Maschine, sie ändert nur, was Sie getippt haben. Wenn die Ausgabe falsch aussieht, prüfen Sie die Bytes, die Sie gefüttert haben, nicht die Kodierung, die Sie ausgeführt haben.
E-Mail, APIs und Uploads
E-Mail ist der Ort, an dem Base64 seine Manieren gelernt hat, und die Manieren sind immer noch die Konvention. SMTP trug historisch nur 7-Bit-ASCII, also reisen Anhänge als Base64, umgebrochen bei 76 Zeichen mit CRLF-Zeilenenden, gemäß RFC 2045. Diese exakte Form für einen MIME-Teil zu produzieren ist der Umbruch plus die Zeilenende-Konvertierung:
base64 -w 76 attachment.bin | sed 's/$/\r/' > attachment.mime
Die alte Garde ist auf Embedded-Systemen immer noch im Dienst: Das uuencode von BusyBox mit dem -m-Flag erzeugt MIME-Base64, eingefasst in das vertraute begin-base64-Framing, und sein Bruder uudecode liest es zurück:
busybox uuencode -m photo.jpg < photo.jpg > photo.uu
APIs und Uploads benutzen dieselbe Idee in JSON-Kleidung: Das Binary wird zu einem Base64-String in einem JSON-Feld, und curl trägt es. Den Body in einer Shell-Variablen zu bauen, hält das Quoting ehrlich:
body="{\"file\":\"$(base64 -w 0 upload.bin)\"}"
curl -fsS -X POST https://httpbin.org/post -H "Content-Type: application/json" -d "$body"
Zwei Interoperabilitäts-Fallen leben hier. Erstens, prüfen Sie, welches Alphabet die API will: Einige erwarten Standard-Base64, einige den URL-sicheren Dialekt, und ein String mit +-Zeichen, der an einen URL-sicheren Endpunkt geschickt wird (oder umgekehrt), schlägt bei der Validierung fehl oder, noch schlimmer, dekodiert zu den falschen Bytes. Zweitens, achten Sie auf Doppel-Kodierung, der klassische Bug, bei dem ein Skript einen Wert kodiert und der Server ihn erneut kodiert, und der Round-Trip zwei Dekodierungen braucht, um ihn aufzuwickeln.
Wenn der Payload groß wird
Der Kodierer ist, wie der Dekodierer, eine Streaming-Maschine: Er liest in Chunks und schreibt in Chunks, also braucht ein 10-GB-Tarball nicht 13 GB RAM, und das Kommando läuft fröhlich Minutenlang auf großen Inputs mit flachem Speicherbedarf. Die Größen-Mathematik ist das einzige Planungswerkzeug, das Sie brauchen: Die Ausgabe ist vier Zeichen pro drei Eingabe-Bytes, plus ein Byte pro umgebrochener Zeile, also wird eine 300-MB-Datei zu rund 400 MB Text. Für einen schnellen Realitäts-Check auf jede Datei:
base64 -w 0 big.bin | wc -c
Wenn der Text selbst durch einen Kanal mit Größen-Grenze muss (eine E-Mail-Anhang-Grenze, ein Ticket-System, eine IM-Nachricht), teilen Sie die kodierte Form, nie das rohe Binary, so dass jedes Chunk noch gewöhnlicher Text ist, den Sie einfügen, komprimieren oder weiterleiten können:
base64 -w 0 big.bin | split -b 4000 - part_
Das produziert eine Reihe von 4000-Zeichen-Parts, der Empfänger cats sie in der richtigen Reihenfolge wieder zusammen und dekodiert einmal. Und wenn der Payload komprimierbar ist, komprimieren Sie vor der Kodierung, denn Base64 fügt Redundanz zu dem hinzu, was die Daten schon enthalten: Ein Tarball eines Projekt-Verzeichnisses schrumpft typischerweise um das Mehrfache unter gzip, bevor der 33-Prozent-Base64-Aufschlag angewendet wird:
tar czf - project/ | base64 -w 0 > project.b64
Tempo wird nicht Ihre Grenze sein. Diese Kodierer schieben Gigabytes in deutlich unter einer Sekunde auf einer modernen Maschine, eine 200-MB-Datei braucht ungefähr einen Zehntel einer Sekunde mit den coreutils- und OpenSSL-Implementierungen, und selbst BusyBox, der langsamste der gängigen, ist immer noch in einem Bruchteil einer Sekunde fertig (gemessen bei ungefähr einem Viertel einer Sekunde für 200 MB auf einer modernen Maschine, ein paar Mal langsamer als coreutils, aber weit davon entfernt, ein Engpass zu sein). Der Engpass in echten Pipelines ist fast immer das Netzwerk, nicht die Kodierung.
Die kleinen Zeichen, die beißen
Die Fallen der Kodierungs-Seite sind kleiner als die der Dekodierungs-Seite, und das ist nur fair:
| Falle | Was passiert | Die Lösung |
|---|---|---|
echo füttert den Kodierer |
ein abschließendes Zeilenende reitet in die Ausgabe, und das letzte Zeichen kodiert es | printf '%s' für Text, bei dem die Anzahl der Bytes zählt |
| auf den Default-Umbruch verlassen | je nach Werkzeug 76, 64 oder null. Ein Ein-Zeilen-Konsument erstickt an umgebrochenem Input | explizit -w 0 setzen (oder die Breite, die der Konsument will) |
| ein abschließendes Zeilenende in der Ausgabe | Zeilen-Umbruch-Modi enden mit einem Zeilenende, das URLs und JSON verunreinigt, wenn es eingefangen wird | -w 0 für eine Zeile, oder per $(...) einfangen, das streicht es |
+ oder / in einer URL |
Plus wird in einem Query-String als Leerzeichen gelesen. Beide erzwingen Percent-Encoding | den URL-sicheren Dialekt für alles benutzen, was in eine URL eintritt |
verwechselte tr-Richtung |
der Tausch produziert valide, aber falsche Bytes, nirgends ein Fehler | Kodierung ist tr '+/' '-_', Dekodierung ist tr '_-' '/+' |
| einen bereits kodierten Wert kodieren | Doppel-Kodierung, die zwei Dekodierungen braucht, um sie aufzuwickeln | prüfen, ob die Quelle schon Base64 ist, bevor Sie kodieren |
| ein UTF-8-BOM im Input | drei zusätzliche Bytes am Anfang jeder dekodierten Ausgabe | das BOM zuerst streichen: sed '1s/^\xef\xbb\xbf//' |
| ein echtes Secret als Base64 speichern | ein Kommando macht es rückgängig. Der RFC dokumentiert echte Fälle von geleakten Credentials | verschlüsseln für Geheimhaltung, Base64 nur für die Transport-Form |
| das Alphabet des Konsumenten annehmen | Fehlpassung zwischen Standard und URL-sicher scheitert bei der Validierung oder dekodiert falsch | die API-Doku lesen, in dem Dialekt kodieren, den der Konsument verlangt |
Gewohnheiten, die Sie sicher halten
- Die Anzahl der Bytes benennen.
printf '%s'für Text, dasFILE-Argument für Dateien, und einwc -c-Sanity-Check, bevor Sie irgendetwas verschicken, bei dem die Größe zählt. - Den Umbruch explizit setzen.
-w 0für URLs und JSON,-w 76für MIME,-w 64für PEM. Nie die Breite dem Default des Werkzeugs überlassen. - Das Alphabet für das Ziel wählen. Standard für E-Mail und Dateien, URL-sicher für Tokens und URLs, und die Doku des Konsumenten vor dem Kodieren prüfen.
- Komprimieren, bevor Sie kodieren. Für jeden komprimierbaren Payload zuerst
gzipodertar czf. Der 33-Prozent-Aufschlag gilt für alles, was Sie dem Kodierer geben. - Den Text teilen, nicht das Binary. Wenn eine Größen-Grenze im Weg ist,
splitdie kodierte Form, so dass jedes Chunk paste-sicher bleibt, und in der richtigen Reihenfolge wieder zusammensetzen, bevor das eine Dekodieren. - Die drei JWT-Jobs getrennt halten. Alphabet, Kryptographie, Format: die Segmente kodieren, den ASCII-Text der verbundenen Segmente signieren, dann ausgeben. Vertauschen Sie sie, und das Token bricht.
- Base64 nie für Verschlüsselung einspringen lassen. Wenn der Wert ein Secret ist, verschlüsseln Sie ihn und kodieren Sie dann den Chiffretext. Wenn er kein Secret ist, sagen Sie es und machen Sie sich keine Sorgen mehr.
Eine kurze Geschichte der Kodierung in der Shell
- 1980, Berkeley. Mary Ann Horton schreibt
uuencodeunduudecodean der University of California, Berkeley, um Binary-Files durch E-Mail zwischen Unix-Systemen zu tragen. Der Name, "Unix-to-Unix encoding", ist die Geburtsurkunde des Formats, und in dem Jahrzehnt oder so danach ist das, womit Shell-Nutzer kodieren. - Das Dial-up-Zeitalter. uuencode auf UNIX und BinHex auf dem TRS-80 und dem Apple II, mit dem Macintosh einen Schritt dahinter, lösen dasselbe Problem mit verschiedenen Alphabeten, jede vertraut nur den Zeichen, die ihr eigenes Terminal drucken kann.
- 1993. MIME standardisiert Base64 für E-Mail in RFC 1521, später RFC 2045, mit dem 76-Zeichen-Zeilenumbruch, den der coreutils-Default bis heute trägt.
- Vor 2006 auf Linux. Es gibt kein
base64-Kommando. Shell-Skripte greifen zuopenssl base64,uuencode -m, Perl oder Python, und die OpenSSL-Gewohnheit ist so tief, dass die Hälfte der alten One-Liner in der Wildnis immer noch damit anfängt. - 15. August 2006. coreutils 6.0 liefert das
base64-Kommando aus, und seine NEWS-Datei nennt es "Funktionalität für base64-Kodierung und -Dekodierung (RFC 3548)", und das Ein-Kommando-Zeitalter beginnt. Ein paar Monate später, im Oktober 2006, formalisiert RFC 4648 die Alphabet-Familie, inklusive des URL-sicheren Dialekts, zu dem dieser Artikel immer wieder greift. - OS X 10.7. macOS liefert sein eigenes
base64aus, die BSD-Variante ohne Default-Umbruch, und deshalb braucht "einfach base64 ausführen" in portablen Skripten einen Plattform-Check. - 2024. coreutils 9.5 ändert, wie Dekodierer ungepolsterten und nicht-kanonischen Input behandeln, was in der Praxis bedeutet, dass Kodierer einen freien Durchgang bekommen: Ausgabe, die ältere GNU-Versionen abgelehnt hätten, dekodiert jetzt sauber. Die Kodierungs-Seite des Formats ist die stabile, und die Dekodierer sind die, die sich bewegt haben.
- 2025. Das Rust-Rewrite von coreutils (uutils) wird der Standard auf den aktuellen Ubuntu-Releases. Gleiches Kommando, gleiche Flags, ein neuer Motor und derselbe 76-Zeichen-Default, den es von der C-Version geerbt hat.
Kleine Wunder
- Der Name des Formats ist auf jeder Maschine wahr.
printf 'base64' | base64ergibtYmFzZTY0auf GNU, uutils, BusyBox, OpenSSL und macOS gleichermaßen. Das ist seit 2006 wahr und wird es immer sein. - Eine Datei aus nichts kodiert zu einer Wand aus A. Füttern Sie ihr drei NUL-Bytes, und die Ausgabe ist
AAAA, denn drei nullwertige Bytes mappen auf vier null-Indizes im Alphabet, die jeweils durch A repräsentiert werden. Eine.b64-Datei, die mit einer langen Kette aus A's anfängt, ist meistens Null-Padding in der Originaldatei (NUL-Bytes), kein Geheimnis. - Die 33-Prozent-Steuer kennt keine Ermäßigungen. Vier Zeichen pro drei Bytes, keine Komprimierung, keine zweite Chance. Der einzige Ausweg ist, die Daten zuerst zu komprimieren, und deshalb ist
tar czfder echte Held der großen-Payload-Pipelines. - Zwei Zeichen haben das ganze URL-Problem verursacht.
+und/sind die einzigen Alphabet-Mitglieder, die jemals einen Ersatz brauchten, und ein ganzer Dialekt des Formats existiert, um sie in den Ruhestand zu schicken. Zweiundsechzig und dreiundsechzig, die letzten beiden Plätze des Alphabets. - Elf Zeichen, sechzig-vier Bits. Eine YouTube-Video-ID ist ein elf Zeichen langer base64url-String, eine 64-Bit-Zahl in URL-Kleidung, und deshalb reist sie durch URLs, ohne ein einziges Prozent-Zeichen.
- Git's berühmtester Impersonator. Die Binary-Blöcke in
git diff --binarysehen aus wie Base64, aber diez-präfixierten Zeilen sind ein base85-artiger Dialekt für sich. Ein Blick, und Sie wissen, dass es nicht Ihr Alphabet ist, ein grep-and-decode-Ausflug, und Sie verlieren zwanzig Minuten. - Jedes Werkzeug umbreicht anders, und das ist Absicht. 76 für MIME, 64 für PEM, null beim BSD-Werkzeug: drei Defaults, drei geerbte Konventionen, ein Format. Die Breite war immer in Ihrer Hand, die Werkzeuge haben sich nur verschiedene Defaults gemerkt.
- Der Kodierer scheitert nie an Ihren Daten. Im Gegensatz zu seinem Dekodierungs-Vetter hat der Kodierer keinen ungültigen Input, keine Korruption, keinen strengen Modus. Er nimmt Bytes und gibt Buchstaben, jedes Mal. Die Bugs in diesem Artikel liegen alle in den Bytes, die Sie ihm geben, und im Ziel, an das Sie sie schicken.
Und wenn die Reise die andere Richtung zeigt, wenn ein langer String aus Buchstaben, Ziffern und dem gelegentlichen Strich oder Unterstrich in Ihrem Terminal landet und Sie die Bytes zurück brauchen, deckt der verlinkte Base64-Dekodierungsartikel unten diesen Ritus in derselben Tiefe ab, von ungepolsterten JWT-Segmenten bis zu jeder Zeilenenden-Falle, die die Dekodierer verstecken.
Zuletzt aktualisiert: 2026-09-08
Verwandter Artikel: Base64-Dekodierung in Bash: Ein vollständiger Leitfaden