Quelqu'un peut-il expliquer la conversion de tableau d'octets en chaîne hexadécimale?

StackOverflow https://stackoverflow.com/questions/1043276

  •  20-08-2019
  •  | 
  •  

Question

J'ai récemment commencé à étudier le hachage MD5 (en Java) et, même si j'ai trouvé des algorithmes et des méthodes pour m'aider à atteindre cet objectif, je me demande comment cela fonctionne réellement.

Pour ma part, j’ai trouvé ce qui suit dans cette 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();
}

Je n'ai pas trouvé nécessaire d'utiliser le transfert de bits en Java, je suis donc un peu rouillé à ce sujet. Quelqu'un assez aimable pour illustrer (en termes simples) comment exactement le code ci-dessus fait la conversion? "> > >"

J'ai également trouvé d'autres solutions sur StackOverflow, telles que ici et ici , qui utilise BigInteger à la place:

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

Pourquoi cela fonctionne-t-il aussi et quelle est la méthode la plus efficace?

Merci de votre temps.

Était-ce utile?

La solution

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

Jusqu'ici, il suffit de configurer et de démarrer une boucle pour parcourir tous les octets du tableau

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

octets convertis en hexadécimal sont composés de deux chiffres hexadécimaux ou de huit chiffres binaires, en fonction de la base dans laquelle vous le regardez. La déclaration ci-dessus décale les 4 bits les plus hauts (> > > n'est pas signé, décalage à droite) et d'ET logique. avec 0000 1111 pour que le résultat soit un entier égal aux 4 bits de poids fort de l’octet (premier chiffre hexadécimal).

Disons que 23 était une entrée, c’est 0001 0111 en binaire. Le décalage fait et AND logique passe à 0000 0001.

        int two_halfs = 0;
        do {

Ceci configure simplement la boucle do / while à exécuter deux fois

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

Ici, nous affichons le chiffre hexadécimal réel, en utilisant simplement le zéro ou un caractère comme point de départ et en passant au caractère correct. La première instruction if couvre tous les chiffres de 0 à 9 et la seconde, tous les chiffres de 10 à 15 (a-f en hex)

Encore une fois, utiliser notre exemple 0000 0001 en décimal est égal à 1. Nous sommes pris dans le bloc supérieur si et ajoutons 1 au caractère '0' pour obtenir le caractère '1', ajoutez-le à la chaîne et passez à autre chose. .

                halfbyte = data[i] & 0x0F;

Nous configurons maintenant le nombre entier pour qu'il soit juste égal aux bits les plus bas de l'octet et le répète.

Encore une fois, si notre entrée était 23 ... 0001 0111 après que l’ET logique devienne seulement 0000 0111, ce qui donne 7 en décimal. Répétez la même logique que ci-dessus pour afficher le caractère "7".

            } while(two_halfs++ < 1);

Nous allons maintenant passer à l'octet suivant du tableau et répéter l'opération.

        }
    return buf.toString();
}

Pour répondre à votre prochaine question, l'API Java dispose déjà d'un utilitaire de conversion de base intégré à BigInteger. Voir le toString (int radix ) documentation.

Ne connaissant pas l'implémentation utilisée par l'API Java, je ne peux pas en dire autant, mais je serais prêt à parier que l'implémentation Java est plus efficace que le premier algorithme quelque peu simple que vous avez publié.

Autres conseils

Pour répondre à ce bit:

  

Pourquoi ça marche aussi

Ce n'est pas. Du moins, pas de la même manière que la version en boucle. new BigInteger (...). toString (16) n'affichera pas les zéros de gauche, contrairement à la version précédente. Habituellement, pour quelque chose comme l’écriture d’un tableau d’octets (en particulier un qui représente quelque chose comme un hachage), vous voudriez une sortie de longueur fixe, donc si vous voulez utiliser cette version, vous devez l’ajouter correctement.

Pour une explication détaillée de bitshifting, consultez les réponses à la question SO suivante Que sont les opérateurs de décalage par bits et comment fonctionnent-ils?

Il semble essayer de convertir un seul octet en un nombre inférieur à 16, ce qui lui permet de déterminer facilement le caractère que cet octet représente avec le code

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

Ceci est une réponse simpliste, mais je ne suis pas si brillant de toute façon = D

Ces éléments que vous n'avez pas à écrire vous-même, car ils sont déjà écrits dans apache-commons-codec:

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

Il existe de nombreuses méthodes plus utiles dans la classe Hex .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top