web-dev-qa-db-fra.com

Algorithmes de hachage Java - Implémentations les plus rapides

Je souhaite savoir quelle est la meilleure et la plus rapide implémentation des algorithmes de hachage pour Java, en particulier MD5 et SHA-2 512 (SHA512) ou 256. Je souhaite qu'une fonction obtienne une chaîne comme argument et renvoie le hachage comme résultat. Merci.

Edit: Ceci est pour obtenir le mappage de chaque URL sur un hachage unique. Étant donné que MD5 n’est pas aussi fiable dans ce domaine, je suis davantage intéressé par la mise en oeuvre la plus rapide et la meilleure pour les algorithmes SHA-2. Notez que je sais que même SHA-2 pourrait produire le même hachage pour certaines URL, mais je peux vivre avec cela.

27
Alireza Noori

Tout d'abord, la vitesse est surestimée. Vous devez prendre des mesures avant de déclarer qu'un algorithme donné est "trop ​​lent". La plupart du temps, la vitesse de la fonction de hachage ne fait aucune différence notable de toute façon. Si vous avez des doutes sur la sécurité, sélectionnez d'abord une fonction de hachage suffisamment sécurisée, puis ne vous souciez que des performances.

De plus, vous voulez hacher des "chaînes". Une Java String est, en interne, une partie d'un tableau de valeurs char qui représentent des points de code Unicode (en réalité, des unités de code Unicode 16 bits qui codent les points de code à l'aide de UTF-16). Une fonction de hachage prend en entrée une séquence de bits ou d'octets. Vous devrez donc effectuer une étape de conversion, par exemple str.getBytes("UTF-8"), pour obtenir votre chaîne sous forme d’octets. Il est probable que l'étape de conversion aura un coût non négligeable par rapport au hachage lui-même.

Remarque: méfiez-vous du codage d'URL! Dans une URL, certains octets peuvent être remplacés par des séquences commençant par le signe '%'; ceci est conçu pour prendre en charge les caractères non imprimables, mais il peut également être utilisé sur des caractères "standard" (par exemple, remplacer "a" par "%61"). Cela signifie que deux chaînes distinctes (au sens de String.equals()) peuvent en réalité représenter la même URL (en ce qui concerne le traitement de l'URL). Selon votre situation, cela peut être un problème ou non.

Vous devez d’abord essayer d’utiliser l’API MessageDigest de Java avec le fournisseur JCE standard (déjà installé) (c’est-à-dire que vous appelez MessageDigest.getInstance("SHA-256")) et d’assortir le résultat. Théoriquement, JCE peut mapper l'appel à une implémentation avec un code "natif" (écrit en C ou Assembly), ce qui sera plus rapide que ce que vous pouvez obtenir avec Java.

Cela étant dit...

sphlib est une implémentation opensource de nombreuses fonctions de hachage cryptographique, en C et en Java. Le code a été optimisé pour la vitesse et, dans la pratique, la version Java s'avère plus rapide que celle offerte par le JRE standard de Sun/Oracle. Utilisez ce lien au cas où le lien précédent échouerait (le serveur hôte principal est parfois en panne de maintenance, comme cela semble être le cas actuellement) (avertissement: téléchargement de 10 Mo). Les archives contiennent également un rapport (qui a été présenté lors de la seconde conférence des candidats à SHA-3 en 2010) qui donne des chiffres de performance mesurés sur plusieurs plates-formes, pour SHA-2 et les 14 candidats du "second tour" pour le prochain SHA-3.

Mais vous devriez vraiment faire des repères dans la situation. Par exemple, les effets sur le cache N1 peuvent avoir un effet considérable sur les performances et ne peuvent pas être prédits avec précision en prenant le code de fonction et en l'exécutant de manière isolée.

50
Thomas Pornin

Edit: J'ai initialement lu la question comme étant "quel est l'algorithme de hachage le plus rapide" et que "la mise en oeuvre la plus rapide de chaque algorithme a été clarifiée". C'est une question valable et d'autres ont signalé des implémentations plus rapides. Cependant, à moins que vous ne partagiez de grandes quantités de données en un court laps de temps, cela n'aura tout simplement pas beaucoup d'importance. Je doute que cela vaille généralement le temps et la complexité d’utiliser autre chose que ce qui est fourni avec le JCE standard.

Pour les adresses URL, SHA-256 nécessite un hachage supérieur à million par seconde sur du matériel moderne pour que quelque chose soit plus rapide. Je ne peux pas imaginer que la plupart des applications nécessitent plus d'un millier par seconde (plus de 86 millions par jour), ce qui signifie que le temps de calcul total passé au processeur serait bien inférieur à 1%. Ainsi, même si vous aviez un algorithme de hachage infiniment rapide, vous ne pourriez améliorer les performances globales que de 1% au mieux.

Réponse originale: Obtenir le meilleur et le plus rapide sont en désaccord les uns avec les autres. Les meilleurs hashes sont généralement plus lents. Si vous vraiment avez besoin de rapidité et de sécurité, utilisez plutôt MD5. Si vous avez besoin de la meilleure sécurité, choisissez alors SHA-256 ou même SHA-512. Vous n’avez pas mentionné l’utilisation que vous en faites, il est donc difficile de recommander l’un ou l’autre. Vous êtes probablement le plus sûr avec SHA-256, car il devrait être assez rapide pour la plupart des cas d’utilisation sur du matériel moderne de toute façon. Voici comment vous pouvez le faire:

String input = "your string";
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(input.getBytes("UTF-8"));
byte[] hash = digest.digest();

Si vous utilisez ceci à des fins de sécurité, comme le hachage d'un mot de passe, vous devez également ajouter du sel au résumé. Si vous voulez une chaîne imprimable hors du hachage, vous pouvez la coder en chaîne hexadécimale:

static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte b : hash) {
    sb.append(HEX_CHARS[(b & 0xF0) >> 4]);
    sb.append(HEX_CHARS[b & 0x0F]);
}
String hex = sb.toString();
21
WhiteFang34

Une autre chose à considérer est d'utiliser MD4. Ce n'est pas aussi sûr que MD5, mais est calculé encore plus rapidement. Windows jusqu’à XP utilisé pour stocker et échanger les mots de passe dans MD4, nous utilisons donc ce hachage car il nous permet toujours de fournir des services d’authentification à cette plateforme.

2
Daniel

Consultez ces exemples: Nombreux exemples SHA/MD5

Aussi: Du même fil: Fast MD5

String hash = MD5.asHex (MD5.getHash (nouveau fichier (nom de fichier)));

2
AndyMac

Considérez BLAKE2, qui est plus rapide et plus sécurisé que les hachages mentionnés ci-dessus.

MD5, SHA-1, SHA256 et SHA-512 sont susceptibles d’allonger.

MD5 et SHA-1 sont vulnérables aux collisions.

MD5 est vulnérable aux collisions choisies préfixe.

SHA-3 et BLAKE2 ne présentent aucun problème de sécurité connu et peuvent générer des résumés de longueur variable.

SHA-3 est le plus rapide lorsqu'il est implémenté dans le matériel; BLAKE2 est le plus rapide lorsque vous utilisez des implémentations logicielles.

BLAKE2b est optimisé pour les plates-formes 64 bits et produit des résumés de toute taille comprise entre 1 et 64 octets.

BLAKE2s est optimisé pour les plates-formes 8 à 32 bits et produit des résumés de toute taille entre 1 et 32 ​​octets.

Voici les points de repère pour AES, MD5, SHA-256 et BLAKE2b.

https://blake2.net/

https://www.cryptopp.com/benchmarks.html

Sur la première liaison, BLAKE2b (947 Mbits) est beaucoup plus rapide que SHA-256 (413 Mbits) et MD5 (632 Mbits).

Dans la deuxième liaison, AES-256 CBC (805 Mbits) et BLAKE2b (776 Mbits) ont une vitesse à peu près égale et sont plus rapides que SHA-256 (275 Mbits) et MD5 (602) Mbits.

0

Pour une chaîne, appelez simplement hashCode() car la surcharge de mémoire coûte moins cher.

Sinon, je recommande ce code pour le hachage privé:

public static int hash8(String val) throws UnsupportedEncodingException {
    return hash8(val.getBytes("UTF-8"));
}

public static int hash8(byte[] val) {
    int h = 1, i = 0;
    for (; i + 7 < val.length; i += 8) {
        h = 31 * 31 * 31 * 31 * 31 * 31 * 31 * 31 * h + 31 * 31 * 31 * 31
                * 31 * 31 * 31 * val[i] + 31 * 31 * 31 * 31 * 31 * 31
                * val[i + 1] + 31 * 31 * 31 * 31 * 31 * val[i + 2] + 31
                * 31 * 31 * 31 * val[i + 3] + 31 * 31 * 31 * val[i + 4]
                + 31 * 31 * val[i + 5] + 31 * val[i + 6] + val[i + 7];
    }
    for (; i + 3 < val.length; i += 4) {
        h = 31 * 31 * 31 * 31 * h + 31 * 31 * 31 * val[i] + 31 * 31
                * val[i + 1] + 31 * val[i + 2] + val[i + 3];
    }
    for (; i < val.length; i++) {
        h = 31 * h + val[i];
    }
    return h;
}

FYI: http://lemire.me/blog/2015/10/22/faster-hashing-without-effort/

0
Daniel De León