web-dev-qa-db-fra.com

Java calcule la représentation hexadécimale d'un condensé SHA-1 d'une chaîne

Je stocke le mot de passe de l'utilisateur sur la base de données sous forme de hachage sha1.

Malheureusement, je reçois des réponses étranges.

Je stocke la chaîne comme ceci:

MessageDigest cript = MessageDigest.getInstance("SHA-1");
              cript.reset();
              cript.update(userPass.getBytes("utf8"));
              this.password = new String(cript.digest());

Je voulais quelque chose comme ça ->

aff -> "0c05aa56405c447e6678b7f3127febde5c3a9238"

plutôt que

aff -> �V @\D ~ fx����: 8

57

Cela se produit car cript.digest () renvoie un tableau d'octets que vous essayez d'imprimer sous forme de chaîne de caractères. Vous voulez le convertir en une chaîne hexagonale imprimable.

Solution facile: Utilisez Apache librairie commons-codec :

String password = new String(Hex.encodeHex(cript.digest()),
                             CharSet.forName("UTF-8"));
40
Jason Nichols

Utilisation de la bibliothèque de codecs commune Apache:

DigestUtils.sha1Hex("aff")

Le résultat est 0c05aa56405c447e6678b7f3127febde5c3a9238

C'est ça :)

102
altumano

Une itération d'un algorithme de hachage n'est pas sécurisée. C'est trop rapide. Vous devez renforcer les clés en répétant plusieurs fois le hachage.

De plus, vous ne salez pas le mot de passe. Cela crée une vulnérabilité aux dictionnaires pré-calculés, tels que "Tables Rainbow".

Au lieu d’essayer de faire rouler votre propre code (ou d’utiliser un bloatware tiers peu précis) pour le faire correctement, vous pouvez utiliser le code intégré à la Java runtime. Voir this répondre pour plus de détails.

Une fois que vous avez haché le mot de passe correctement, vous obtenez un byte[]. Un moyen facile de convertir cela en hexadécimal String est avec la classe BigInteger:

String passwordHash = new BigInteger(1, cript.digest()).toString(16);

Si vous voulez vous assurer que votre chaîne a toujours 40 caractères, vous devrez peut-être ajouter des zéros à gauche (vous pouvez le faire avec String.format().).

24
erickson

Si vous ne souhaitez pas ajouter de dépendances supplémentaires à votre projet, vous pouvez également utiliser

MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(message.getBytes("utf8"));
byte[] digestBytes = digest.digest();
String digestStr = javax.xml.bind.DatatypeConverter.printHexBinary(digestBytes);
10
Manish Sahni

La méthode crypt.digest () renvoie un octet []. Ce tableau d'octets est la somme SHA-1 correcte, mais les hachages de chiffrement sont généralement affichés aux humains sous forme hexadécimale. Chaque octet dans votre hachage donnera deux chiffres hexadécimaux.

Pour convertir en toute sécurité un octet en hex, utilisez ceci:

// %1$ == arg 1
// 02  == pad with 0's
// x   == convert to hex
String hex = String.format("%1$02x", byteValue);

Cet extrait de code peut être utilisé pour convertir un caractère en hexadécimal :

/*
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import Java.io.*;

public class UnicodeFormatter  {

   static public String byteToHex(byte b) {
      // Returns hex String representation of byte b
      char hexDigit[] = {
         '0', '1', '2', '3', '4', '5', '6', '7',
         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
      };
      char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
      return new String(array);
   }

   static public String charToHex(char c) {
      // Returns hex String representation of char c
      byte hi = (byte) (c >>> 8);
      byte lo = (byte) (c & 0xff);
      return byteToHex(hi) + byteToHex(lo);
   }
}

Notez que travailler avec des octets dans Java est très sujet aux erreurs. Je revérifierais tout et testerais également des cas étranges.

Aussi, vous devriez envisager d'utiliser quelque chose de plus fort que SHA-1. http://csrc.nist.gov/groups/ST/hash/statement.html

5
cyber-monk

Avec Google Guava :

Maven:

<dependency>
   <artifactId>guava</artifactId>
   <groupId>com.google.guava</groupId>
   <version>14.0.1</version>
</dependency>

Échantillon:

HashCode hashCode = Hashing.sha1().newHasher()
   .putString(password, Charsets.UTF_8)
   .hash();            

String hash = BaseEncoding.base16().lowerCase().encode(hashCode.asBytes());
3
Tho

Si vous utilisez Spring c'est assez simple:

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder("SHA-1");
String hash = encoder.encodePassword(password, "salt goes here");
2
Vedran

Le stockage de mots de passe non réversibles ne se limite pas à de simples algorithmes de hachage standard.

  1. Faites plusieurs tours pour ralentir les attaques par force brute
  2. Utilisez un "sel" par enregistrement comme entrée de l'algorithme de hachage en plus du mot de passe pour rendre les attaques par dictionnaire moins faisables et éviter les collisions de sortie.
  3. Utilisez "pepper", un paramètre de configuration d'application en tant qu'entrée de l'algorithme de hachage pour rendre inutile le vidage d'une base de données volée avec un "pepper" inconnu.
  4. Complétez l'entrée pour éviter les faiblesses de certains algorithmes de hachage, par exemple. où vous pouvez ajouter un caractère au mot de passe sans connaître le mot de passe, en modifiant le hachage.

Pour plus d'informations, voir par exemple.

Vous pouvez également utiliser une méthode http://en.wikipedia.org/wiki/Password-authenticated_key_agreement pour éviter de transmettre le mot de passe en texte clair au serveur.

2
Stefan L

Que diriez-vous de convertir byte [] en chaîne base64?

    byte[] chkSumBytArr = digest.digest();
    BASE64Encoder encoder = new BASE64Encoder();
    String base64CheckSum = encoder.encode(chkSumBytArr);
1
Mahes

Pour utiliser UTF-8, procédez comme suit:

userPass.getBytes("UTF-8");

Et pour obtenir une chaîne Base64 du résumé, vous pouvez faire quelque chose comme ceci:

this.password = new BASE64Encoder().encode(cript.digest());

Puisque MessageDigest.digest() renvoie un tableau d'octets, vous pouvez le convertir en chaîne à l'aide d'Apache Hex Encoding (plus simple).

Par exemple.

this.password = Hex.encodeHexString(cript.digest());
1
Buhake Sindi

digest () renvoie un tableau d'octets que vous convertissez en chaîne à l'aide de l'encodage par défaut. Ce que vous voulez faire, c'est l'encoder en base64.

1
PaulJWilliams

echo -n "aff" | sha1sum produit le bon résultat (echo insère une nouvelle ligne par défaut)

1
Krystal
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
        messageDigest.reset();
        messageDigest.update(password.getBytes("UTF-8"));
        String sha1String = new BigInteger(1, messageDigest.digest()).toString(16);
1
Pankaj Kumar

vous pouvez aussi utiliser ce code (à partir de crackstation.net):

private static String toHex(byte[] array) { BigInteger bi = new BigInteger(1, array); String hex = bi.toString(16); int paddingLength = (array.length * 2) - hex.length(); if(paddingLength > 0) return String.format("%0" + paddingLength + "d", 0) + hex; else return hex; }

1
Mahdi

Vous devez d'abord encoder le résultat. MessageDigest renvoie un hachage "brut", plutôt qu'un lisible par l'homme.

Modifier:

@thejh a fourni un lien vers le code qui devrait fonctionner. Personnellement, je suggérerais d'utiliser soit Bouncycastle ou Apache Commons Codec pour faire le travail. Bouncycastle serait utile si vous souhaitez effectuer d’autres opérations liées à la cryptographie.

0