¡Buenas! Hoy les voy a traer algunos conceptos de encriptación y cómo Java los soporta.
Supongamos que tenemos una aplicación en la que almacenamos información confidencial y no queremos que sea mostrada como texto plano o en el código de la aplicación, entonces es aquí donde entra la criptografía.
Dentro de la criptografía existen varios algoritmos con diferentes características. Nosotros hoy veremos los Algoritmos de Digestión de Mensajes o de Hash acompañados de una pequeña implementación sobre su uso en Java.
Algoritmos de Digestión de Mensajes
Estos algoritmos son tales que, a partir de un mensaje y mediante ciertas operaciones matemáticas, generan otro mensaje denominado ‘Huella Digital’ (que según el algoritmo que usemos puede ser de tamaño fijo o no) que cumple con las siguientes características:
- Es incomprensible a simple vista.
- Cada huella es única para cada mensaje.
- Dos huellas son iguales si y solo si el mensaje original también lo es.
- Es unidireccional, es decir que no se puede reconstruir el mensaje original a partir de su huella digital.
Usaremos este método para probar los distintos algoritmos de digestión que soporta Java mediante la clase MessageDigest:
public static String digest(String str, String alg) {
try {
MessageDigest md = MessageDigest.getInstance(alg);
// Indicamos el algoritmo a usar
return new String(md.digest(str.getBytes()));
// 'Digerimos' el mensaje
} catch (NoSuchAlgorithmException e) {
System.out.println("el algoritmo " + alg + " no existe");
return null;
}
}
Algoritmos y sus resultados:
·MD2: digest("lineadecodigo", "MD2") -> zA��&�#K��F%5 ·MD5: digest("lineadecodigo", "MD5") -> �e����_m9E �S�* ·SHA1: digest("lineadecodigo", "SHA-1") -> &�4!�7�Rr�6/�fs� ·SHA256: digest("lineadecodigo", "SHA-256") -> c�� �j 21��?։��*����,l��� ·SHA384: digest("lineadecodigo", "SHA-384") -> pNƒ+���u��w�g;���� �:Yc�( ·SHA512: digest("lineadecodigo", "SHA-512") -> O� ���i�Q�>��G�8���o�C[:-�ga4:�n3hg�Ѻ�"�o~�Ǡ�#0�(�
Incomprensible, ¿verdad? ¡Esa es la idea! Pero… ¿cómo se usan?
La idea del siguiente ejemplo hace hincapié en las propiedades de las huellas digitales mencionadas anteriormente:
Supongamos que tenemos una aplicación en la que se requiere que los usuarios se identifiquen mediante Nombre de Usuario y Contraseña, y que a su vez estos datos deben estar guardados en algún medio de almacenamiento como archivo/s o una base de datos.
El problema surge con las contraseñas, ya que por ninguna razón estas pueden estar en texto plano, por lo que una buena opción seria encriptarlas mediante algunos de los algoritmos mencionados previamente y mantenerlas almacenadas de esta forma.
Dicho esto, nos remitimos al ejemplo:
Para hacer las cosas más simples vamos a representar nuestro almacenamiento como un Mapeo o Mapa de Usuarios(String) a Contraseñas(String).
Primero que nada, debemos crear el almacenamiento de prueba para el ejemplo:
// Almacenamiento de los datos de los usuarios
protected Map usuarios;
public EjemploLogin() {
usuarios = new HashMap();
// Se usara el algoritmo SHA-256 (usuarioX -> passwordX)
usuarios.put("usuario1", "���D*ƅ�A���M=2�{�5D/i��N");
usuarios.put("usuario2", "l�ռ��x5*�3`�?�N���Y���H]xp�");
usuarios.put("usuario3", "Y�6~-(de�e�뵬?Z�U");
usuarios.put("usuario4", "�xs�s���օ��^_��ϸ>�&�f@��8P+");
}
Si te preguntas porque declaré al mapeo con esto: <String, String> te invito a que leas sobre tipos genéricos en Java, un tema realmente interesante y extremadamente útil, sobre todo para reutilización de código :)
Una vez hecho esto, deberíamos brindar un servicio que permita a un usuario acceder al sistema mediante su nombre de usuario y su contraseña:
public boolean login(String usuario, String password) {
// Obtenemos la huella digital de su contraseña almacenada
String huella_password = usuarios.get(usuario);
// Comprobamos que esta existe
if (huella_password == null)
return false;
else {
// Digerimos la contraseña ingresada
String huella = Digestion.digest(password, "SHA-256");
// En caso de que las huellas sean iguales por la propiedad 3 sabemos
// las contraseñas también lo son.
return huella_password.equals(huella);
}
}
Recuerden siempre ser consistentes y usar el mismo algoritmo de digestión tanto al generar las huellas para almacenar como al generarlas para hacer la comprobación.
Finalmente, les dejo unos casos de prueba para que verifiquen si todo salió bien:
login("usuario1", "password1"); -> true
login("usuario2", "123456789"); -> false
login("usuario3", "password3"); -> true
login("usuario4", "abcdefghi"); -> false