Pergunta

Eu recentemente comecei a olhar para MD5 hashing (em Java) e enquanto eu encontrei algoritmos e métodos para me ajudar a conseguir isso, estou me perguntando como ele realmente funciona.

Por um lado, eu encontrei o seguinte a partir esta URL :

private static String convertToHex(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));
                halfbyte = data[i] & 0x0F;
            } while(two_halfs++ < 1);
        }
    return buf.toString();
}

Eu não encontrei nenhuma necessidade de usar bit-shifting em Java por isso estou um pouco enferrujado sobre isso. Alguém gentil o suficiente para ilustrar (em termos simples) como é que o código acima faz a conversão? ">>>"?

Eu também encontrou outras soluções no StackOverflow, como aqui e aqui , que usa BigInteger em vez disso:

try {
   String s = "TEST STRING";
   MessageDigest md5 = MessageDigest.getInstance("MD5");
   md5.update(s.getBytes(),0,s.length());
   String signature = new BigInteger(1,md5.digest()).toString(16);
   System.out.println("Signature: "+signature);

} catch (final NoSuchAlgorithmException e) {
   e.printStackTrace();
}

Por que é que isso funciona também, e de que maneira é mais eficiente?

Obrigado pelo seu tempo.

Foi útil?

Solução

private static String convertToHex(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {

Até este ponto ... apenas básico configurar e iniciar um loop para percorrer todos os bytes na matriz

        int halfbyte = (data[i] >>> 4) & 0x0F;

bytes quando convertido para hex são dois dígitos hexadecimais ou 8 dígitos binários, dependendo do que basear você olhar para ele. As mudanças declaração acima dos altos 4 bits para baixo (>>> é mudança não assinado direita) e ANDs lógicas com 0000 1111 de modo a que o resultado é um número inteiro igual ao elevados 4 bits do byte (primeiro dígito hex).

Say 23 foi uma entrada, este é 0001 0111 em binário. As marcas de turno e abrigos lógicas e isso para 0000 0001.

        int two_halfs = 0;
        do {

Isso só configura a fazer / while para executar duas vezes

            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));

Aqui nós estamos exibindo o dígito hex real, basicamente, apenas usando a zero ou um personagem como um ponto de partida e deslocando-se para o caractere correto. O primeiro se as tampas declaração todos os dígitos 0-9, e a segunda tampas de todos os dígitos 10-15 (a-f em hexadecimal)

Mais uma vez, usando o nosso exemplo 0000 0001 em decimal é igual a 1. Nós pego no superior se o bloco e adicionar 1 para o caractere '0' para obter o personagem '1', acréscimo que para a cadeia e seguir em frente .

                halfbyte = data[i] & 0x0F;

Agora vamos configurar o inteiro para apenas igualar os bits baixos do byte e repita.

Mais uma vez, se a nossa entrada foi de 23 ... 0001 0111 após a lógica AND torna-se apenas 0000 0111 que é de 7 em decimal. Repita a mesma lógica acima eo caráter '7' é exibido.

            } while(two_halfs++ < 1);

Agora nós apenas passar para o próximo byte na matriz e repetir.

        }
    return buf.toString();
}

Para responder a sua pergunta seguinte, a API Java já tem um utilitário de conversão de base construída para BigInteger já. Veja a toString (radix int ) documentação .

Não sabendo a implementação usada pela API Java, eu não posso dizer com certeza, mas eu estaria disposto a apostar que o implenentation Java é mais eficiente do que o primeiro um pouco simples algoritmo que você postou.

Outras dicas

Para responder a esta bit:

Por que é que isso funciona muito

Não faz. Pelo menos, não da mesma forma que a versão de loop faz. nova BigInteger (...). toString (16) não mostrará zeros à esquerda, que a versão antiga vai. Normalmente, para algo como escrever um array de bytes (especialmente um que representa algo como um hash), você iria querer uma saída de comprimento fixo por isso, se você quiser usar essa versão você tem que preenchê-lo de forma adequada.

Para uma explicação completa sobre bitshifting check-out as respostas na seguinte pergunta SO Quais são shift (bit-shift) operadores bit a bit e como eles funcionam?

Ele parece tentar converter um único byte em um número menor do que 16, ao fazê-lo, ele pode facilmente determinar caracther wich que byte representa com o código

  if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));

Esta é uma resposta simplista, mas não sou tão brilhante de qualquer maneira = D

Estas coisas que você não tem que escrever por si mesmo, porque ele já está escrito em apache-commons-codec:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(byte[] array)

Há uma série de métodos mais úteis na classe Hex.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top