Algoritmo para aplicar Base64

[La presente se encuentra disponible tambien en mi blog Explotandocodigo]

Si hay algo que aveces se requiere realizar es codificar un archivo binario a texto ASCII y viceversa, si este es tu caso puedes utilizar Base64, el cual es muy sencillo y rápido de implementar aunque no es del todo seguro.

Los usuarios de PHP pueden hacer uso de las funciones nativas base64_encode y base64_decode,los de Python pueden importar el paquete base64 para servirse de este, de todas formas puedes usar la siguiente herramienta en linea llamada Binary File to Base64 Encoder / Translator, ver referencia [1].

Ahora que si deseas realizar algún tipo de encriptado para tu proyecto con un mínimo de esfuerzo, puedes optar por la biblioteca jasypt, ver referencia [4].

Introduccion

¿Que es BASE64 y donde se utiliza?

El Base64 Content-Transfer-Encoding está diseñado para representar secuencias arbitrarias de octetos en una forma que no necesita ser humanamente legible. Los algoritmos de codificación y decodificación son simples, pero los datos codificados son sistemáticamente sólo alrededor del 33% más grande que los datos sin codificar.

Esta compuesta por un subconjunto 65 de caracteres US-ASCII, permitiendo 6 bits para ser representados por caracteres imprimibles. (El 65° carácter adicional, "=", se utiliza para significar una función específica para la transformación.)

Aquí 3 Bytes se representan con una cadena de texto de 4 caracteres,en total estos 24 bits se subdividen en agrupaciones de 6 bits, cada uno de los cuales se traduce en un solo dígito en el alfabeto base64. En otras palabras estos 6 bits se usan como índice en una matriz de 64 caracteres imprimibles.

Todos los saltos de línea, espacios en blanco u otros caracteres que no se encuentra en la Tabla 1 deben de ser ignorado por el software de decodificación.

Esta codificación es prácticamente idéntica a la utilizada en la privacidad de Correo Mayor (PEM), también en la URL's de algunos sitios, PGP, Thunderbird y Evolution lo ocupan para el cifrado de contraseñas en los correos entre otros. Ver referencia [2].

Codificación Base64 en las URL's

Esta codificación puede ser nombrada como "base64url" y no debe considerarse igual que "base64". Esta es técnicamente idéntica a la anterior, a excepción de del carácter 62 y 63 del alfabeto, una alternativa al alfabeto sugerido es utilizar "~" como carácter en la posición 63. Debido a que el carácter "~" tiene un significado especial en algunos entornos de sistema de archivos, aunque no se recomienda.

Se ocupa para apuntar a algún nombre de archivo o dirección de manera segura en la web, es por ello que hay URL's que son lo suficientemente cortas como para cortar y pegar.Por eso la codificación de seis bits por carácter (base 64) que es mucho mejor que la codificación de cinco bits por carácter (base 32).

Por ejemplo:

http://localhost:4004/id/1b17864eeb6c68294c9b2db0324a2b773401f0da0537d82626c24a7850e15ef2d6c4265dcd5e85f1

La misma URL en base64:

http://localhost:4004/id/GxeGTutsaClMmy2wMkordzQB8NoFN9gmJsJKeFDhXvLWxCZdzV6F8Q

Se puede deducir entonces que Base64 es 17% mas compacto que Base32

Desarrollo

He implementado una clase para realizar el codificado, la cual se llama Base64Encoder.java la cual esta disponible desde este enlace [3]. En cuanto tenga listo el decodificador lo publicare aquí.

Codificacion

  1 package encode;
  2
  3 /**
  4  * @author Gabriel Mtz. Nájera
  5  */

  6 public class Base64Encoder {
  7     private static StringBuilder sb = new StringBuilder();
  8    
  9     public static String[] mapInt2Str = {
 10         "a","b","c","d","e","f","g","h",
 11         "i","j","k","l","m","n","o","p",
 12         "q","r","s","t","u","v","w","x",
 13         "y","z","A","B","C","D","E","F",
 14         "G","H","I","J","K","L","M","N",
 15         "O","P","Q","R","S","T","U","V",
 16         "W","X","Y","Z","0","1","2","3",
 17         "4","5","6","7","8","9","+","/"
 18     };
 19  
 20     /**
 21      * @param data un array de 3 bytes con los datos a codificar
 22      * @param ioff
 23      * @return String
 24      * @throws java.lang.Exception
 25      */

 26     public static String encodeBase64(byte[] data, int ioff)throws Exception{
 27         sb = new StringBuilder("");
 28         if (ioff > 0) {
 29            
/*
30-32              
*/

 33             int i0 = (data[0] & 0x3f);
 34             sb.append(mapInt2Str[i0]);
 35             if (ioff > 1) {
/*36-42*/
 43                 int i1 = ((data[1] & 0x0f) << 2) | ((data[0] & 0xc0) >> 6);
 44                 sb.append(mapInt2Str[i1]);
 45                 if (ioff > 2) {
 46                    
/*47-52*/
 53                     int i2 = ((data[2] & 0x03) << 4) | ((data[1] & 0xf0) >> 4);
 54                     sb.append(mapInt2Str[i2]);
 55                    
/*56-58*/
 59                     int i3 = ((data[2] & 0xfc) >> 2);
 60                     sb.append(mapInt2Str[i3]);
 61                 }
 62             }
 63         }        
 64         return sb.toString();
 65     }
 66     /**
 67      * Codifica
 68      * Se leen 3 bytes y se obtiene la cadenas de texto de 4 caracteres
 69      * @param sInputFilePath La ruta de binario
 70      * @return String codificación del archivo
 71      */

 72     public static String encodeBinaryData(String sInputFilePath){
 73         String sBase64Data = "";      //codificada
 74         java.io.BufferedInputStream bis = null; //lectura
 75         StringBuilder strb = new StringBuilder();//escritura
 76         try{
 77             bis = new java.io.BufferedInputStream(
 78                     new java.io.FileInputStream(sInputFilePath)
 79                     );
 80             int iReadBytes = 0;
 81             byte data[] = new byte[3];
/*82-85*/
 85             while( (iReadBytes = bis.read(data, 0,3)) != -1){
 86                 strb.append( Base64Encoder.encodeBase64(data, iReadBytes) );
 87                 //System.out.println("Escribe:"+strb);
 88             }
 89             sBase64Data = strb.toString();
 90         }catch(Exception ex){
 91             sBase64Data = null;
 92             System.out.println( ex.getMessage() );
 93         }finally{
 94             try {
 95                 if (bis != null) bis.close();
 96             } catch (java.io.IOException ex) {
 97                 System.out.println( ex.getMessage() );
 98             }
 99         }        
100         return sBase64Data;
101     }
102
103 }
104
105
Si prefieres ver la documentacion de la clase, lo puedes hacer desde este enlace [3]

Enlaces y referencias

[1]http://www.greywyvern.com/code/php/binary2base64
[2]http://www.ietf.org/rfc.html (The Internet Engineering Task Force)

- REQUEST FOR COMMENTS -

2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of
Internet Message Bodies. N. Freed, N. Borenstein. November 1996.
(Format: TXT=72932 bytes) (Obsoletes RFC1521, RFC1522, RFC1590)
(Updated by RFC2184, RFC2231, RFC5335) (Status: DRAFT STANDARD)

2046 Multipurpose Internet Mail Extensions (MIME) Part Two: Media
Types. N. Freed, N. Borenstein. November 1996. (Format: TXT=105854
bytes) (Obsoletes RFC1521, RFC1522, RFC1590) (Updated by RFC2646,
RFC3798, RFC5147) (Status: DRAFT STANDARD)

3548 The Base16, Base32, and Base64 Data Encodings. S. Josefsson, Ed..
July 2003. (Format: TXT=26363 bytes) (Obsoleted by RFC4648) (Status:
INFORMATIONAL)

4648 The Base16, Base32, and Base64 Data Encodings. S. Josefsson.
October 2006. (Format: TXT=35491 bytes) (Obsoletes RFC3548) (Status:
PROPOSED STANDARD)

5335 Internationalized Email Headers. Y. Abel, Ed.. September 2008.
(Format: TXT=27945 bytes) (Updates RFC2045, RFC2822) (Status:
EXPERIMENTAL)

[3] http://www.usuarios.lycos.es/exploit4fun/Source_code/encode/Base64Encode...
[4] http://www.jasypt.org/

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

Base64 para URLs

La opción común para usar Base64 en URL's es cambiar los caracteres 63 y 64 por - y _ en vez de + y / porque estos dos últimos son especiales para URL's.

Given the choice of dancing pigs and security, users will choose dancing pigs, every single time. - Steve Riley

base64url

La verdad es que es interesante, pero creo que es mucho mejor utilizar el Content-Transfer-Encoding=gzip y utilizar este algoritmo de compresion para enviar y recibir los datos, los navegadores lo manejan y es el que utiliza por ejemplo google para enviar las paginas.

Imagen de ezamudio

Almacenamiento

Base64 no es un algoritmo de compresión de datos, de hecho te infla 25% los datos que codificas; es un algoritmo para codificar datos binarios como texto para su transmisión o almacenamiento en medios que no permiten transmisión de datos binarios (incluso en sistemas viejos que manejan caracteres de 7 bits).

Se usa también por ejemplo en mails encriptados ya sea con certificados X509 o con PGP, asi como attachments de mail (si ves algun mensaje de correo que traiga un archivo anexo o una imagen, etc y ves el "código fuente" de ese mail, verás que los attachments vienen codificados en base64).

Los certificados X509, llaves privadas y públicas de RSA o DSA (por ejempo para SSH o PGP) se almacenan en base 64, precisamente para poder enviarlas en un mail y que se puedan guardar en un archivo de texto simple sin ningún formato especial.

Los passwords en UNIX/Linux se guardan en base64, revisa tu /etc/passwd

Si quieres incluir en un URL algún dato encriptado como lo menciona el post original, lo mejor es que lo pongas en base 64.

En todos los casos anteriores podrías usar hexadecimal pero entonces el tamaño de los datos se te va al doble (dos caracteres por cada byte de datos) y con base64 solamente crece 25% (4 caracteres por cada 3 bytes de datos).

Given the choice of dancing pigs and security, users will choose dancing pigs, every single time. - Steve Riley

Imagen de benek

Tienes idea de cómo lo

Tienes idea de cómo lo hacen en PGP? ... Me imagino que el usuario elige una llave y en base a ella el algoritmo obtiene el resultado, es correcto?

Como comentario, en la mayoría de sistemas UNIX y Linux (de unos años para acá) ya se utilizan Shadow Passwords, por lo que la contraseña encriptada ya no está en /etc/passwd sino en /etc/shadow (al que solo puede acceder root) y ya no está encriptada con Base64 sino en MD5 en la mayoría de los casos o algunas ocasiones en DES.

--
Javier Benek

Imagen de ezamudio

codificación != encripción

Base64 no es un algoritmo de encripción por lo que nada puede estar encriptado en base64 (sería muy malo usarlo para encripción porque no tiene usa una llave y por lo tanto cualquiera puede decodificar datos codificados en base64). MD5 tampoco es encripción, es una digestión de mensaje o hash, y el resultado de MD5 son 128 bits, los cuales puedes codificar en hexadecimal, que te da una cadena de 32 caracteres, o en base64, que te da una cadena como de 20 caracteres (el proceso de MD5 es irreversible, no puedes obtener los datos originales a partir del MD5, es como querer obtener una vaca a partir de carne molida). No veo cómo se puede usar DES para encriptar passwords, pues necesitas otra llave distinta para poder decriptarlos, además que realmente no necesitas decriptar un password nunca; para validarlo simplemente encriptas o digieres (con MD5 o SHA) lo que el usuario te da como password y luego lo comparas con lo que tienes almacenado y listo (generalmente hay que agregarle sal antes de digerirlo para que dos usuarios con el mismo password tengan distintos hashes y evitar ataques, pero bueno ya son detalles de implementación).

PGP es encripción con llave pública y es un tema aparte. Alguna vez di una plática sobre encripción simétrica y asimétrica en la Comunidad Java, podría darla ahora en las reuniones que están haciendo aunque como ya les dije, no puedo en la de enero, pero a ver si para la de febrero ya me lanzo y puedo dar esa plática nuevamente.

PGP explicado rapidito en un párrafo: se genera el par de llaves aleatoriamente y el usuario elige un passphrase para encriptar la llave privada; para firmar mensajes se saca un MD5 del mensaje y se encripta con la llave privada; para encriptar mensajes necesitas la llave pública del recipiente, generas una llave aleatoria AES o 3DES y encriptas el mensaje con esa llave, que a su vez encriptas con la llave pública del recipiente. Los resultados de haber encriptado cualquier cosa (el hash, el mensaje completo etc) son binarios y para enviarlos por mail se codifican en base64.

Given the choice of dancing pigs and security, users will choose dancing pigs, every single time. - Steve Riley

Imagen de benek

Wow, muy interesante.

Wow, muy interesante. Estaría muy bien tu idea de que en próximas reuniones pudieras hablarnos más a detalle sobre esto.

Gracias por resolver mi duda.

--
Javier Benek

Imagen de gabo

Ya esta echa...

Revisando el proyecto Limewire; me encontre una clase que ya lo implementa org.apache.commons.codec.binary.Base64

Imagen de Shadonwk

interezante ...

interezante ... interezante... habria que ver la manera de asistir a la reunion ya que ahora es menos posible ir porque estoy hasta campeche.. pero pueden subir un buen video de la platica estaria excelente