Charger un fichier
  1. base64hub
  2. Base64 dans le code
  3. Go (Golang)
Code

Base64 en Go

Le paquet encoding/base64 de Go propose quatre encodages prêts à l’emploi et des enveloppes pour les flux. L’essentiel du travail consiste à choisir le bon des quatre. Les sorties ci-dessous proviennent de Go 1.25.

Encoder et décoder une chaîne

Les chaînes Go sont déjà en UTF-8 : une conversion en []byte suffit.

package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	enc := base64.StdEncoding.EncodeToString([]byte("héllo wörld"))
	fmt.Println(enc) // aMOpbGxvIHfDtnJsZA==

	dec, err := base64.StdEncoding.DecodeString(enc)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(dec)) // héllo wörld
}

Vérifiez toujours err. En cas d’échec, DecodeString peut renvoyer les octets décodés jusque-là en même temps que l’erreur : utiliser le résultat sans contrôle vous donne des données tronquées sans le moindre avertissement.

Les quatre encodages : Std, URL, Raw

VariableAlphabetRemplissage<<???>> s’encode en
StdEncoding+ /ouiPDw/Pz8+Pg==
URLEncoding- _ouiPDw_Pz8-Pg==
RawStdEncoding+ /nonPDw/Pz8+Pg
RawURLEncoding- _nonPDw_Pz8-Pg
d := []byte("<<???>>")
base64.URLEncoding.EncodeToString(d)    // PDw_Pz8-Pg==
base64.RawURLEncoding.EncodeToString(d) // PDw_Pz8-Pg

b, err := base64.RawURLEncoding.DecodeString("PDw_Pz8-Pg") // "<<???>>", nil

Le décodage est strict sur le remplissage, dans les deux sens. Les encodages avec remplissage rejettent une entrée qui n’en a pas, et les encodages raw rejettent = :

base64.StdEncoding.DecodeString("aGk")
// illegal base64 data at input byte 0
base64.RawURLEncoding.DecodeString("PDw_Pz8-Pg==")
// illegal base64 data at input byte 10

Si vous acceptez des entrées de plusieurs sources, retirez les = finaux avec strings.TrimRight(s, "=") et décodez avec un encodage Raw. Vous pouvez aussi créer des encodages personnalisés avec base64.NewEncoding(alphabet) et .WithPadding(base64.NoPadding). La page Base64 ou Base64URL explique où l’on rencontre chaque variante.

Encoder et décoder un fichier

data, err := os.ReadFile("hello.txt")
if err != nil {
	log.Fatal(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(data)) // aGVsbG8K

raw, err := base64.StdEncoding.DecodeString("aGVsbG8K")
if err != nil {
	log.Fatal(err)
}
os.WriteFile("copy.txt", raw, 0o644)

Flux avec NewEncoder et NewDecoder

Pour les gros fichiers, enveloppez un io.Writer ou un io.Reader. La consommation mémoire reste constante :

in, _ := os.Open("big.bin")
defer in.Close()
out, _ := os.Create("big.b64")
defer out.Close()

w := base64.NewEncoder(base64.StdEncoding, out)
if _, err := io.Copy(w, in); err != nil {
	log.Fatal(err)
}
if err := w.Close(); err != nil { // flushes the last partial block
	log.Fatal(err)
}

w.Close() ne ferme pas out : il écrit le ou les deux derniers octets et le remplissage. L’oublier est le bug Base64 classique en Go : la sortie a l’air correcte mais il lui manque jusqu’à quatre caractères. Le décodage est symétrique :

r := base64.NewDecoder(base64.StdEncoding, f)
io.Copy(dst, r)

Pour un fichier de test de 300 Ko, les résultats en flux et en mémoire étaient identiques. Le décodeur ignore \r et \n et lit donc directement une entrée découpée au format MIME. Pour calculer les tailles de tampon à l’avance, EncodedLen(5) renvoie 8 et RawStdEncoding.EncodedLen(5) renvoie 7 ; le guide du surcoût de taille donne la formule correspondante.

Go 1.22 a ajouté AppendEncode et AppendDecode, qui ajoutent le résultat à une slice existante. Pratique pour les en-têtes :

dst := base64.StdEncoding.AppendEncode([]byte("Basic "), []byte("user:pass"))
fmt.Println(string(dst)) // Basic dXNlcjpwYXNz

Le générateur d’en-tête Basic Auth construit la même valeur dans le navigateur.

Validation et CorruptInputError

Toute erreur de décodage est une base64.CorruptInputError, un int64 qui donne la position du premier octet invalide :

_, err := base64.StdEncoding.DecodeString("PDw_Pz8-Pg==")
var ce base64.CorruptInputError
if errors.As(err, &ce) {
	fmt.Println(err) // illegal base64 data at input byte 3
}

Résultats obtenus avec StdEncoding :

EntréeErreur
PDw_Pz8-Pg==illegal base64 data at input byte 3 (le _)
aGkillegal base64 data at input byte 0
aGk=!!illegal base64 data at input byte 4
aGk==illegal base64 data at input byte 4
aGVs bG8Killegal base64 data at input byte 4 (espace)
aGl=pas d’erreur, renvoie hi
"aGVs\nbG8K"pas d’erreur, saut de ligne ignoré

aGl= a des bits de remplissage non nuls. Pour rejeter ce genre d’entrée non canonique, utilisez .Strict() :

_, err = base64.StdEncoding.Strict().DecodeString("aGl=")
// illegal base64 data at input byte 3

Le validateur Base64 met en évidence les mêmes positions ; les erreurs Base64 courantes donnent les causes habituelles.

Pièges

  • Décoder les parties d’un JWT avec StdEncoding. Les jetons sont en Base64URL sans remplissage. Utilisez RawURLEncoding, ou inspectez d’abord le jeton avec le décodeur JWT.
  • Ignorer le résultat partiel. "aGk=!!" renvoie "hi" et une erreur. N’utilisez pas les octets quand err != nil.
  • Oublier Close() sur l’encodeur. Le dernier bloc est perdu.
  • Les espaces d’un copier-coller. Le décodeur n’ignore que \r et \n. Supprimez d’abord les autres espaces avec strings.Join(strings.Fields(s), "").

Notes de version

  • RawStdEncoding et RawURLEncoding : Go 1.5.
  • Strict() : Go 1.8.
  • AppendEncode, AppendDecode : Go 1.22.
  • Le paquet n’a pas d’encodeur MIME avec découpage des lignes : les paquets mime et net/mail gèrent l’e-mail, sinon insérez vous-même \r\n tous les 76 caractères.

FAQ

Quelle est la différence entre URLEncoding et RawURLEncoding ?

Les deux utilisent l’alphabet URL-safe avec - et _. URLEncoding écrit le remplissage = et l’exige au décodage ; RawURLEncoding l’omet et le rejette. Les JWT utilisent RawURLEncoding.

Que signifie « illegal base64 data at input byte 0 » ?

C’est une base64.CorruptInputError, et le nombre indique la position où le décodage a échoué. À l’octet 0 avec une chaîne courte, cela signifie en général que la longueur est incorrecte, souvent à cause d’un remplissage manquant ; utilisez l’encodage Raw pour une entrée sans remplissage.

Le décodeur Base64 de Go ignore-t-il les sauts de ligne ?

Oui. Les quatre encodages ignorent \r et \n : une entrée découpée au format MIME se décode. Les espaces et les autres caractères provoquent une erreur.

Continuer la lecture