Translate

quinta-feira, 15 de agosto de 2013

Hash, o que é e como utilizar?

O que é hash?

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.

Compreendendo alguns métodos de hash:

Os métodos de hash mais comuns em Java por ordem de menor até a maior dispersão são:

  1. MD5
  2. SHA-1
  3. SHA-256
  4. SHA-384
  5. SHA-512

Em que aplica hash?

Normalmente os hash são uma forma de ofuscar senhas, gerar uma assinatura de um arquivo para conferir sua integridade, gerar tokens, certificados digitais, códigos de barras etc, justamente por se tratar de uma forma de dispersão simples.

Uma classe para testar!

A classe a seguir testa os tipos de hash mencionados, fique a vontade para trocar a frase na variável phrase do método main da classe. Fique atento, pois se você ter uma arquivo com muitos GB para calcular o hash, bastar dividi-lo em blocos menores e passar os bytes de cada bloco para a função update de digest:

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: MD5, Byte size: 16 - Bit size: 128 - Hash value: 61 A5 23 38 E3 CF A1 E1 1B 6E B0 99 C6 CB EB BA 

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.

Um comentário:

  1. 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.

    Para 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.

    ResponderExcluir