Domanda

Di recente ho iniziato a guardare l'hash MD5 (in Java) e mentre ho trovato algoritmi e metodi per aiutarmi a realizzarlo, mi chiedo come funzioni effettivamente.

Per uno, ho trovato quanto segue da questo 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();
}

Non ho trovato alcun bisogno di usare lo spostamento dei bit in Java, quindi sono un po 'arrugginito. Qualcuno abbastanza gentile da illustrare (in termini semplici) come fa esattamente il codice sopra riportato la conversione? & Quot; > > > "?

Ho trovato anche altre soluzioni su StackOverflow, come qui e qui , che utilizza invece BigInteger:

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();
}

Perché funziona anche quello e in che modo è più efficiente?

Grazie per il tuo tempo.

È stato utile?

Soluzione

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

Fino a questo punto ... solo configurazione di base e avvio di un ciclo per passare attraverso tutti i byte dell'array

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

byte quando convertiti in esadecimale sono due cifre esadecimali o 8 cifre binarie a seconda della base in cui la guardi. L'istruzione precedente sposta gli alti 4 bit verso il basso (> > > è spostamento destro senza segno) e AND logici con 0000 1111 in modo che il risultato sia un numero intero uguale ai 4 bit alti del byte (prima cifra esadecimale).

Di '23 è stato un input, questo è 0001 0111 in binario. Il turno fa e logico AND copre questo a 0000 0001.

        int two_halfs = 0;
        do {

Questo imposta semplicemente il ciclo do / while per l'esecuzione due volte

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

Qui mostriamo la cifra esadecimale attuale, fondamentalmente semplicemente usando lo zero o un carattere come punto di partenza e spostando il carattere corretto. La prima istruzione if copre tutte le cifre 0-9 e la seconda copre tutte le cifre 10-15 (a-f in esadecimale)

Ancora una volta, usando il nostro esempio 0000 0001 in decimale è uguale a 1. Veniamo catturati nel blocco if superiore e aggiungiamo 1 al carattere '0' per ottenere il carattere '1', aggiungilo alla stringa e vai avanti .

                halfbyte = data[i] & 0x0F;

Ora impostiamo il numero intero in modo che sia uguale ai bit bassi dal byte e ripeti.

Ancora una volta, se il nostro input era 23 ... 0001 0111 dopo che l'AND logico diventa solo 0000 0111 che è 7 in decimale. Ripeti la stessa logica di cui sopra e viene visualizzato il carattere "7".

            } while(two_halfs++ < 1);

Ora passiamo al byte successivo nell'array e ripetiamo.

        }
    return buf.toString();
}

Per rispondere alla tua prossima domanda, l'API Java ha già un'utilità di conversione di base già integrata in BigInteger. Vedi toString (int radix ) documentazione.

Non conoscendo l'implementazione utilizzata dall'API Java, non posso dirlo con certezza, ma sarei disposto a scommettere che l'implementazione Java è più efficiente del primo algoritmo piuttosto semplice che hai pubblicato.

Altri suggerimenti

Per rispondere a questo bit:

  

Perché funziona anche così

Non lo fa. Almeno, non allo stesso modo della versione loop. nuovo BigInteger (...). toString (16) non mostrerà zero iniziali, come invece farà la versione precedente. Di solito per qualcosa come scrivere un array di byte (in particolare uno che rappresenta qualcosa come un hash) si vorrebbe un output a lunghezza fissa, quindi se si desidera utilizzare quella versione, è necessario completarlo in modo appropriato.

Per una spiegazione approfondita del bitshift, controlla le risposte nella seguente domanda SO Cosa sono gli operatori di spostamento bit a bit (bit-shift) e come funzionano?

Sembra provare a convertire un singolo byte in un numero inferiore a 16, facendo così può facilmente determinare quale personaggio rappresenta quel byte con il codice

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

Questa è una risposta semplicistica, ma non sono comunque così brillante = D

Queste cose non devi scrivere da solo, perché sono già scritte in apache-commons-codec:

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

Esistono molti metodi più utili nella classe Hex .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top