O hash é uma forma útil para transformar uma imensa quantidade de bytes em uma sequência menor de bytes.
Esta forma de transformação é denominada de dispersão, ou seja, você tem um conteúdo original não importando seu tamanho em bytes e então processa o hash deste conteúdo para obter o valor hash bem menor desde 2 bytes até 64 bytes. Normalmente este valor é convertido para hexadecimal para o tornar inteligível.
Os métodos de hash mais comuns produzem em Java valores de 128 até 512 bits. Por se tratar apenas de um método para dispersão e não de geração de chaves exclusivas, os hashs de conteúdos distintos podem resultar no mesmo valor, porém remotamente ocorre.
A possibilidade de um valor de hash coincidir para conteúdos distintos torna-se mais remota a medida em que o resultado aumenta (128 até 512 bits), a dispersão. Portanto, saber qual método hash a ser utilizado depende muito da aplicação e deve ser avaliado pelo projetista do sistema.
Os valores em hash são reversíveis dependendo do tamanho do conteúdo e nível de dispersão utilizado. Quanto maior a frase (conteúdo para processar o hash) e o método de dispersão forem, mais difícil fica para um fraudador tentar identificar a frase original.
Se a frase for pequena como é o caso de senhas, o melhor é usar de ofuscamento adicionando constantes maiores para aumentar a chave e até mesmo números aleatórios, desde que estes sejam armazenados no cadastro de senhas.
Vale deixar claro que qualquer método de hash é unidirecional, ou seja, só encripta, não decripta por padrão.
Se você decidir por encriptar uma senha via um método hash, a única maneira legal para conferir a senha é pegar a próxima senha que o usuário informar e passar pelo mesmo método de hash para saber se coincide com o hash armazenado no momento do cadastro da senha. Isso vale para todas as aplicações com hash porque ele e unidirecional por padrão.
Os métodos de hash mais comuns em Java por ordem de menor até a maior dispersão são:
- MD5
- SHA-1
- SHA-256
- SHA-384
- SHA-512
Em que aplica hash?
Uma classe para testar!
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HashTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
// Frase para gerar o hash
String phrase = "my phrase is anything, who cares?";
MD5Test(phrase);
SHATest(phrase);
SHA256Test(phrase);
SHA384Test(phrase);
SHA512Test(phrase);
}
public static void MD5Test(String phrase) throws NoSuchAlgorithmException {
String hashMethod = null;
byte[] result = null;
/************************
* MD5 Test
************************/
hashMethod = "MD5";
MessageDigest digest = MessageDigest.getInstance(hashMethod);
digest.reset();
digest.update(phrase.getBytes());
result = digest.digest();
System.out.println(String.format("Hash method: %s, Byte size: %d - Bit size: %d - Hash value: %s\n", hashMethod, result.length, result.length * 8, byteArrayToHex(result, true)));
}
public static void SHATest(String phrase) throws NoSuchAlgorithmException {
String hashMethod = null;
byte[] result = null;
/************************
* SHA Test
************************/
hashMethod = "SHA";
MessageDigest digest = MessageDigest.getInstance(hashMethod);
digest.reset();
digest.update(phrase.getBytes());
result = digest.digest();
System.out.println(String.format("Hash method: %s, Byte size: %d - Bit size: %d - Hash value: %s\n", hashMethod, result.length, result.length * 8, byteArrayToHex(result, true)));
}
public static void SHA1Test(String phrase) throws NoSuchAlgorithmException {
String hashMethod = null;
byte[] result = null;
/************************
* SHA1 Test
************************/
hashMethod = "SHA-1";
MessageDigest digest = MessageDigest.getInstance(hashMethod);
digest.reset();
digest.update(phrase.getBytes());
result = digest.digest();
System.out.println(String.format("Hash method: %s, Byte size: %d - Bit size: %d - Hash value: %s\n", hashMethod, result.length, result.length * 8, byteArrayToHex(result, true)));
}
public static void SHA256Test(String phrase) throws NoSuchAlgorithmException {
String hashMethod = null;
byte[] result = null;
/************************
* SHA256 Test
************************/
hashMethod = "SHA-256";
MessageDigest digest = MessageDigest.getInstance(hashMethod);
digest.reset();
digest.update(phrase.getBytes());
result = digest.digest();
System.out.println(String.format("Hash method: %s, Byte size: %d - Bit size: %d - Hash value: %s\n", hashMethod, result.length, result.length * 8, byteArrayToHex(result, true)));
}
public static void SHA384Test(String phrase) throws NoSuchAlgorithmException {
String hashMethod = null;
byte[] result = null;
/************************
* SHA384 Test
************************/
hashMethod = "SHA-384";
MessageDigest digest = MessageDigest.getInstance(hashMethod);
digest.reset();
digest.update(phrase.getBytes());
result = digest.digest();
System.out.println(String.format("Hash method: %s, Byte size: %d - Bit size: %d - Hash value: %s\n", hashMethod, result.length, result.length * 8, byteArrayToHex(result, true)));
}
public static void SHA512Test(String phrase) throws NoSuchAlgorithmException {
String hashMethod = null;
byte[] result = null;
/************************
* SHA512 Test
************************/
hashMethod = "SHA-512";
MessageDigest digest = MessageDigest.getInstance(hashMethod);
digest.reset();
digest.update(phrase.getBytes());
result = digest.digest();
System.out.println(String.format("Hash method: %s, Byte size: %d - Bit size: %d - Hash value: %s\n", hashMethod, result.length, result.length * 8, byteArrayToHex(result, true)));
}
public static String byteArrayToHex(byte[] bytes, boolean useSpace) {
StringBuffer retorno = new StringBuffer();;
if (bytes==null || bytes.length==0) {
return retorno.toString();
}
// Com espaço
if (useSpace) {
for (int i=0; i<bytes.length; i++) {
byte valor = bytes[i];
int d1 = valor & 0xF;
d1 += (d1 < 10) ? 48 : 55;
int d2 = (valor & 0xF0) >> 4;
d2 += (d2 < 10) ? 48 : 55;
retorno.append((char) d2);
retorno.append((char) d1);
retorno.append(" ");
}
// Sem espaço
} else {
for (int i=0; i<bytes.length; i++) {
byte valor = bytes[i];
int d1 = valor & 0xF;
d1 += (d1 < 10) ? 48 : 55;
int d2 = (valor & 0xF0) >> 4;
d2 += (d2 < 10) ? 48 : 55;
retorno.append((char) d2);
retorno.append((char) d1);
}
}
return retorno.toString();
}
}
Os resultados:
Hash method: SHA, Byte size: 20 - Bit size: 160 - Hash value: 9C C9 C2 2F 56 34 4D 5F 37 AB 18 92 63 0D 28 AB AB AA 0C B3
Hash method: SHA-256, Byte size: 32 - Bit size: 256 - Hash value: 9D D9 0A BD 74 BD 57 24 F7 3E DB 6B 27 43 C7 9D 11 4D B3 0C 21 65 A8 3D C2 71 CF 6B 59 A6 4F A6
Hash method: SHA-384, Byte size: 48 - Bit size: 384 - Hash value: 24 AF A2 1A 5F CD C2 1E 31 92 EB 29 16 5D 8D 4B 31 25 45 60 E3 D9 ED 30 71 3E D8 E8 24 1E E3 35 FE 9D 41 18 9B 09 31 A8 C1 71 37 81 59 0A C1 E1
Hash method: SHA-512, Byte size: 64 - Bit size: 512 - Hash value: 3C BE 76 C0 1F 34 0A 7E 25 F9 D4 8B AC B6 1B 17 26 87 39 A3 AC 4D 43 72 FB B2 A9 0E B9 3D 03 D0 3E 4C 91 2D 25 12 49 E1 F9 2A AF 8D 9F FC 8C BF D2 10 FB B0 CB 65 CF 12 A7 71 09 7B 10 CE 21 75
Boa sorte.
Excelente artigo. Os Hashs são passiveis de combinações iguais, porque são apenas mais um mecanismo de garantir a integridade de um determinado conjunto de dados.
ResponderExcluirPara se ter um exemplo um CRC que basicamente é um HASH com o objetivo de identificar falhas na transmissão de dados pode ocorrer de vir danificado ou duplicado por causa da quantidade de situações que podem aparecer de forma identicas.