Chaîne de hachage via SHA-256 en Java

111

En regardant ici et sur Internet en général, j'ai trouvé Bouncy Castle . Je souhaite utiliser Bouncy Castle (ou un autre utilitaire disponible gratuitement) pour générer un Hash SHA-256 d'une chaîne en Java. En regardant leur documentation, je n'arrive pas à trouver de bons exemples de ce que je veux faire. Quelqu'un ici peut-il m'aider?

knpwrs
la source

Réponses:

264

Pour hacher une chaîne, utilisez la classe MessageDigest intégrée :

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.math.BigInteger;

public class CryptoHash {
  public static void main(String[] args) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    String text = "Text to hash, cryptographically.";

    // Change this to UTF-16 if needed
    md.update(text.getBytes(StandardCharsets.UTF_8));
    byte[] digest = md.digest();

    String hex = String.format("%064x", new BigInteger(1, digest));
    System.out.println(hex);
  }
}

Dans l'extrait de code ci-dessus, digestcontient la chaîne hachée et hexcontient une chaîne ASCII hexadécimale avec un remplissage de zéro à gauche.

Brendan Long
la source
2
@Harry Pham, le hachage devrait toujours être le même, mais sans plus d'informations, il serait difficile de dire pourquoi vous en obtenez différents. Vous devriez probablement ouvrir une nouvelle question.
Brendan Long
2
@Harry Pham: Après avoir appelé, digestl'état interne est réinitialisé; Ainsi, lorsque vous l'appelez à nouveau sans mettre à jour avant, vous obtenez le hachage de la chaîne vide.
Debilski
3
@BrendanLong Now, comment récupérer digestà nouveau String?
Sajad
1
@Sajjad Utilisez votre fonction d'encodage base64 préférée. J'aime celui d' Apache Commons personnellement.
Brendan Long
1
@Adam Non, c'est trompeur. L'appel de «toString» sur un tableau d'octets produit un résultat différent de la conversion du contenu du tableau d'octets en chaîne, la réponse de Brendan Longs est plus appropriée
max.mustermann
30

Ceci est déjà implémenté dans les bibliothèques d'exécution.

public static String calc(InputStream is) {
    String output;
    int read;
    byte[] buffer = new byte[8192];

    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        while ((read = is.read(buffer)) > 0) {
            digest.update(buffer, 0, read);
        }
        byte[] hash = digest.digest();
        BigInteger bigInt = new BigInteger(1, hash);
        output = bigInt.toString(16);
        while ( output.length() < 32 ) {
            output = "0"+output;
        }
    } 
    catch (Exception e) {
        e.printStackTrace(System.err);
        return null;
    }

    return output;
}

Dans un environnement JEE6 +, on peut également utiliser JAXB DataTypeConverter :

import javax.xml.bind.DatatypeConverter;

String hash = DatatypeConverter.printHexBinary( 
           MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));
empileur
la source
3
cette version a un bug (au moins à partir d'aujourd'hui et avec java8 @ win7). essayez de hacher «1234». le résultat doit commencer par '03ac67 ...' mais il commence en fait par '3ac67 ...'
Chris
@Chris merci, j'ai corrigé cela ici, mais j'ai trouvé une meilleure solution que ma préférée à ce sujet est actuellement: stackoverflow.com/questions/415953/...
stacker
1
Pour les nouveaux lecteurs de cet ancien fil: Le favori (MD5-hash) auquel @stacker fait référence est désormais considéré comme non sécurisé ( en.wikipedia.org/wiki/MD5 ).
mortensi
1
La condition doit être output.length () <64, pas 32.
Sampo
Comment pouvons-nous comparer deux valeurs hachées différentes créées en utilisant le même sel? Supposons que l'un provienne de la connexion par formulaire (besoin de hacher en utilisant Salt avant de comparer) et un autre vient de db et comment pouvons-nous comparer ces deux?
Pra_A
16

Vous n'avez pas nécessairement besoin de la bibliothèque BouncyCastle. Le code suivant montre comment procéder à l'aide de la fonction Integer.toHexString

public static String sha256(String base) {
    try{
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(base.getBytes("UTF-8"));
        StringBuffer hexString = new StringBuffer();

        for (int i = 0; i < hash.length; i++) {
            String hex = Integer.toHexString(0xff & hash[i]);
            if(hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }

        return hexString.toString();
    } catch(Exception ex){
       throw new RuntimeException(ex);
    }
}

Un merci spécial à user1452273 de ce post: Comment hacher une chaîne avec sha256 en Java?

Continuez votre bon travail!

Coup de fouet
la source
9

Lorsque vous utilisez des hashcodes avec n'importe quel fournisseur jce, vous essayez d'abord d'obtenir une instance de l'algorithme, puis mettez-la à jour avec les données que vous souhaitez hacher et lorsque vous avez terminé, vous appelez digest pour obtenir la valeur de hachage.

MessageDigest sha = MessageDigest.getInstance("SHA-256");
sha.update(in.getBytes());
byte[] digest = sha.digest();

vous pouvez utiliser le condensé pour obtenir une version encodée en base64 ou hexadécimale selon vos besoins

Nikolaus Gradwohl
la source
Par curiosité, pouvez-vous aller directement digest()avec le tableau d'octets d'entrée, en sautant update()?
ladenedge
Une chose que j'ai remarquée est que cela fonctionne avec "SHA-256" alors que "SHA256" lance une NoSuchAlgorithmException. Pas de problème.
knpwrs
9
Selon mon commentaire à Brandon, ne pas utiliser String.getBytes()sans spécifier un encodage. Actuellement, ce code peut donner des résultats différents sur différentes plates-formes - ce qui est un comportement cassé pour un hachage bien défini.
Jon Skeet
@ladenedge oui - si votre chaîne est suffisamment courte @KPthunder votre droite @Jon Skeet dépend du contenu de la chaîne - mais oui, ajoutez une chaîne de codage getBytes pour être du côté de la sauvegarde
Nikolaus Gradwohl
7

Java 8: Base64 disponible:

    MessageDigest md = MessageDigest.getInstance( "SHA-512" );
    md.update( inbytes );
    byte[] aMessageDigest = md.digest();

    String outEncoded = Base64.getEncoder().encodeToString( aMessageDigest );
    return( outEncoded );
Mike Dever
la source
5

Je suppose que vous utilisez une version Java relativement ancienne sans SHA-256. Vous devez donc ajouter le fournisseur BouncyCastle aux «fournisseurs de sécurité» déjà fournis dans votre version java.

    // NEEDED if you are using a Java version without SHA-256    
    Security.addProvider(new BouncyCastleProvider());

    // then go as usual 
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    String text = "my string...";
    md.update(text.getBytes("UTF-8")); // or UTF-16 if needed
    byte[] digest = md.digest();
obe6
la source
+1 pour mentionner BouncyCastle, qui ajoute quelques nouveaux MessageDigests par rapport à la sélection relativement dérisoire disponible dans le JDK.
mjuarez
0
return new String(Hex.encode(digest));
Kay
la source
4
Sans informations sur le package / fournisseur, la classe "Hex" n'est pas très utile. Et si c'est Hex d'Apache Commons Codec, j'utiliserais à la return Hex.encodeHexString(digest)place.
eckes
0

Utilisation de Java 8

MessageDigest digest = null;
try {
    digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
}
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
String encoded = DatatypeConverter.printHexBinary(hash);        
System.out.println(encoded.toLowerCase());
MST
la source
-1

Cela fonctionnera avec le package suivant "org.bouncycastle.util.encoders.Hex"

return new String(Hex.encode(digest));

C'est dans un pot de château gonflable.

Shrikant Karvade
la source