Base32

Codifica texto o hexadecimal en Base32 o base32hex, con o sin relleno, mayúsculas o minúsculas, y lo decodifica, con línea y columna de un carácter intruso.

Entrada
Salida
JBXWYYI=

Bytes en treinta y dos caracteres, y los dígitos que se quedan fuera

Base32 escribe bytes como texto, con treinta y dos caracteres que representan cinco bits cada uno, así que cada cinco bytes — cuarenta bits — se convierten en ocho caracteres. Hello ocupa cinco bytes y se escribe JBSWY3DP. Elige «Decodificar» y pega Base32, y la página devuelve los bytes que ese Base32 representa: como texto, o en hexadecimal si pones «Bytes como» en «Hexadecimal».

El RFC 4648, que lo define, usa las veintiséis letras mayúsculas y los dígitos del 2 al 7. El RFC da la razón de que falten el 0 y el 1: quien maneje el texto puede confundir con facilidad el 0 con la O, y el 1 con la l o la I, así que el alfabeto se queda con las letras y deja fuera esos dos dígitos. Junto a las letras necesita seis dígitos, y los seis que toma son del 2 al 7, así que el 8 y el 9 tampoco están en él. Al decodificar en este alfabeto, la página rechaza un 0, un 1, un 8 o un 9 allí donde esté, en lugar de leer un 0 como O o un 1 como I: el RFC permite que un decodificador los lea así, y dice que por defecto no debería hacerlo.

Que una letra esté en mayúscula o en minúscula no forma parte del valor. El RFC 4648 diseñó Base32 para texto que tiene que leerse sin distinguir mayúsculas de minúsculas, así que jbswy3dp es Hello igual que JBSWY3DP. El RFC escribe su alfabeto en mayúsculas, y lo mismo hace esta página salvo que actives «minúsculas». Además, la lectura pasa por alto los espacios en blanco en cualquier sitio, saltos de línea incluidos, así que un Base32 partido en grupos o repartido en varias líneas se lee como si estuviera escrito de una pieza.

El relleno, y las longitudes en que viene Base32

Los bytes rara vez llegan en grupos completos de cinco. Los que sobran al final, de uno a cuatro, ocupan dos, cuatro, cinco o siete caracteres, y el RFC 4648 rellena ese último grupo de caracteres hasta ocho con =: seis, cuatro, tres o uno. Así, f es MY======, fo es MZXQ====, foo es MZXW6=== y foob es MZXW6YQ=, mientras que fooba, cinco bytes, llena sus ocho exactamente como MZXW6YTB.

Contados de ocho en ocho, entonces, los caracteres anteriores a cualquier = dejan siempre de resto 0, 2, 4, 5 o 7 y nunca 1, 3 o 6, porque ningún número de bytes deja ese resto; la página rechaza un texto así en su último carácter en lugar de leerlo como algo más corto. El relleno no dice nada que la longitud no diga, así que la página lee Base32 sin su relleno — JBUQ es Hi igual que JBUQ==== — y rechaza el relleno solo donde está y es incorrecto: un = en medio, con más texto detrás, o el número equivocado de = al final, donde el rechazo dice cuántos corresponden ahí.

Al codificar, el interruptor «Relleno» decide si se escriben los =. Empieza activado, porque el RFC 4648 pide relleno salvo que la especificación que usa Base32 diga otra cosa, y varias lo hacen: el Key Uri Format, que describe el otpauth:// URI de un código QR de 2FA, dice que el relleno de un secreto debería omitirse, y los registros NSEC3 e IPFS no escriben ninguno. El interruptor «minúsculas», a su lado, escribe las letras en minúscula; los dígitos y el = no tienen mayúscula ni minúscula que cambiar. Los dos interruptores solo aparecen al codificar, porque la lectura acepta cualquier combinación de ellos.

Otras herramientas leen menos que esta página. GNU coreutils escribe Base32 con base32 y el segundo alfabeto, base32hex, con basenc --base32hex; el módulo base64 de Python tiene una función para cada uno. Todas escriben lo que esta página escribe al abrirse, con relleno y en mayúsculas. Pero base32 -d rechaza un Base32 al que le falta el relleno o cuyas letras están en minúscula, y el b32decode de Python también rechaza los dos casos, y solo lee minúsculas cuando se le pasa casefold=True:

# Escribir: el alfabeto por defecto y luego el otro
printf 'Hi' | base32                          # JBUQ====
printf 'Hi' | basenc --base32hex              # 91KG====

# Leer de nuevo: con relleno, luego sin relleno, luego en minúsculas
printf 'JBUQ====' | base32 -d                 # Hi
printf 'JBUQ' | base32 -d                     # base32: invalid input
printf 'jbuq====' | base32 -d                 # base32: invalid input

# Lo mismo en un script
import base64
base64.b32encode(b'Hi')                       # b'JBUQ===='
base64.b32hexencode(b'Hi')                    # b'91KG===='
base64.b32decode('JBUQ')                      # binascii.Error: Incorrect padding
base64.b32decode('jbuq====', casefold=True)   # b'Hi'

Dos alfabetos: base32 y base32hex

El RFC 4648 define un segundo alfabeto, base32hex: los dígitos del 0 al 9 y luego las letras de la A a la V, así que sus caracteres siguen el orden de los valores que representan, del 0 para el cero a la V para el treinta y uno. Eso le da una propiedad que el primero no tiene, y que el RFC señala: comparado carácter a carácter, su texto se ordena según el orden de los bytes que representa. El byte 00 es AA====== en base32 y 00====== en base32hex, y el byte FF es 74====== y VS======; al ordenarlos como texto, base32 pone FF primero, porque los dígitos van antes que las letras, mientras que base32hex mantiene los bytes en orden.

Los registros NSEC3 de DNSSEC lo usan. El nombre de uno de esos registros empieza por el hash de un nombre de dominio, escrito en base32hex sin relleno, y el RFC 5155 señala que, escritos así, los nombres convertidos en hash se ordenan igual que los hashes por su valor. La zona de ejemplo del propio RFC convierte example en el hash 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom. Con base32hex elegido, la página lee esos 32 caracteres como los 20 bytes del hash; con base32 elegido, rechaza el 0 — y un aviso dice que el texto se lee entero en base32hex, junto a un botón que cambia a él.

Como los mismos bytes son un texto distinto en cada uno — Hi es JBUQ==== en base32 y 91KG==== en base32hex —, el alfabeto que elijas vale para las dos direcciones, y la página nunca lo cambia por ti. Cuando un texto que decodificas contiene un carácter que el alfabeto elegido no tiene, o termina en bits sobrantes que no son cero, algo que explican las preguntas de más abajo, mientras que el otro alfabeto lo lee entero tal como lo escribiría un codificador, un aviso lo dice junto a un botón que cambia a ese alfabeto; el alfabeto solo cambia cuando pulsas ese botón o lo eliges tú. Un texto que los dos leen sin problema, como ABCDEFGH, se lee en el elegido, porque nada en él dice cuál se quería.

Dónde aparece Base32: secretos 2FA, direcciones onion e IPFS

En el Key Uri Format, que describe el otpauth:// URI que puede llevar un código QR de configuración, el secreto que hay detrás de los códigos de una app de autenticación se escribe en Base32: el parámetro secret del URI es Base32, y el relleno debería omitirse. Pega un secreto así en mayúsculas o en minúsculas, en grupos separados por espacios o repartidos en varias líneas, con o sin = — un guion entre grupos se rechaza allí donde está — o pega el URI entero, y la página lee el secreto que hay en él y lo dice. Lo que significan los demás parámetros del URI, y cómo un secreto se convierte en los códigos que muestra una app, corresponden al Depurador de códigos TOTP / 2FA: su guía explica el URI y sus parámetros, y su página calcula los códigos. La etiqueta y el emisor del URI están codificados en porcentaje, como pide el Key Uri Format, y el Codificador / decodificador de URL los lee.

Una dirección onion de la versión 3 de Tor también es Base32. Sus 56 caracteres antes de .onion son el Base32 de 35 bytes: la clave pública de 32 bytes del servicio, una suma de comprobación de dos bytes y un byte de versión, 03. La especificación de Tor escribe sus direcciones de ejemplo en minúsculas, y 35 bytes llenan grupos completos, así que no hay relleno que omitir. Pega los 56 caracteres sin .onion, pon «Bytes como» en «Hexadecimal», y el último byte se lee como 03.

IPFS escribe sus identificadores de contenido, los CID, en Base32 por defecto a partir de la versión 1: en minúsculas y sin relleno, tras una letra, b, que no forma parte del Base32 sino que lo nombra — el prefijo de multibase, que se quita antes de decodificar el resto. Así, bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi, el ejemplo de la propia documentación de IPFS, se rechaza aquí entero, como una longitud que ningún byte produce; sin su b se lee como 36 bytes, el CID binario, que empieza por 01, el número de su versión.

Un secreto 2FA son bytes, no texto

El secreto de ejemplo del Key Uri Format es JBSWY3DPEHPK3PXP, y ese documento detalla su valor como diez bytes: los caracteres de Hello!, y luego DE AD BE EF. Sus primeros ocho caracteres, JBSWY3DP, son Hello por sí solos. Decodificado aquí con «Bytes como» en «Texto», como viene la página por defecto, sale como Hello!, luego U+07AD — DE AD forman por casualidad un carácter, una marca combinante de la escritura thaana — y luego dos U+FFFD, que representan cada uno una secuencia que no es texto. Un aviso debajo del resultado cuenta las secuencias reemplazadas, dice que la primera empieza en el byte 9, cuyos bits empiezan en el carácter de la línea 1, columna 13, el 3, y dice que puede que los bytes no sean texto en absoluto.

Un secreto real son bytes aleatorios, que rara vez forman texto, así que decodificado como texto es un revoltijo de caracteres sueltos y U+FFFD que no te dice nada sobre si el secreto es correcto. Para eso está la opción «Hexadecimal» de «Bytes como». Elígela, o pulsa el botón que hay junto al aviso, y el mismo secreto se muestra entero como 48 65 6C 6C 6F 21 DE AD BE EF: los bytes mismos, que son lo que guarda un servidor y de lo que se calcula cada código. La página nunca cambia a hexadecimal por su cuenta, así que lo que hay en pantalla es siempre lo que elegiste.

En sentido contrario es la misma elección, hecha al codificar. Una clave que un servidor guarda en hexadecimal son bytes: elige «Codificar», pon «Bytes como» en «Hexadecimal» y pégala — con espacios o todo seguido, con 0x delante de los bytes, como un array de números o como un volcado hexadecimal con la disposición de hexdump -C o de xxd — y la página escribe el Base32 que acepta una app de autenticación. 48656C6C6F21DEADBEEF sale como JBSWY3DPEHPK3PXP, el secreto de arriba; diez bytes llenan grupos completos, y una clave que no los llena, como una de dieciséis bytes, sale con = detrás salvo que desactives el interruptor «Relleno», como pide el Key Uri Format. El hexadecimal pegado por error al decodificar — un número par de dígitos hexadecimales y nada más que espacios en blanco, en una forma que al codificar se puede leer como bytes — recibe un aviso de que parece hexadecimal, junto a un botón que pasa a codificarlo. Y al decodificar, «Descargar» guarda los bytes mismos como un archivo llamado bytes.bin.

Base32 o Base64, y por qué no el alfabeto de Crockford

Base64 hace el mismo trabajo con sesenta y cuatro caracteres, cuatro por cada tres bytes, lo que hace su texto un tercio más largo que los bytes, mientras que el de Base32 es tres quintos más largo. Lo que Base64 sacrifica a cambio es poder ignorar las mayúsculas y minúsculas: su alfabeto tiene las mayúsculas y las minúsculas como valores distintos, y además + y /, así que SGk= es Hi y sgk= son otros dos bytes. Base32 conviene al texto que pasa por algo que no distingue mayúsculas de minúsculas, o que una persona lee en una pantalla y teclea en otra. Cuando el Base64 que pegas aquí contiene un + o un /, que ningún Base32 escribe, y tiene forma de Base64 de principio a fin, se rechaza con un aviso de que parece Base64 y un enlace a la herramienta Base64, que lee Base64 como texto.

Existen otros alfabetos de treinta y dos caracteres, y esta página ofrece los dos del RFC 4648 y ninguno más. Uno es el de Douglas Crockford, que conserva los diez dígitos y deja fuera la I, la L, la O y la U, y que el formato ULID utiliza. Crockford lo definió para escribir números, y para bytes tiene dos respuestas: los dieciséis bytes del 00 al 0F, empaquetados de cinco en cinco bits como el RFC 4648 empaqueta los bytes, son 000G40R40M30E209185GR38E1W, y leídos como un número de 128 bits, como se leen los veintiséis caracteres de un ULID, son 00041061050R3GG28A1C60T3GF. Una página que escribiera bytes en él estaría eligiendo una de las dos por ti, sin que lo vieras.

Preguntas frecuentes

¿Por qué mi secreto decodificado muestra U+FFFD?
Porque un secreto 2FA son bytes aleatorios, y los bytes aleatorios rara vez son texto UTF-8. Con «Bytes como» en «Texto», la página escribe cada secuencia que no es texto como U+FFFD, el carácter de reemplazo, y un aviso dice cuántas hubo y dónde empieza la primera, como byte y como la línea y la columna del carácter en que empiezan los bits de ese byte. Los bytes mismos quedan intactos: el botón que hay junto al aviso los muestra en hexadecimal, y «Descargar» los guarda. Un U+FFFD que de verdad está en un texto, los bytes EF BF BD, se lee como texto y no se cuenta.
¿Qué significa «una longitud que ningún byte produce»?
Contados de ocho en ocho, los caracteres de un Base32, dejando aparte cualquier =, dejan de resto 0, 2, 4, 5 o 7, sean cuales sean los bytes, así que un texto que deja 1, 3 o 6 no puede representar ningún byte, y la página lo rechaza en su último carácter. Un texto así no lo escribió de ese modo ningún codificador: algo se perdió o se añadió por el camino hasta ti. JBSWY3DPEHPK3P, el secreto del Key Uri Format con dos caracteres de menos, se rechaza ahí. Un corte también puede caer en una longitud que los bytes sí producen, y entonces se lee como menos bytes — JBSWY3DPEHPK3PX como nueve —, algo que la página solo puede notar donde los bits sobrantes del último carácter no son cero, como los de esa X. Un corte en el límite de un grupo completo de ocho no deja nada que notar.
¿Qué son los bits sobrantes, y por qué dice la página que los míos no son cero?
Cinco bits por carácter y ocho por byte rara vez cuadran, así que, salvo que los bytes vengan en grupos completos de cinco, el último carácter lleva de uno a cuatro bits que ningún byte contiene, y un codificador los escribe como ceros. MZXW6YQ= y MZXW6YR= son los dos foob: los tres últimos bits de la Q son 000 y los de la R son 001, y solo el primero es lo que escribe un codificador. La página lee los dos, y para el segundo su aviso nombra la R, dónde está, y la Q que un codificador escribe ahí. Unos bits sobrantes que no son cero significan que el texto no es lo que escribió un codificador: puede que se haya cortado, editado a mano o escrito en el otro alfabeto, y esto último la página lo comprueba por ti.
¿Es Base32 un cifrado?
No. Base32 cambia cómo se escriben los bytes y nada más: cualquiera puede decodificarlo, y todo decodificador que siga el RFC 4648 recupera los mismos bytes con el mismo alfabeto. Un secreto 2FA escrito en Base32 es el propio secreto, así que quien vea la clave de configuración tiene tu segundo factor.
¿Se envía a un servidor algo de lo que pego?
No. Las dos direcciones se ejecutan en esta página, en tu propio dispositivo: nada de lo que pegas — un secreto, un texto o hexadecimal — se sube, y el archivo que guarda «Descargar» se crea en tu navegador a partir de los bytes que ya están ahí.

Herramientas relacionadas