base64

package module
v0.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 0 Imported by: 0

README

base64

Códec base64 (RFC 4648) con cero dependencias — ni stdlib ni tinywasm/* — pensado para binarios WASM del edge (Cloudflare Workers, goflare) compilados con TinyGo.

Por qué existe

encoding/base64 sí es compatible con TinyGo. Este paquete no se justifica por compatibilidad sino por tamaño: base64 es una tabla de lookup y unos desplazamientos de bits, y la versión del stdlib arrastra bastante más de lo que esa tarea necesita.

Medido con TinyGo 0.41.1 (-target wasm), el mismo programa mínimo que codifica y decodifica una cadena:

Implementación Binario .wasm
encoding/base64 154 115 bytes
tinywasm/base64 122 967 bytes
ahorro 31 148 bytes (20 %)
La regla que hay detrás: cero imports o no compensa

La primera versión de este paquete importaba tinywasm/fmt solo para declarar su error. El resultado fue 74 KB más grande que el stdlib: la dependencia costaba cuatro veces más que todo lo que el códec ahorraba.

Por eso el error se declara con un tipo propio y el paquete no importa nada:

type invalidError struct{}

func (invalidError) Error() string { return "base64 invalid" }

var ErrInvalid error = invalidError{}

Un paquete de utilidad para el edge solo compensa si es de cero dependencias. Si alguna vez hay que importar algo aquí, hay que volver a medir: puede dejar de tener sentido.

API

// base64url (RFC 4648 §5), SIN padding — la codificación que usa JWT.
// Equivale a encoding/base64.RawURLEncoding.
func URLEncode(src []byte) string
func URLDecode(s string) ([]byte, error)

// base64 estándar (RFC 4648 §4), CON padding — equivale a StdEncoding.
func Encode(src []byte) string
func Decode(s string) ([]byte, error)

var ErrInvalid error

// Alfabeto configurable — p. ej. bcrypt.
type Encoding struct { /* ... */ }

func NewEncoding(alphabet string, pad bool) (*Encoding, error)
func (e *Encoding) Encode(src []byte) string
func (e *Encoding) Decode(s string) ([]byte, error)
func (e *Encoding) EncodedLen(n int) int
func (e *Encoding) DecodedLen(n int) int

type Error string

const (
	ErrAlphabetLength    = Error("base64: el alfabeto debe tener exactamente 64 caracteres")
	ErrAlphabetDuplicate = Error("base64: el alfabeto tiene caracteres repetidos")
	ErrAlphabetNonASCII  = Error("base64: el alfabeto sólo admite ASCII")
	ErrInvalidCharacter  = Error("base64: carácter no válido en la entrada")
	ErrInvalidLength     = Error("base64: longitud de entrada no válida")
)

Encode/Decode y URLEncode/URLDecode son envoltorios sin estado sobre dos *Encoding pre-construidos; NewEncoding es el motor genérico que precalcula la tabla inversa y comparte el mismo bucle de bits.

Uso

package main

import (
	"fmt"

	"github.com/tinywasm/base64"
)

func main() {
	s := base64.URLEncode([]byte("hello"))
	fmt.Println(s) // aGVsbG8

	b, err := base64.URLDecode(s)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b)) // hello
}

// Alfabeto propio (bcrypt: "./A-Za-z0-9" sin relleno)
func Example_bcrypt() {
	bcryptAlphabet := "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	enc, err := base64.NewEncoding(bcryptAlphabet, false)
	if err != nil {
		panic(err)
	}
	s := enc.Encode([]byte("hello"))
	println(s)

	b, err := enc.Decode(s)
	if err != nil {
		panic(err)
	}
	println(string(b))
}

Garantías

  • Codifica idéntico al stdlib (RawURLEncoding); decodifica como RawURLEncoding.Strict() — deliberadamente más estricto que el stdlib por defecto, que acepta codificaciones no canónicas.
  • Vectores RFC 4648 §10, no solo round-trips: un round-trip pasa igual aunque las dos direcciones estén mal del mismo modo.
  • URL-safe: la salida nunca contiene +, / ni = (usa - y _ para los índices 62 y 63).
  • Estricto al decodificar: rechaza padding, alfabeto estándar, espacios y cualquier byte fuera del alfabeto. Decodifica tokens: ser permisivo significaría aceptar una firma que el emisor nunca generó.
  • Solo canónico (RFC 4648 §3.5): los bits sobrantes del último grupo deben ser cero. Sin esta comprobación, "Zg" y "Zh" decodifican ambos a "f" — varias grafías para los mismos bytes, es decir, malleabilidad. Lo destapó la auditoría de seguridad de tinywasm/jwt (hallazgo I-1).
  • Sin map: la tabla de decodificación es un [256]byte.

Tests

go install github.com/tinywasm/devflow/cmd/gotest@latest
gotest           # nativo + wasm (compilador de Go)
gotest -tinygo   # suite WASM compilada con TinyGo real

Patrón dual: la lógica vive en RunBase64Tests (shared_test.go) y los dos puntos de entrada (backStlib_test.go con !wasm, frontWasm_test.go con wasm) delegan en ella.

Documentation

Overview

Package base64 implements the base64 codec (RFC 4648) without the Go standard library.

It exists because `encoding/base64` costs a measured 18,740 bytes in a TinyGo wasm binary — real weight on the edge (Cloudflare Workers, goflare) for a transformation that is a lookup table and some bit shifting. The stdlib is TinyGo-compatible; this package is about size, not compatibility.

Index

Constants

View Source
const (
	ErrAlphabetLength    = Error("base64: el alfabeto debe tener exactamente 64 caracteres")
	ErrAlphabetDuplicate = Error("base64: el alfabeto tiene caracteres repetidos")
	ErrAlphabetNonASCII  = Error("base64: el alfabeto sólo admite ASCII")
	ErrInvalidCharacter  = Error("base64: carácter no válido en la entrada")
	ErrInvalidLength     = Error("base64: longitud de entrada no válida")
)

Variables

View Source
var ErrInvalid error = invalidError{}

ErrInvalid is returned for any input that is not well-formed base64.

Functions

func Decode added in v0.0.4

func Decode(s string) ([]byte, error)

Decode decodes a padded standard base64 string (RFC 4648 §4), equivalent to the stdlib's StdEncoding.Strict(). Padding is required and its length must match the trailing group size; any '=' outside the final group — or any byte outside the standard alphabet — is rejected via the same canonicality rule URLDecode applies.

func Encode added in v0.0.4

func Encode(src []byte) string

Encode encodes src as standard base64 (RFC 4648 §4) WITH padding — equivalent to the stdlib's StdEncoding. This is what data URIs, MCP image content, and most JSON/HTTP payloads expect; use URLEncode instead for tokens embedded in a URL or a JWT segment.

func URLDecode added in v0.0.2

func URLDecode(s string) ([]byte, error)

URLDecode decodes an unpadded base64url string.

Every byte outside the alphabet is rejected, including '=', '+', '/' and whitespace, and so is any non-canonical encoding (RFC 4648 §3.5: the unused trailing bits of the final group must be zero). This decodes tokens, so leniency would mean accepting a signature segment the signer never produced. It is equivalent to the stdlib's RawURLEncoding.Strict() — deliberately stricter than the stdlib default, which accepts non-canonical input.

func URLEncode added in v0.0.2

func URLEncode(src []byte) string

URLEncode encodes src as base64url (RFC 4648 §5) WITHOUT padding.

Unpadded is what JWT uses (equivalent to the stdlib's RawURLEncoding). The output never contains '+', '/' or '='.

Types

type Encoding added in v0.0.5

type Encoding struct {
	// contains filtered or unexported fields
}

Encoding es un códec base64 con alfabeto propio. Se construye una vez y se reutiliza; NewEncoding precalcula la tabla inversa para que decodificar no tenga que recorrer el alfabeto por cada carácter.

func NewEncoding added in v0.0.5

func NewEncoding(alphabet string, pad bool) (*Encoding, error)

NewEncoding devuelve un códec sobre alphabet, que DEBE tener exactamente 64 caracteres ASCII distintos. pad indica si la salida lleva relleno '='.

func (*Encoding) Decode added in v0.0.5

func (e *Encoding) Decode(s string) ([]byte, error)

Decode decodifica s con el alfabeto del Encoding. Es estricta: rechaza caracteres fuera del alfabeto, longitudes imposibles, relleno incorrecto y codificaciones no canónicas (bits sobrantes no cero, RFC 4648 §3.5).

func (*Encoding) DecodedLen added in v0.0.5

func (e *Encoding) DecodedLen(n int) int

DecodedLen devuelve la longitud máxima en bytes de la decodificación de n bytes codificados. Para pad=true asume entrada con relleno; para pad=false asume entrada sin relleno.

func (*Encoding) Encode added in v0.0.5

func (e *Encoding) Encode(src []byte) string

Encode codifica src con el alfabeto del Encoding.

func (*Encoding) EncodedLen added in v0.0.5

func (e *Encoding) EncodedLen(n int) int

EncodedLen devuelve la longitud en bytes de la codificación de n bytes de entrada.

type Error added in v0.0.5

type Error string

Error es un error de base64 sin dependencias. El paquete presume de cero imports (ver README: importar tinywasm/fmt cuesta 74 KB en TinyGo) y por eso no usa fmt.Errorf ni errors.New.

func (Error) Error added in v0.0.5

func (e Error) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL