Subir un archivo
  1. base64hub
  2. Base64 en código
  3. OpenSSL
Código

Base64 con OpenSSL

openssl base64 está disponible en casi cualquier máquina Linux, macOS y BSD, y se comporta igual en todas. También falla sin avisar. Las salidas de esta página son de OpenSSL 3.5.

Codificar y decodificar una cadena

printf '%s' 'héllo wörld' | openssl base64        # aMOpbGxvIHfDtnJsZA==
echo 'aMOpbGxvIHfDtnJsZA==' | openssl base64 -d   # héllo wörld

openssl base64 es una forma abreviada de openssl enc -base64; las dos admiten las mismas opciones. Usa printf '%s' al codificar para que no se cuele un salto de línea en los datos, y echo al decodificar, por el motivo que se explica a continuación.

La trampa del salto de línea final y -A

Por defecto, OpenSSL procesa el Base64 como líneas de texto terminadas en salto de línea. Al decodificar, ignora una última línea sin \n, así que esto no imprime absolutamente nada:

printf 'aGVsbG8K' | openssl base64 -d             # (no output)
printf 'aGVsbG8K\n' | openssl base64 -d           # hello
printf 'aGVsbG8K' | openssl base64 -d -A          # hello

-A le dice a OpenSSL que trate toda la entrada como una sola línea. Úsalo en ambos sentidos:

  • Al codificar: sin -A, la salida se corta a 64 caracteres por línea. Con -A obtienes una sola línea, que es lo que necesitan las cabeceras HTTP, JSON y las variables de entorno.
  • Al decodificar: con -A, la entrada debe ser una sola línea sin saltos. Sin -A, las entradas de varias líneas, como el cuerpo de un PEM, se decodifican sin problema.
head -c 60 /dev/zero | tr '\0' x | openssl base64      # 64 chars, newline, 16 chars
head -c 60 /dev/zero | tr '\0' x | openssl base64 -A   # 80 chars on one line

El corte a 64 caracteres corresponde al formato PEM (RFC 7468), no a MIME, que usa hasta 76. Para una salida MIME encajan mejor el codificador Base64 MIME o GNU base64 (76 por defecto).

Base64 URL-safe

OpenSSL no tiene modo Base64URL. Traduce con tr:

printf '%s' '<<???>>' | openssl base64 -A | tr '+/' '-_' | tr -d '='
# PDw_Pz8-Pg

Para decodificar, invierte la correspondencia y restaura el relleno; la página Base64 en Bash tiene un bucle que lo hace. OpenSSL ignora sin avisar - y _, como se ve más abajo, así que nunca le pases directamente una entrada URL-safe. Base64 frente a Base64URL explica la diferencia.

Codificar y decodificar archivos

openssl base64 -in photo.jpg -out photo.b64
openssl base64 -d -in photo.b64 -out photo-copy.jpg

OpenSSL trabaja en flujo, así que los archivos grandes no son un problema. Un archivo aleatorio de 100 KB sobrevivió a la ida y vuelta byte a byte. El archivo codificado tiene líneas de 64 caracteres y termina en salto de línea, así que decodificarlo sin -A funciona. Si necesitas un archivo de una sola línea, añade -A al codificar y también al decodificar.

Para un data URI:

printf 'data:image/jpeg;base64,%s' "$(openssl base64 -A -in photo.jpg)"

La sección BUGS del manual de enc de OpenSSL 3.5 todavía recoge dos problemas relacionados: -A no funciona correctamente con archivos grandes, y al decodificar sin -A, si los primeros 1024 bytes de la entrada no contienen ningún salto de línea, se ignoran las dos primeras líneas. Con un archivo grande de una sola línea, córtalo antes con fold -w 64 y decodifica sin -A.

Fallos silenciosos: validar el resultado

OpenSSL no informa de un Base64 no válido. Se detiene en los datos incorrectos, escribe lo que haya decodificado y termina con código 0. Resultados con OpenSSL 3.5:

EntradaSalidaCódigo de salida
aGVsbG8K + salto de líneahello\n0
aGVsbG8K (sin salto de línea)nada0
aGk + salto de línea (sin relleno)nada0
aGk=!! + salto de líneanada0
PDw_Pz8-Pg== + salto de línea (URL-safe)nada0
not base64 at all + salto de líneanada0

Por eso los scripts tienen que comprobar la salida por su cuenta:

n=$(echo "$b64" | openssl base64 -d | wc -c)
[ "$n" -gt 0 ] || echo "decode failed or input was empty" >&2

Eso detecta los fallos completos, pero no los parciales, en los que OpenSSL decodificó un prefijo antes de llegar a los datos incorrectos.

O cambia a GNU base64 -d, que imprime base64: invalid input y termina con 1. Para ver qué falla en una cadena concreta, el validador Base64 marca el carácter incorrecto, y errores habituales de Base64 explica las causas.

Hashes, claves y salida cifrada

La mayor parte del uso de Base64 en OpenSSL se combina con otros comandos:

printf '%s' hi | openssl dgst -sha256 -binary | openssl base64 -A
# j0NDRmSPa5bfid2pAcUXaxCm2Dlh3TwayItZstwyeqQ=

openssl rand -base64 32          # 32 random bytes -> 44 characters

La primera forma produce resúmenes SHA-256 en Base64, que es lo que usan los hashes SRI y muchas firmas de API; la versión para el navegador es la herramienta SHA-256 a Base64. -binary es importante: sin esa opción codificas el texto hexadecimal del hash, no el hash.

openssl rand -base64 32 es una forma habitual de generar secretos y claves; el generador de claves Base64 hace lo mismo en el navegador.

openssl enc con -a (igual que -base64) codifica en Base64 el texto cifrado:

printf '%s' 'secret text' | openssl enc -aes-256-cbc -pbkdf2 -a -pass pass:demo
# U2FsdGVkX1/eMk5T8FT9dX8OyAxLRn/ukvgmovOQOeA=   (salt is random, changes every run)

El prefijo U2FsdGVkX1 es el Base64 de Salted__. Decodificarlo sin la contraseña no revela nada legible. Esa diferencia entre codificar y cifrar se explica en codificación frente a cifrado.

Archivos PEM

Los certificados y las claves en formato PEM son DER en Base64 entre líneas -----BEGIN ...-----, cortado a 64 caracteres. OpenSSL los convierte directamente, sin trabajo manual con Base64:

openssl x509 -in cert.pem -outform der -out cert.der
openssl x509 -in cert.der -inform der -outform pem

Para inspeccionar un bloque PEM en el navegador, usa el decodificador de certificados o PEM a DER.

Preguntas frecuentes

¿Por qué openssl base64 -d no imprime nada?

O la entrada no termina en salto de línea, o no es válida. Sin -A, OpenSSL espera líneas terminadas en salto de línea y descarta sin avisar una última línea que no lo tenga. Añade -A, o usa echo con la cadena en lugar de printf '%s'.

¿openssl base64 es lo mismo que openssl enc -base64?

Sí. openssl base64 es un atajo de openssl enc -base64, y ambos aceptan -d, -A, -in y -out.

¿Cómo compruebo si openssl base64 -d ha funcionado?

No puedes fiarte del código de salida: una entrada no válida devuelve 0 con una salida vacía o parcial. Comprueba que la salida no esté vacía, o usa GNU base64 -d, que termina con 1 si la entrada es incorrecta.

¿Qué es U2FsdGVkX1 al principio de una cadena Base64?

Es el Base64 de Salted__, la cabecera que openssl enc escribe delante de los datos cifrados cuando se usa una contraseña. La cadena es texto cifrado, así que al decodificarla obtienes ruido binario, no el texto original.

Sigue leyendo