MD5 com java

17 respostas
wellington_marinheir

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

17 Respostas

T

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.

A

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

wellington_marinheir

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

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.

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

T

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.

Use DigestInputStream, que faz exatamente isso.

rodrigousp

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;
hmgsouza

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.

Mandrake6

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!

xjunior

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…

lsouzabr

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

Obrigado pelo código.

wallashss

vlws!

Sombriks

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);’.

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…

E

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…

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

kaizerslawten

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

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

jefaokpta

Vlws pelo tópico, me ajudou muito.

Flws

brunoGama

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

Criado 27 de novembro de 2006
Ultima resposta 24 de jan. de 2009
Respostas 17
Participantes 15