Cómo codificar y decodificar Base64: online, terminal, JavaScript, Python y archivos (PDF, imágenes)

Base64 convierte bytes en 64 caracteres ASCII seguros para que los datos binarios puedan viajar por canales de solo texto: JSON, correo, cabeceras HTTP, data URIs o variables de entorno. Codificar y decodificar es una sola llamada en cualquier plataforma. Recuperar exactamente lo que entró depende de tres cosas: qué bytes representan tu texto, qué alfabeto Base64 se usó y si se añadieron saltos de línea o relleno por el camino.

Decodificar y codificar Base64 online

Pega un texto para codificarlo o un string Base64 para decodificarlo. Un buen decodificador indica si el resultado es texto UTF-8 legible o datos binarios, como una imagen, un PDF o un archivo comprimido, y te deja descargarlos en lugar de mostrarlos como caracteres ilegibles.

Mucha gente busca "desencriptar Base64", pero no hay nada que desencriptar. Base64 no tiene clave: cualquiera puede decodificarlo, y por eso nunca debe usarse para ocultar contraseñas ni tokens. Por la misma razón, usa un decodificador que funcione en el navegador sin subir la entrada cuando el string pueda contener credenciales, como una cabecera Authorization o un Secret de Kubernetes.

texto    : Hola, DevToolGrid!
base64   : SG9sYSwgRGV2VG9vbEdyaWQh

texto    : café
base64   : Y2Fmw6k=          (UTF-8: la é son dos bytes, C3 A9)

En la terminal: Linux, macOS y Windows

# Linux (GNU coreutils)
printf '%s' 'Hola' | base64             # SG9sYQ==
printf '%s' 'SG9sYQ==' | base64 -d      # Hola
base64 -w0 foto.jpg > foto.b64          # -w0: sin saltos de línea
base64 -d foto.b64 > foto.jpg

# macOS (las versiones antiguas usan -D para decodificar)
base64 -d -i foto.b64 -o foto.jpg

# Windows PowerShell
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('Hola'))
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('SG9sYQ=='))

Dos trampas de la terminal causan la mayoría de los resultados incorrectos. echo añade un salto de línea, así que echo Hola | base64 da SG9sYQo=, la codificación de Hola\n; usa printf '%s'. Y el base64 de GNU corta la salida cada 76 caracteres, lo que rompe data URIs, valores JSON y variables de entorno; añade -w0.

Convertir Base64 a PDF o a imagen, y al revés

Un PDF o una imagen en Base64 son simplemente los bytes del archivo codificados. Para convertir Base64 a PDF hay que decodificar a bytes y guardarlos en un archivo con la extensión correcta, sin pasar nunca por texto.

# Base64 a PDF en Linux o macOS
base64 -d documento.b64 > documento.pdf

# Si viene como data URI, quita primero el prefijo
sed 's/^data:[^,]*,//' documento.txt | base64 -d > documento.pdf

# Imagen a Base64 (una sola línea, lista para un data URI)
echo "data:image/png;base64,$(base64 -w0 logo.png)"
import base64
with open('documento.pdf', 'wb') as f:          # 'wb': escribir bytes
    f.write(base64.b64decode(cadena_b64))

Comprueba el resultado por sus primeros bytes: un PDF empieza por %PDF (en Base64, JVBER), un PNG por \x89PNG (iVBOR) y un JPEG por FF D8 FF (/9j/). Si el archivo guardado no abre, casi siempre se leyó o escribió como texto en algún paso.

En JavaScript: navegador y Node.js

btoa() y atob() son anteriores al soporte de Unicode en la web. Tratan cada carácter como un byte y lanzan InvalidCharacterError con cualquier carácter fuera de Latin-1, lo que incluye la mayoría de los emojis. Convierte primero el texto a bytes UTF-8.

// Navegador: seguro con UTF-8
const codificar = (texto) =>
  btoa(String.fromCharCode(...new TextEncoder().encode(texto)));
const decodificar = (b64) =>
  new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));

codificar('café 😀');                 // 'Y2Fmw6kg8J+YgA=='
decodificar('Y2Fmw6kg8J+YgA==');      // 'café 😀'

// Node.js: Buffer maneja UTF-8 y binario
Buffer.from('café', 'utf8').toString('base64');          // 'Y2Fmw6k='
Buffer.from('Y2Fmw6k=', 'base64').toString('utf8');      // 'café'

Los navegadores recientes (Baseline desde septiembre de 2025) incluyen además Uint8Array.fromBase64() y toBase64(), que trabajan directamente con bytes.

En Python y PHP

import base64
base64.b64encode('café'.encode('utf-8')).decode('ascii')   # 'Y2Fmw6k='
base64.b64decode('Y2Fmw6k=').decode('utf-8')               # 'café'
base64.b64decode(s, validate=True)                          # rechaza caracteres no válidos
<?php
echo base64_encode('café');                     // Y2Fmw6k=
echo base64_decode('Y2Fmw6k=');                  // café
var_dump(base64_decode('no*base64', true));      // false: modo estricto

Por defecto, base64_decode de PHP y b64decode de Python ignoran los caracteres fuera del alfabeto. Un string corrupto se decodifica en bytes ligeramente incorrectos en lugar de dar error. Usa el modo estricto (true en PHP, validate=True en Python) cuando la entrada venga de fuera.

Por qué el texto decodificado sale ilegible

Base64 restaura los bytes exactos, pero no dice qué significan. Si el resultado se ve mal, los bytes están bien y la interpretación no.

Caracteres raros como café indican bytes UTF-8 leídos como Latin-1: decodifica como UTF-8. Un resultado que empieza por %PDF, PK, \x89PNG o \xFF\xD8 es un PDF, un ZIP (incluidos DOCX y XLSX), un PNG o un JPEG: guárdalo como archivo. Si empieza por \x1F\x8B está comprimido con gzip y hay que descomprimirlo después.

Si decodificar falla del todo, revisa si se usa el alfabeto URL-safe (- y _ en lugar de + y /), si falta el relleno =, si hay espacios o saltos de línea copiados, si sigue pegado un prefijo data:…;base64, o si los + se convirtieron en espacios al pasar por una URL.

Dónde te encuentras Base64 en el día a día

Kubernetes guarda los valores de los Secrets codificados en Base64, y a menudo se confunde esa codificación con protección. kubectl get secret db -o jsonpath='{.data.password}' | base64 -d muestra el valor a cualquiera con permiso de lectura, así que limita quién puede leer Secrets y activa el cifrado en reposo.

JSON no tiene tipo binario, por eso las API que transportan archivos, imágenes o firmas los envían como strings Base64; revisa en la documentación qué alfabeto usan y si incluyen relleno. Los adjuntos de correo son Base64 dentro de partes MIME, con líneas de 76 caracteres. Y las variables de entorno y secretos de CI suelen guardar certificados o claves de cuentas de servicio en Base64, porque los archivos originales tienen saltos de línea que muchos sistemas manejan mal.

# CI: guardar un archivo de clave como una sola línea y restaurarlo en el job
base64 -w0 cuenta-servicio.json            # pega la salida en el secreto del CI
printf '%s' "$CLAVE_B64" | base64 -d > cuenta-servicio.json

Fuentes y lecturas recomendadas

RFC 4648 define Base64, Base64url y el relleno. RFC 2045 define la variante MIME con líneas de 76 caracteres. MDN documenta btoa(), atob(), Uint8Array.fromBase64() y toBase64(). El manual de GNU coreutils cubre base64 -w, y la documentación de base64 en Python y de base64_decode en PHP cubre la decodificación estricta.

Frequently asked questions

¿Cómo decodifico Base64?

Pega el string en un decodificador Base64, o ejecuta `printf '%s' 'SG9sYQ==' | base64 -d` en Linux o macOS. En código usa `Buffer.from(s, 'base64')` en Node.js, `base64.b64decode(s)` en Python o `base64_decode($s)` en PHP, y decodifica los bytes como UTF-8 si son texto.

¿Se puede desencriptar Base64?

No hay nada que desencriptar: Base64 es una codificación, no un cifrado, y no tiene clave. Cualquiera puede decodificarlo en un paso, así que nunca lo uses para proteger contraseñas o secretos.

¿Cómo convierto Base64 a PDF?

Decodifica el string a bytes y guárdalos en un archivo `.pdf` sin pasar por texto: `base64 -d archivo.b64 > archivo.pdf`. Si empieza por `data:application/pdf;base64,`, quita antes ese prefijo.

¿Cómo convierto una imagen a Base64?

Lee la imagen como bytes y codifícalos: `base64 -w0 imagen.png` en Linux, `FileReader.readAsDataURL()` en el navegador o `base64.b64encode(open(ruta, 'rb').read())` en Python.

¿Por qué btoa() da error con mi texto?

`btoa()` solo acepta caracteres del rango Latin-1. Convierte primero el texto a bytes UTF-8 con `TextEncoder` y codifica esos bytes.

¿Por qué Base64 ocupa más que el original?

Cada 3 bytes se convierten en 4 caracteres, así que el resultado es alrededor de un 33 % más grande, más el relleno. Los codificadores MIME además añaden un salto de línea cada 76 caracteres.