Close Up Photo of Programming of Codes

Cómo funciona la codificación Base64?

Publicado el 11 de noviembre de 2024
base64algorithms

Tabla de contenidos

Que es Base 64?

Si estas iniciando o ya tienes algún tiempo como desarrollador web, probablemente has escuchado o utilizado la codificación Base64. Si no lo has escuchado, aquí te va una definición: Base64 es un sistema de codificación que se usa para representar los datos binarios en formato de texto. Genial! puedo transformar binario a texto!, pero como funciona 🤔? como puedo transformar una secuencia de bits (10101010) en texto 🤔?. Es posible que en el día a día no necesites conocer como funciona el algoritmos realmente, pero si tienes curiosidad en conocerlo, estas en el lugar correcto. Por cierto, usaré javascript para la implementación.

Cómo funciona?

La codificación Base64 se puede resumir en los siguientes pasos.

  1. Convertir el texto a bytes (se puede omitir si estamos trabajando directamente con bytes (paso 2))
  2. Convertir los bytes a binario
  3. Agrupar los binarios en bloques de 6 bits
  4. Convertir cada grupo de 6 bits a decimal
  5. Convertir los decimales a caracteres Base64
  6. Agregar padding al final

Es un poco abstracto, así que lo haremos paso a paso. Supongamos que tenemos el texto Hola Mundo y deseamos transformarlo a Base64. Entonces seguirmos los siguientes pasos:

const text = 'Hola Mundo';

1. Convertir el texto a bytes

Para convertir una cadena de texto a bytes, podemos usar la siguiente función para iterar en cada caracter y transformarlo a bytes. Si estas trabajando directamente con bytes, este paso es opcional.

const bytes = [];

for (let i = 0; i < text.length; i++) {
  bytes.push(text.charCodeAt(i));
}

// bytes = [72, 111, 108, 97, 32, 77, 117, 110, 100, 111]

2. Convertir los bytes a binario

Una vez que tenemos un arreglo de bytes, debemos transformarlo a una larga cadena binaria.

  • Para transformar cada byte en su formato binario, podemos usar el método toString() que se encuentra en los números y permite transformar un número a un string con una base específica, base 2 en este caso.
  • Además, para asegurar que tendrá 8 caracteres, usamos la función padStart() para añadir tantos 0s como sean necesarios al inicio del string.
  • Finalmente usamos el método join() para unir toda la cadena
const binary = bytes.map((byte) => byte.toString(2).padStart(8, '0')).join('');

// binary = 01001000011011110110110001100001001000000100110101110101011011100110010001101111
// binary (para lectura) = 01001000 01101111 01101100 01100001 00100000 01001101 01110101 01101110 01100100 01101111

3. Agrupar los binarios en bloques de 6 bits

Una vez que tenemos la cadena binaria, debemos agruparlos en bloques de 6 bits. Esta es la razón por la que se llama base64, con 6 bits puedes formar 64(2^6) números diferentes [0 - 63].

  • Usaremos el método slice() para obtener secciones del arreglo.
  • Usaremos el método padEnd() para agregar 0s al final y asegurarnos de que el tamaño siempre sea 6.
const blocks6 = [];

for (let i = 0; i < binary.length; i += 6) {
  blocks6.push(binary.slice(i, i + 6).padEnd(6, '0'));
}

// blocks6 = ['010010', '000110', '111101', '101100', '011000', '100010', '000001', '001101', '011101', '010110', '111001', '100100', '011011', '110000']

4. Convertir cada grupo de 6 bits a decimal

Ahora que tenemos los bloques de 6 bits, hay que transformarlos en números decimales.

const decimals = blocks6.map((block) => parseInt(block, 2));
// decimals = [18, 6, 61, 44, 24, 18, 1, 13, 29, 22, 57, 36, 27, 48]

5. Convertir los decimales a caracteres Base64

El último paso es el más interesante, cada uno de los números de la lista se usará como índice de la tabla de caracteres Base64 para formar el texto codificado. Como cada número es de 6 bits, sus valores varían entre 0 y 63, es decir, tenemos 64 posibles valores, que es justo el tamaño de la tabla Base64. Si aún no conoces la tabla, se compone de la siguiente manera.

Tabla de caracteres Base64

La tabla está compuesta de la siguiente manera:

  • Las letras en mayúsculas (A-Z) (26 caracteres)
  • Las letras en minúscula (a-z) (26 caracteres)
  • Los dígitos (0-9) (10 caracteres)
  • Caracteres especiales ”+/” (2 caracteres)
  • Se usa ”=” para el padding
Esto da como resultado lo siguiente: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

const base64 = decimals.map((decimal) => base64Table[decimal]).join('');
// base64 = SG9sYSBNdW5kbw

Si bien es cierto, ya tenemos el texto codificado, nos falta considerar algo muy importante, el padding.

6. Agregar padding al final

Recordemos que la codificación Base64 agrupa los bytes en bloques de 6 bits. Si analizamos los posibles valores de entrada notaremos que no siempre la cantidad de bits es divisible entre 6, a veces nos sobran bits, veamos algunos ejemplos:

TextoBinarioBits totalesBloques de 6Bits sobrantes
S01010011812
Sa01010011 011000011624
Sal01010011 01100001 011011002440
Salu01010011 01100001 01101100 …3252
Salud01010011 01100001 01101100 …4064
Saludo01010011 01100001 01101100 …4880

De la tabla podemos concluir que cuando los valores de entrada son múltiplos de 3 bytes (24 bits), no nos sobra ningún bit. Es por ello que la codificación Base64 trabaja con bloques de 3 bytes, al aplicar el algoritmo, estos se convierten en 4 bloques de 6 bits, es decir, 4 caracteres Base64. Cuando el número de bytes no es múltiplo de 3, entonces tenemos que añadir un padding (=) para mantener la alineación. Agreguemos la codificación a la tabla.

TextoBinarioBits totalesBloques de 6Bits sobrantesBase64
S01010011812Uw==
Sa01010011 011000011624U2E=
Sal01010011 01100001 011011002440U2Fs
Salu01010011 01100001 01101100 …3252U2FsdQ==
Salud01010011 01100001 01101100 …4064U2FsdWQ=
Saludo01010011 01100001 01101100 …4880U2FsdWRv

Podemos concluir lo siguiente:

  • Los caracteres aumentan de 4 en 4 en base a la longitud de la entrada.
  • Si los bytes son múltiplo de 3n + 1 (ejm: 3, 6, 9, etc) no agregamos padding.
  • Si los bytes son múltiplo de 3n + 1 (ejm: 1, 4, 7, etc) agregamos (==) de padding.
  • Si los bytes son múltiplo de 3n + 2 (ejm: 2, 5, 8, etc) agregamos (=) de padding.

Entonces el algorimo quedaría de la siguiente forma.

const padding = (3 - (text.length % 3)) % 3;
// Para 3n + 1 (1, 4, 7, 10, etc)  => 2 => "=="
// Para 3n + 2 (2, 5, 8, 11, etc)  => 1 => "="

const base64 = decimals.map((decimal) => base64Table[decimal]).join('') + padding;
// base64 = SG9sYSBNdW5kbw==

Algoritmo completo

Este es el algoritmo completo

const text = 'Hola Mundo';

const bytes = [];

for (let i = 0; i < text.length; i++) {
  bytes.push(text.charCodeAt(i));
}

const binary = bytes.map((byte) => byte.toString(2).padStart(8, '0')).join('');

const blocks6 = [];

for (let i = 0; i < binary.length; i += 6) {
  blocks6.push(binary.slice(i, i + 6).padEnd(6, '0'));
}

const decimals = blocks6.map((block) => parseInt(block, 2));

const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

const padding = (3 - (text.length % 3)) % 3;

const base64 = decimals.map((decimal) => base64Table[decimal]).join('') + padding;

No reinventes la rueda

En el día a día no vas a implementar el algoritmo para la codificación Base64, ya existen funciones que nos ayudan con esto, la implementación que hice fue con fines explicativos y evidentemente no está optimizada. En tu día a día usarías la función btoa() de la siguiente manera.

const text = 'Hola Mundo';
const base64 = btoa(text);
// base64 = SG9sYSBNdW5kbw

Si…, eso es todo 😅.

Calculadora

Desarrollé una pequeña calculadora que te permite transformar texto en base64, y te muestra los valores en cada uno de los pasos que seguimos en esta guía.

Text to Base64 Converter

Bytes (10)

72 111 108 97 32 77 117 110 100 111

Bytes in Binary (10)

01001000 01101111 01101100 01100001 00100000 01001101 01110101 01101110 01100100 01101111

Bytes grouped in blocks of 6 (14)

010010 000110 111101 101100 011000 010010 000001 001101 011101 010110 111001 100100 011011 110000

Decimals (14)

18 6 61 44 24 18 1 13 29 22 57 36 27 48

Base64 (14)

SG9sYSBNdW5kbw==

Base64 (usando btoa)

Siguientes pasos

Como ves, el algoritmo no es tan complicado, pero si es un poco trabajoso 😅. Pero ahora que los has entendido, tal vez quieras poner en práctica tus conocimientos. Así que aquí hay algunas ideas de proyectos que puedes realizar

Codificador y Decodificador Base 64

Crea una aplicación que permita transformar un texto a Base64 y que permita convertir de Base64 a texto (spoiler: debes usar el algoritmo a la inversa).

  • Tecnologías: las que quieras, puede ser una aplicación web, móvil, terminal, etc.

Crea tu propia codificación

Como ya entendíste la lógica detrás de la codificación Base64, puedes experimentar creando la tuya propia.

  • Cambiar la cantidad de bits: Porque limitarse a Base64?, como sería una codificación Base128 o Base32 🤔?
  • Cambiar la tabla de caracteres: puedes cambiar el orden de los caracteres de la tabla de caracteres Base64 o crear tu propia tabla.

© 2024 Willington Ortiz. Todos los derechos reservados.