domingo, 19 de enero de 2014

Como usar SHA en Java (hash texto)

En esta ocasión vamos a aprender a crear un password usando el algoritmo de SHA(Secure Hash Algorithm) sea 1,256,512,etc.

Para hacerlo es muy sencillo ya que java tiene librerías preparadas para esto,lo único que tenemos que hacer unas cuantas acciones con bytes.

Lo primero que tenemos que hacer es crear una instancia de un proveedor de seguridad(el encargado de darnos los algoritmos):

Por ejemplo : SHA-1 o SHA-256

Debemos importar:

import java.security.MessageDigest; // Para crear el hash

import java.security.NoSuchAlgorithmException; // Para manejar error

Vamos a definir una String que sera el texto pasado a SHA :

String password = "Tiempo de Tux"; 

Tenemos que obtener los bytes del String para trabajarlos,creamos un array de bytes:

byte[] passB = password.getBytes(); 

Ahora tenemos que crear la instancia de SHA:

 MessageDigest messageD = MessageDigest.getInstance("SHA-1");

Le pasamos el array de bytes como un update ya que solo es una instancia de momento:

messageD.update(passB);

Creamos otro array de bytes pero esta vez sera el hash devuleto por la funcion digest de la instancia de SHA:

byte[] bytes = messageD.digest();

Por ultimo debemos convertir los bytes a base 16 o base 64,como hexadecimal es mas fácil al usar los mismos tipos de datos del lenguaje,asi que vamos a usar este:

1
2
3
4
5
6
7
8
9
StringBuilder passS = new StringBuilder(); // Para usar una String mutable

for (byte b : bytes) { // Convertimos a hex
   passS.append(String.format("%02x:", b));
}

String finalStringSha = passS.toString();

System.out.println(finalStringSha);


Eso es todo ya solo falta compilar y ejecutar.

Aquí un código completo:


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

class Ejemplo {
	public static void main(String[] args) throws NoSuchAlgorithmException {

		if (args.length == 0) {
			uso();System.exit(1);
		}
		String AGM,password;
		if (args[0].equals("-s256"))
			AGM = "SHA-256";
		else if (args[0].equals("-s512"))
			AGM = "SHA-512";
		else 
			AGM = "SHA-1";
		
		if (args.length == 1) {
			password = args[0];
		} else {
			password = args[1];
		}
		
		byte[] passB = password.getBytes();

		MessageDigest messageD = MessageDigest.getInstance(AGM);

		messageD.update(passB);

		byte[] bytes = messageD.digest();

		StringBuilder passS = new StringBuilder();

		for (byte b : bytes) {
			passS.append(String.format("%02x:", b));
		}

		String finalStringSha = passS.toString();

		System.out.println(finalStringSha);

	}
	
	private static void uso() {
		System.out.println("Uso:");
		System.out.println("Programa Algoritmo ");
		System.out.println("Algoritmos: ");
		System.out.println("-s1 SHA-1");
		System.out.println("-s256 SHA-256");
		System.out.println("-s512 SHA-512");
	}

}

Lo compilan y lo ejecutan así por ejemplo:

java Ejemplo -s256 Linux


Eso es todo.

2 comentarios:

  1. Gracias por el post.
    Sólo un par de apuntes:

    En general, al usar el método getBytes() de Strings, especificar SIEMPRE el charset o codificación de caracteres, para obtener resultados coherentes. De no especificarlo, se toma la referencia de la plataforma y podrías obtener resultados diferentes en función del sistema y/o su configuración.

    Por otro lado, Strings.format es relativamente costoso (por si funcionamiento interno). Si vanos a realizar la operación a menudo, en un servidor por ejemplo, convendría sustituirla por una operación a medida, que no use String ni Formatter, y que opere en un espacio de memoria mínimo. También podemos delegar el trabajo a la clase Hex de Apache Commons Codec, aunque eso, claro, supone descargar el Jar correspondiente y meterlo en el Classpath.

    Un saludo!

    ResponderBorrar
    Respuestas
    1. O:

      Gracias por los apuntes,en lo de getbytes() tienes razon es bueno especificar el charset,aunque se tiene que añadir en un manejo de excepciones y podria dar el mismo resultado si muestra un problema con el encoding,lo mejor seria usar utf-8:

      try {
      passB = password.getBytes( "UTF-8" );
      } catch (UnsupportedEncodingException e) {
      passB = password.getBytes();
      }

      Y sobre lo de string format,es pesado si,pero muchas cosas en java son pesadas,podemos usar:

      String x = Integer.toHexString(0xFF & b);
      if (x.length() == 1)
      passS.append('0');
      passS.append(x);
      passS.append(":");

      Saludos :D

      Borrar

Los comentarios serán revisados antes de ser publicados.