martes, 16 de enero de 2007

Encriptar y desencriptar passwords en Java con Blowfish

Muchas veces al desarrollar un sistema, los programadores nos vemos obligados a almacenar datos que no son de interés común a todos los usuarios que lo utilicen, mas bien son datos privados de cada usuario particular, especialmente en el caso de contraseñas o passwords, que deben permanecer almacenados manera tal que el sistema tenga conocimiento de ellos, pero no asi las personas que lo utilicen. En casos como este debemos almacenar estas cadenas de manera no legible a los usuarios.

Imagínese que tenemos la lista de usuarios con sus respectivos datos, y su contraseña almacenadas en una base de datos, y que tal base de datos caiga en manos de alguna persona con malas intenciones, ver el contenido de una db no es de lo mas difícil, esta persona podría obtener el usuario y contraseña del administrador del sistema, pudiendo asi modificar información vital del sistema, tales asi como montos, tazas de cambio, costos, salarios, etc, ocasionando perdidas a la compañía.

Pero que sucede si el campo mas importante de la fila "Password" esta encriptada?, sencillamente los datos obtenidos no servirían de nada, a no ser que los pueda desencriptar.

En este articulo, se explica como podemos encriptar y desencriptar un password (sin espacios) en otros tutoriales explicaremos como podríamos almacenar estos passwords en un archivo de texto, o una base de datos.

A continuación tenemos la clase que nos permitirá encriptar y desencriptar lo que necesitemos:

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.spec.*;
import java.io.*;

public class Blowfish {

public static String encriptar(String cleartext, String key)

throws Exception {

return crypt(cleartext, key, Cipher.ENCRYPT_MODE);

}

public static String desEncriptar(String ciphertext, String key)

throws Exception {

return crypt(ciphertext, key, Cipher.DECRYPT_MODE);

}

private static String crypt(String input, String key, int mode)

throws Exception {

// Install SunJCE provider

Provider sunJce = new com.sun.crypto.provider.SunJCE();

Security.addProvider(sunJce);

KeyGenerator kgen = KeyGenerator.getInstance("Blowfish");

kgen.init(448);

SecretKey skey = kgen.generateKey();

byte[] raw = key.getBytes();

SecretKeySpec skeySpec = new SecretKeySpec(raw, "Blowfish");

Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");

cipher.init(mode, skeySpec);

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ByteArrayInputStream bis = new ByteArrayInputStream(input.getBytes());

CipherOutputStream cos = new CipherOutputStream(bos, cipher);

int length = 0;

byte[] buffer = new byte[8192];

while ((length = bis.read(buffer)) != -1) {

cos.write(buffer, 0, length);

}

bis.close();

cs.close();

return bos.toString();

}

}

Siendo los metodos principales encriptar y desEncriptar de la clase Blowfish públicos y estáticos nos dará la facilidad de utilizarlos sin necesidad crear una instancia de la clase sino que bastara con invocar la clase y luego el metodo, de modo que podemos almacenar el resultado en una variable String de la siguiente manera:


try {

String passwordEncriptado=Blowfish.encriptar("miPassword", "llave");

}

catch (Exception ex) {

ex.printStackTrace();

}

donde:

miPassword es la contraseña que deseamos encriptar

y llave es precisamente la llave que se tendrá en cuenta para encriptar y desencriptar

Bien, ahora ya tenemos el ciphertext del password almacenada en passwordEncriptado, con un

System.out.println(passwordEncriptado); podemos ver el ciphertext que es õÛR.Â<¶ìZïúÞÆˆ}³ equivalente a miPassword

De la misma manera si queremos desencriptarlo bastara con llamar al método desEncriptar de la siguiente manera:

try {

String passwordDesencriptado=Blowfish.desEncriptar(passwordEncriptado,"llave");

}

catch (Exception ex) {

ex.printStackTrace();

}

Donde:

passwordEncriptado es el ciphertext, y la llave es la llave utilizada para encriptarlo. Observación importante: Si se utiliza una llave diferente no se podrá recuperar el password, sino que obtendremos otra cadena en vez de la original.

Si imprimimos a consola podremos ver que passwordDesencriptado = "miPassword". Tal como estaba antes de encriptarse.

Con esto ya tenemos el poder para almacenar información confidencial, dando mas seguridad al sistema en cuanto a perdida, modificaciones y robo de informaciones.

Espero este tutorial haya sido de ayuda, no dudes en escribirnos, sobre cualquier duda, tutorial o sugerencia que tengas para aportar.

1 comentario:

Jesús Bañuelos dijo...

Gracias por la info, a aplicarla se ha dicho! :D