MD5 com java

Caros amigos,
Esta rotina transforma uma String em uma cadeia de 32 caracteres (um hash)
Ela é normalmente utilizada para criptografar senha de usuários, funcionando da seguinte maneira:

  1. O sistema recebe a senha, cria um hash e armazena no banco de dados
  2. Para efetuar o login o sistema recebe a senha, passa pela mesma função (criando outro hash)
    e compara com o que está na base de dados.
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.swing.JOptionPane;

public class principal {
	
	//Função para criar hash da senha informada
	public static String md5(String senha){
		String sen = "";
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		BigInteger hash = new BigInteger(1, md.digest(senha.getBytes()));
		sen = hash.toString(16);			
		return sen;
	}
	
	public static void main(String[] args) {
		
		String senha = JOptionPane.showInputDialog("Digite uma senha:");
		String saida = "Entrada: " + senha + "\nSenha com MD5: " + md5(senha);

		JOptionPane.showConfirmDialog(null,saida, "Resultado", JOptionPane.CLOSED_OPTION);    
	}
}

Copie o codigo e salve-o como principal.java dentro do seu projeto.

Sempre às ordens,
Wellington Marinheiro

Só tomar cuidado com duas coisas.

 		BigInteger hash = new BigInteger(1, md.digest(senha.getBytes()));
 		sen = hash.toString(16);

a) “senha.getBytes()” pode dar resultados diferentes conforme seu sistema operacional. Por exemplo, no Windows em inglês o “encoding” padrão é parecido com o ISO-8859-1, e no Linux o “encoding” padrão é UTF-8. Portanto, é necessário explicitar o encoding (ou seja, algo como ‘senha.getBytes(“UTF-8”)’) para não ter problemas quando for usar a mesma base de senhas em vários sistemas operacionais.

b) Usar BigInteger para converter para hexadecimal é válido, mas você pode ter (a probabilidade é de aproximadamente 1/16 + 1/256, ou seja, 6,65%) uma string com menos de 32 caracteres. Complete o resultado com zeros à esquerda.

Apenas como observação, também… O algoritmo de hashing MD5 já está sendo considerado quebrado por grande parte dos criptólogos. Para aplicações novas, prefira os SHA.

Abraço,

Armando

Caros amigos,

Em nenhum momento eu sugeri que esta era a melhor e mais segura maneira de se fazer a coisa.
Apenas encontrei uma maneira extremanete prática de se gerar um hash de uma string utilizando MD5.

Para simplificar mais ainda, não chamem a função, façam assim:

    String s1 = "teste";
    MessageDigest md = MessageDigest.getInstance("MD5");
    BigInteger hash = new BigInteger(1, md.digest(senha.getBytes()));
    String s2 = hash.toString(16);
    System.out.println(s2);

Espero ter ajudado alguem
Wellington Marinheiro

Vocês não acham a solução da SUN tosca !?
É preciso carregar a String toda em memória para calcular o MD5. Não tentem isto com arquivos grandes.
Acho mais apropriado utilizar uma biblioteca que calcule o MD5 para um Stream.

Ocorre que para calcular o MD5 não é necessário muita memória, blocos de 128bits são calculados de cada vez e de cada bloco guarda-se os valores em 4 variáveis de 32 bits.

Eu recomendo fortemente o jigsaw da w3c cuja licença permite o uso em software proprietários .
http://www.w3.org/Jigsaw/

[]'s

[quote=rodrigousp]Vocês não acham a solução da SUN tosca !?
É preciso carregar a String toda em memória para calcular o MD5. Não tentem isto com arquivos grandes.
Acho mais apropriado utilizar uma biblioteca que calcule o MD5 para um Stream.
[/quote]
Use DigestInputStream, que faz exatamente isso.

Boa Thingol!
Minhas Desculpas para a SUN.
Agora temos a seguinte solução alternativa:

		MessageDigest md =  MessageDigest.getInstance(digestSpec);
		DigestInputStream digin = new DigestInputStream(new DataInputStream(new BufferedInputStream(new FileInputStream(filename))),md);
		byte[] buffer=new byte[BUFSIZE];
			
		while ( digin.read(buffer, 0, BUFSIZE) != - 1)
		{
			//Do nothing, the digest is calculated automatically as file is read in.	
		}
			
		digin.close();
		byte[] ret = md.digest();
		String result= convertBytetoHex(ret);
		return result;	

Genial wmarinheiro

Os caras ficam ai criticando, mas vc foi o unico que conseguiu mostrar a criptografia de forma simples!!!

Se não eficiente… ao menos foi didático!!!

Vlw mesmo.

Cara fantástico.
Mto útil mesmo. E acima de tudo Didático. :smiley:

E quanto o pessoal ter comentado que MD5 não eh tão segura pq não tentam usar Salt? :twisted:

Thx Guy!

Não é melhor usar o SHA1 ou as derivações dele? tipo SHA128 ou SHA256… Ainda a partir das variações superiores ao SHA128 não foram encontrados colisões…

[quote=wmarinheiro]Caros amigos,
Esta rotina transforma uma String em uma cadeia de 32 caracteres (um hash)
Ela é normalmente utilizada para criptografar senha de usuários, funcionando da seguinte maneira:

  1. O sistema recebe a senha, cria um hash e armazena no banco de dados
  2. Para efetuar o login o sistema recebe a senha, passa pela mesma função (criando outro hash)
    e compara com o que está na base de dados.
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.swing.JOptionPane;

public class principal {
	
	//Função para criar hash da senha informada
	public static String md5(String senha){
		String sen = "";
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		BigInteger hash = new BigInteger(1, md.digest(senha.getBytes()));
		sen = hash.toString(16);			
		return sen;
	}
	
	public static void main(String[] args) {
		
		String senha = JOptionPane.showInputDialog("Digite uma senha:");
		String saida = "Entrada: " + senha + "\nSenha com MD5: " + md5(senha);

		JOptionPane.showConfirmDialog(null,saida, "Resultado", JOptionPane.CLOSED_OPTION);    
	}
}

Copie o codigo e salve-o como principal.java dentro do seu projeto.

Sempre às ordens,
Wellington Marinheiro[/quote]

Obrigado pelo código.

vlws!

meus 5 centavos à discussão:

String key = request.getParameter("key");
MessageDigest digest = MessageDigest.getInstance("MD5");
String secret = "xpto";// secret could change constantly
long tStamp = System.currentTimeMillis();
tStamp = tStamp - (tStamp % 15000);// valid for 15 seconds
System.out.println(tStamp);
digest.update((secret + ":" + tStamp).getBytes());
byte[] hash = digest.digest();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
for (byte b : hash)
ps.printf("%02x", 0xFF & b);
String pass = new String(baos.toByteArray());
System.out.println("key:\t" + key);
System.out.println("pass:\t" + pass);

Aqui o truque para evitar hashes quebrados reside no ‘ps.printf("%02x", 0xFF & b);’.

Não existe uma biblioteca nativa que possua um método pra gerar o hash md5 de forma automática?
Me surpreendi ao perceber que é necessário tratar o hash gerado…até em php tem um método nativo…

[quote=gRoOve]Não existe uma biblioteca nativa que possua um método pra gerar o hash md5 de forma automática?
Me surpreendi ao perceber que é necessário tratar o hash gerado…até em php tem um método nativo…[/quote]

“Automática” quer dizer que você precisa de sua representação em formato String, é isso?

Poxa amigo ajudou demais, estava penando nesse assunto, muito grato.

[quote=wmarinheiro]Caros amigos,

Em nenhum momento eu sugeri que esta era a melhor e mais segura maneira de se fazer a coisa.
Apenas encontrei uma maneira extremanete prática de se gerar um hash de uma string utilizando MD5.

Para simplificar mais ainda, não chamem a função, façam assim:

    String s1 = "teste";
    MessageDigest md = MessageDigest.getInstance("MD5");
    BigInteger hash = new BigInteger(1, md.digest(senha.getBytes()));
    String s2 = hash.toString(16);
    System.out.println(s2);

Espero ter ajudado alguem
Wellington Marinheiro
[/quote]

Vlws pelo tópico, me ajudou muito.

Flws

Se eu colocar o getBytes(“UTF-8”); o método toString continuaria recebendo o parâmetro 16?