Codificación y decodificación de cadenas Base64 en Java

C

Introducción

El proceso de convertir datos mediante la aplicación de algunas técnicas / reglas a un nuevo formato se denomina codificación. La decodificación es el proceso inverso de la codificación: devolver los datos codificados al formato original.

La codificación nos rodea y las computadoras dependen en gran medida de diferentes formatos de codificación para entregar y transferir información.

Desde la última imagen de un gato en su feed hasta el mensaje de voz que escuchó en una aplicación de mensajería, todos estos se codificaron en el lado del remitente, se le entregaron y decodificaron en el lado del destinatario.

La codificación asegura que los datos permanezcan intactos y sean eficientes para el transporte.

¿Qué es Base64?

Base64 es un esquema de codificación de binario a texto. Se representa como caracteres ASCII imprimibles donde cada carácter Base64 contiene 6 bits de información binaria.

Es muy útil para almacenar información de imagen / audio en cadenas de información. Lo que Base64 no es es un algoritmo de cifrado.

Si bien “oscurece” los datos hasta cierto punto, no es un formato seguro de ninguna manera.

¿Cómo funciona Base64?

En Base64, como sugiere el nombre, se utilizan 64 caracteres para codificar datos binarios. Estos personajes son:

  • 26 letras mayúsculas [A-Z]
  • 26 letras minúsculas [a-z]
  • 10 dígitos [0-9]
  • 2 caracteres especiales [+ , /]

Nota: También hay un carácter 65 (=), que tiene un significado especial y se llama carácter de relleno.

Como es habitual, cuando se trata de computadoras, los números se representan en potencias de 2. Por lo tanto, 64 caracteres de Base64 se pueden escribir como:
$$
64 = 2 ^ 6
$$
Cada carácter está representado en 6 bits. Podría ir más alto que esto y hacer que cada carácter represente 8 bits. Eso sería Base256. Sin embargo, esto no es práctico debido a las dificultades en el proceso de codificación / decodificación.

Sigamos adelante y codifiquemos manualmente una cadena simple para tener una buena idea de cómo funciona el proceso.

Codificación manual

Por ejemplo, digamos que tenemos un String – ABC123 que nos gustaría codificar en Base64. Hay cinco pasos que tomamos durante este proceso:

  • Tome los valores ASCII de los caracteres de entrada por separado:
PersonajeUNsegundoC123
ASCII (decimal)sesenta y cinco6667495051
  • Convierta el valor decimal de cada carácter en un binario de 8 bits:
PersonajeUNsegundoC123
ASCIIsesenta y cinco6667495051
Binario010000010100001001000011001100010011001000110011
  • Reorganice los números binarios en trozos de 6 bits:

    010000 010100 001001 000011 001100 010011 001000 110011

    Si es imposible dividirlo en partes de seis, tenemos que almohadilla la secuencia.

  • Obtenga los valores decimales de estos fragmentos binarios:
Binario010000010100001001000011001100010011001000110011
Decimaldieciséis20931219851
  • Finalmente, usando el gráfico Base64, convierta cada número decimal en un carácter Base64:
ValorCarbonizarseValorCarbonizarseValorCarbonizarseValorCarbonizarse
0UNdieciséisQ32gramo48w
1segundo17R33h49X
2C18S34yo50y
3re19T35j51z
4mi20U36k520
5F21V37l531
6GRAMO22W38metro542
7H23X39norte553
8yo24Y40o564
9J25Z41pags575
10K26un42q586
11L27segundo43r597
12METRO28C44s608
13norte29re45t619
14O30mi46tu62+
15PAGS31F47v63/

Al final, nos quedamos con la String QUJDMTIz – la representación Base64 de ABC123.

Nota: Se codifican 6 caracteres de entrada en 8 caracteres al final. Esto significa que se necesita ~ 33% más de espacio para almacenar una cadena codificada en Base64 en lugar de la cadena original.

¿Por qué utilizar la codificación Base64?

Las computadoras funcionan con 0sy 1s, entonces, ¿por qué molestarse en convertir esto a otro formato?

Si verdad. El binario es el lenguaje de las computadoras. Es exactamente por eso que lo estamos convirtiendo. Una secuencia como 0010110 puede significar muchas cosas. Puede ser parte de una imagen, puede ser parte de un archivo de audio o puede ser un comando que borre la mitad de su disco duro.

Estos datos deben procesarse de manera diferente, dependiendo de lo que se supone que representan. Además, muchos servidores no esperan datos binarios sin procesar. Los servidores de correo electrónico, por ejemplo, esperan datos textuales. Todos los correos electrónicos están codificados antes de que las aplicaciones los envíen.

Codificación de cadenas con Java 8 – Base64

Java 8 nos presentó una nueva clase: Base64. Admite la codificación y decodificación de algunos tipos de variantes de datos según lo especificado por RFC 2045 y RFC 4648:

  • Básico
  • URL y nombre de archivo seguros
  • MÍMICA

Codificación y decodificación básica de cadenas

Usando el codificador base, podemos codificar una cadena en Base64. El codificador base no agrega un carácter separador de línea.

Si la longitud de la cadena no es divisible por 3 (la representación de 8 bits no podrá agruparse en grupos de 6 bits), el relleno se agregará en forma de = al final:

Encoder encoder = Base64.getEncoder();
String originalString = "basic";
String encodedString = encoder.encodeToString(originalString.getBytes());

System.out.println(encodedString);

los Base64 es una clase de fábrica de la que recuperaremos diferentes implementaciones / variaciones del codificador. los encodeToString() El método codificará nuestra entrada en una representación Base64 de la entrada y la empaquetará en un String. También puede utilizar el encode() método para codificarlo en un byte corriente o un ByteBuffer en lugar.

Si es necesario, también puede devolver una instancia de codificador que no rellene las cadenas de entrada a través del withoutPadding() método mientras lo instancia desde la clase de fábrica:

Base64.getEncoder().withoutPadding();

Nota: La codificación sin relleno probablemente dará como resultado una cadena Base64 que no se puede volver a decodificar ya que se pierde una parte de la información.

Ejecutar el ejemplo de código producirá:

YmFzaWM=

Con nuestra cadena codificada, también creemos una instancia Decoder y decodificar la cadena producida. Sin embargo, los decodificadores solo funcionan con byte matrices:

Decoder decoder = Base64.getDecoder();
byte[] bytes = decoder.decode(encodedString);
		
System.out.println(new String(bytes));

Este código resultará en:

basic

Codificación y decodificación de URL

Para codificar y decodificar URL, podemos usar una instancia de Encoder y Decoder que utilizan el tipo seguro de URL y nombre de archivo de Base64. Tampoco añaden un carácter separador de línea.

Los obtenemos a través del getUrlEncoder() y getUrlDecoder() métodos a través del Base64 fábrica:

Encoder encoder = Base64.getUrlEncoder();
String originalinput = "https://Pharos.sh.com/tag/java/";
String encodedUrl = encoder.encodeToString(originalinput.getBytes());

System.out.println(encodedUrl);

Al igual que antes, el encodeToString() El método codificará la entrada y la empaquetará en una Cadena:

aHR0cHM6Ly9zdGFja2FidXNlLmNvbS90YWcvamF2YS8=

los encode() El método codificaría la entrada en un byte formación. De nuevo, el decode() El método funciona con un byte array y decodifica la Cadena Base64 en la original:

Decoder decoder = Base64.getUrlDecoder();
byte[] bytes = decoder.decode(encodedUrl);

System.out.println(new String(bytes));

Ejecutar este código produce:

https://Pharos.sh.com/tag/java/

Nota: Tres caracteres especiales están disponibles en este esquema: +, /, =. Estos caracteres pueden tener un significado diferente en las URL y ciertos sistemas de archivos y podrían causar un problema si se utiliza la cadena codificada. Para asegurarnos de evitar estos problemas, las URL y las cadenas de archivos deben codificarse y decodificarse mediante el decodificador seguro para URL.

los + y / los caracteres se reemplazan con - y _ respectivamente.

Codificación y decodificación MIME

Las etiquetas de extensión de correo de Internet multipropósito (MIME) se utilizan para identificar el tipo de medio (HTML, audio, video).

Dado que muchos tipos de medios, como imágenes, documentos, etc., se envían como archivos adjuntos por correo electrónico, es necesario codificarlos en un formato aceptable para todos los protocolos.

Al enviar archivos adjuntos, como .txt archivo, están codificados en Base64 y adjuntados al correo electrónico. Así es como puede verse un archivo adjunto:

Content-Type: text/plain;
name="log_attachment.txt"
Content-Disposition: attachment;
filename="attachment.txt"
Content-Transfer-Encoding: base64

TUlNRS1WZXJzaW9uOiAxLjANClgtTWFpbGVyOiBNYWlsQmVlLk5FVCA4LjAuNC40MjgNClN1Ympl
Y3Q6IHRlc3Qgc3ViamVjdA0KVG86IGtldmlubUBkYXRhbW90aW9uLmNvbQ0KQ29udGVudC1UeXBl
OiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7DQoJYm91bmRhcnk9Ii0tLS09X05leHRQYXJ0XzAwMF9B
RTZCXzcyNUUwOUFGLjg4QjdGOTM0Ig0KDQoNCi0tLS0tLT1fTmV4dFBhcnRfMDAwX0FFNkJfNzI1
RTA5QUYuODhCN0Y5MzQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsNCgljaGFyc2V0PSJ1dGYt
OCINCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KdGVzdCBi
b2R5DQotLS0tLS09X05leHRQYXJ0XzAwMF9BRTZCXzcyNUUwOUFGLjg4QjdGOTM0DQpDb250ZW50
LVR5cGU6IHRleHQvaHRtbDsNCgljaGFyc2V0PSJ1dGYtOCINCkNvbnRlbnQtVHJhbnNmZXItRW5j
b2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KPHByZT50ZXN0IGJvZHk8L3ByZT4NCi0tLS0tLT1f
TmV4dFBhcnRfMDAwX0FFNkJfNzI1RTA5QUYuODhCN0Y5MzQtLQ0K

Al codificar MIME, la salida se formatea para que sea compatible con MIME; las líneas no pueden tener más de 76 caracteres y cada línea termina con rn, excepto por el último, naturalmente. los r es un carácter de retorno de carro mientras que el n es el carácter de nueva línea.

Hagamos un archivo, llamado file.txt que contiene:

"I met a traveller from an antique land,
Who said - “Two vast and trunkless legs of stone
Stand in the desert.... Near them, on the sand,
Half sunk a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them, and the heart that fed;
And on the pedestal, these words appear:
My name is Ozymandias, King of Kings;
Look on my Works, ye Mighty, and despair!
Nothing beside remains. Round the decay
Of that colossal Wreck, boundless and bare
The lone and level sands stretch far away.”

Ozymandias, by Percy Bysshe Shelley

Ahora, leamos los bytes del archivo y empaquételos en un byte array, después de lo cual lo codificaremos:

byte[] bytes = Files.readAllBytes(Paths.get("path/to/file"));
String encodedString = Base64.getMimeEncoder().encodeToString(bytes);
System.out.println(encodedString);

Este código nos cederá:

IkkgbWV0IGEgdHJhdmVsbGVyIGZyb20gYW4gYW50aXF1ZSBsYW5kLA0KV2hvIHNhaWTigJTigJxU
d28gdmFzdCBhbmQgdHJ1bmtsZXNzIGxlZ3Mgb2Ygc3RvbmUNClN0YW5kIGluIHRoZSBkZXNlcnQu
Li4uIE5lYXIgdGhlbSwgb24gdGhlIHNhbmQsDQpIYWxmIHN1bmsgYSBzaGF0dGVyZWQgdmlzYWdl
IGxpZXMsIHdob3NlIGZyb3duLA0KQW5kIHdyaW5rbGVkIGxpcCwgYW5kIHNuZWVyIG9mIGNvbGQg
Y29tbWFuZCwNClRlbGwgdGhhdCBpdHMgc2N1bHB0b3Igd2VsbCB0aG9zZSBwYXNzaW9ucyByZWFk
DQpXaGljaCB5ZXQgc3Vydml2ZSwgc3RhbXBlZCBvbiB0aGVzZSBsaWZlbGVzcyB0aGluZ3MsDQpU
aGUgaGFuZCB0aGF0IG1vY2tlZCB0aGVtLCBhbmQgdGhlIGhlYXJ0IHRoYXQgZmVkOw0KQW5kIG9u
IHRoZSBwZWRlc3RhbCwgdGhlc2Ugd29yZHMgYXBwZWFyOg0KTXkgbmFtZSBpcyBPenltYW5kaWFz
LCBLaW5nIG9mIEtpbmdzOw0KTG9vayBvbiBteSBXb3JrcywgeWUgTWlnaHR5LCBhbmQgZGVzcGFp
ciENCk5vdGhpbmcgYmVzaWRlIHJlbWFpbnMuIFJvdW5kIHRoZSBkZWNheQ0KT2YgdGhhdCBjb2xv
c3NhbCBXcmVjaywgYm91bmRsZXNzIGFuZCBiYXJlDQpUaGUgbG9uZSBhbmQgbGV2ZWwgc2FuZHMg
c3RyZXRjaCBmYXIgYXdheS7igJ0NCg0KT3p5bWFuZGlhcywgYnkgUGVyY3kgQnlzc2hlIFNoZWxs
ZXk=

Naturalmente, decodificar este contenido es tan fácil como:

Decoder decoder = Base64.getMimeDecoder();
byte[] decodedBytes = decoder.decode(encodedString);
System.out.println(new String(decodedBytes));

Este código producirá:

"I met a traveller from an antique land,
Who said - “Two vast and trunkless legs of stone
Stand in the desert.... Near them, on the sand,
Half sunk a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them, and the heart that fed;
And on the pedestal, these words appear:
My name is Ozymandias, King of Kings;
Look on my Works, ye Mighty, and despair!
Nothing beside remains. Round the decay
Of that colossal Wreck, boundless and bare
The lone and level sands stretch far away.”

Ozymandias, by Percy Bysshe Shelley

Apache Commons

Debido a su utilidad y prevalencia en Java, muchos proyectos han Apache Commons incluido en el classpath. Es una gran biblioteca con muchas características útiles que se utilizan a menudo en producción, y la codificación / decodificación no es una excepción.

Con Maven, agregarlo a su proyecto es tan fácil como incluir la dependencia:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>${version}</version>
</dependency>

O, si está usando Gradle:

compile group: 'commons-codec', name: 'commons-codec', version: '${version}'

Similar a la implementación oficial de Java, el Base64 class es la API principal. Aunque, en lugar de ser utilizado como fábrica para Encoder/Decoder instancias, la clase misma maneja toda la codificación y decodificación. Otros métodos útiles que proporciona son métodos como isBase64(), isInAlphabet() y isUrlSafe().

Codificación y decodificación básica de cadenas de Apache Commons

Sigamos adelante y codifiquemos una cadena simple en Base64. los encodeBase64() el método acepta un byte matriz, y devuelve un byte matriz, que representa la entrada codificada.

String inputString = "Some String";
byte[] bytes = Base64.encodeBase64(inputString.getBytes());

System.out.println(new String(bytes));

Ejecutar este código producirá:

U29tZSBTdHJpbmc=

Alternativamente, puede utilizar el encodeBase64String() método, que devolverá un String, en lugar de un byte formación:

String inputString = "Some String";
String encodedString = Base64.encodeBase64String(inputString.getBytes());

System.out.println(encodedString);

Ejecutar este código producirá:

U29tZSBTdHJpbmc=

En la misma línea, el Base64 class también se utiliza como decodificador. Acepta un byte matriz o cadena y devuelve un byte formación:

String decodedString = new String(Base64.decodeBase64(encodedString.getBytes()));
System.out.println(decodedString);
// Or
String anotherDecodedString = new String(Base64.decodeBase64(encodedString));
System.out.println(anotherDecodedString);

Ejecutar este código producirá:

Some String
Some String

Codificación y decodificación de URL de Apache Commons

La codificación y decodificación de URL sigue el mismo principio:

String originalInput = "https://Pharos.sh.com/tag/java/";
byte[] bytes = Base64.encodeBase64URLSafe(originalInput.getBytes());

System.out.println(new String(bytes));

Ejecutar esto resultará en:

aHR0cHM6Ly9zdGFja2FidXNlLmNvbS90YWcvamF2YS8=

También puede devolver una cadena en lugar de una byte formación:

String originalInput = "https://Pharos.sh.com/tag/java/";
String encodedString = Base64.encodeBase64URLSafeString(originalInput.getBytes());

System.out.println(encodedString);

los encodedStringLos contenidos son:

aHR0cHM6Ly9zdGFja2FidXNlLmNvbS90YWcvamF2YS8=

Y finalmente, también podemos decodificar la representación Base64 de la URL:

String decodedUrl = new String(Base64.decodeBase64(encodedString.getBytes()));
System.out.println(decodedUrl);
// Or
String anotherDecodedUrl = Base64.decodeBase64(encodedString);
System.out.println(anotherDecodedUrl);
https://Pharos.sh.com/tag/java/
https://Pharos.sh.com/tag/java/

Codificación y decodificación MIME de Apache Commons

La codificación y decodificación de tipos MIME es un poco diferente a la implementación oficial de Java. Esta vez usamos el encodeBase64Chunked() método:

byte[] bytes = Files.readAllBytes(Paths.get("path/to/file"));
String encodedString = new String(Base64.encodeBase64Chunked(bytes));
System.out.println(encodedString);

Este código da como resultado:

IkkgbWV0IGEgdHJhdmVsbGVyIGZyb20gYW4gYW50aXF1ZSBsYW5kLA0KV2hvIHNhaWTigJTigJxU
d28gdmFzdCBhbmQgdHJ1bmtsZXNzIGxlZ3Mgb2Ygc3RvbmUNClN0YW5kIGluIHRoZSBkZXNlcnQu
Li4uIE5lYXIgdGhlbSwgb24gdGhlIHNhbmQsDQpIYWxmIHN1bmsgYSBzaGF0dGVyZWQgdmlzYWdl
IGxpZXMsIHdob3NlIGZyb3duLA0KQW5kIHdyaW5rbGVkIGxpcCwgYW5kIHNuZWVyIG9mIGNvbGQg
Y29tbWFuZCwNClRlbGwgdGhhdCBpdHMgc2N1bHB0b3Igd2VsbCB0aG9zZSBwYXNzaW9ucyByZWFk
DQpXaGljaCB5ZXQgc3Vydml2ZSwgc3RhbXBlZCBvbiB0aGVzZSBsaWZlbGVzcyB0aGluZ3MsDQpU
aGUgaGFuZCB0aGF0IG1vY2tlZCB0aGVtLCBhbmQgdGhlIGhlYXJ0IHRoYXQgZmVkOw0KQW5kIG9u
IHRoZSBwZWRlc3RhbCwgdGhlc2Ugd29yZHMgYXBwZWFyOg0KTXkgbmFtZSBpcyBPenltYW5kaWFz
LCBLaW5nIG9mIEtpbmdzOw0KTG9vayBvbiBteSBXb3JrcywgeWUgTWlnaHR5LCBhbmQgZGVzcGFp
ciENCk5vdGhpbmcgYmVzaWRlIHJlbWFpbnMuIFJvdW5kIHRoZSBkZWNheQ0KT2YgdGhhdCBjb2xv
c3NhbCBXcmVjaywgYm91bmRsZXNzIGFuZCBiYXJlDQpUaGUgbG9uZSBhbmQgbGV2ZWwgc2FuZHMg
c3RyZXRjaCBmYXIgYXdheS7igJ0NCg0KT3p5bWFuZGlhcywgYnkgUGVyY3kgQnlzc2hlIFNoZWxs
ZXk=

La decodificación es la misma que antes:

String decodedMime = new String(Base64.decodeBase64(encodedString.getBytes()));
System.out.println(decodedMime);
// Or
String anotherDecodedMime = Base64.decodeBase64(encodedString);
System.out.println(anotherDecodedMime);

Este código da como resultado:

"I met a traveller from an antique land,
Who said - “Two vast and trunkless legs of stone
Stand in the desert.... Near them, on the sand,
Half sunk a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them, and the heart that fed;
And on the pedestal, these words appear:
My name is Ozymandias, King of Kings;
Look on my Works, ye Mighty, and despair!
Nothing beside remains. Round the decay
Of that colossal Wreck, boundless and bare
The lone and level sands stretch far away.”

Ozymandias, by Percy Bysshe Shelley

Métodos auxiliares de Apache Commons

En la verdadera moda de Apache Commons, se nos presentan algunos métodos auxiliares que nos hacen la vida un poco más fácil. Por ejemplo, podemos comprobar si un String o un byte la matriz está en Base64 válida:

String originalInput = "https://Pharos.sh.com/tag/java/";
byte[] bytes = Base64.encodeBase64URLSafe(originalInput.getBytes());

System.out.println(Base64.isBase64(bytes));
// Or
System.out.println(Base64.isBase64(encodedString));

Este código daría como resultado:

true 
true

Podemos comprobar si estamos en modo seguro para URL o no:

System.out.println(Base64.isUrlSafe());

Dado que hemos codificado una cadena de URL a través del encodeBase64URLSafe() método, este código da como resultado:

true

Y finalmente, podemos comprobar si cada individuo byte de nuestra matriz está en el alfabeto Base64:

for (int i = 0; i < bytes.length; i++) {
    System.out.println(Base64.isInAlphabet(bytes[i]));
}

Conclusión

En este artículo, nos sumergimos en lo que es la codificación y decodificación, seguido de una descripción general de Base64. Hemos codificado manualmente una cadena para comprender mejor el proceso, que precede a muchos ejemplos de código.

Utilizando el Base64 class en Java nos permite hacer diferentes tipos de codificadores y decodificadores, optimizados para codificar y decodificar cadenas básicas, URL y tipos MIME.

Utilizando el Base64 clase proporcionada por Apache Commons, confiamos en la clase base para hacer la codificación directamente.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con tus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad