Hash String über SHA-256 in Java

111

Indem ich mich hier und im Internet im Allgemeinen umgesehen habe , habe ich Bouncy Castle gefunden . Ich möchte Bouncy Castle (oder ein anderes frei verfügbares Dienstprogramm) verwenden, um einen SHA-256-Hash eines Strings in Java zu generieren. Wenn ich mir ihre Dokumentation ansehe, kann ich anscheinend keine guten Beispiele dafür finden, was ich tun möchte. Kann mir hier jemand helfen?

knpwrs
quelle

Antworten:

264

Verwenden Sie zum Hashing eines Strings die integrierte MessageDigest- Klasse:

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

digestEnthält im obigen Snippet die Hash-Zeichenfolge und hexeine hexadezimale ASCII-Zeichenfolge mit Links-Null-Auffüllung.

Brendan Long
quelle
2
@ Harry Pham, der Hash sollte immer der gleiche sein, aber ohne weitere Informationen wäre es schwer zu sagen, warum Sie andere bekommen. Sie sollten wahrscheinlich eine neue Frage öffnen.
Brendan Long
2
@ Harry Pham: Nach dem Aufruf wird digestder interne Status zurückgesetzt; Wenn Sie es also erneut aufrufen, ohne es zuvor zu aktualisieren, erhalten Sie den Hash der leeren Zeichenfolge.
Debilski
3
@BrendanLong Nun, wie kann ich digestwieder zu String abrufen ?
Sajad
1
@Sajjad Verwenden Sie Ihre bevorzugte Base64-Codierungsfunktion. Ich mag die in Apache Commons persönlich.
Brendan Long
1
@ Adam Nein, das ist irreführend. Das Aufrufen von "toString" für ein Byte-Array führt zu einem anderen Ergebnis als das Konvertieren des Inhalts des Byte-Arrays in "String". Die Antwort von Brendan Longs ist angemessener
max.mustermann
30

Dies ist bereits in den Laufzeitbibliotheken implementiert.

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

In einer JEE6 + -Umgebung kann man auch JAXB DataTypeConverter verwenden :

import javax.xml.bind.DatatypeConverter;

String hash = DatatypeConverter.printHexBinary( 
           MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));
Stapler
quelle
3
Diese Version hat einen Fehler (zumindest ab heute und mit java8 @ win7). versuche '1234' zu hashen. Das Ergebnis muss mit '03ac67 ...' beginnen, aber es beginnt tatsächlich mit '3ac67 ...'
Chris
@ Chris Dank, fest ich dies hier, aber ich fand eine bessere Lösung mein Favorit auf dieser ist zur Zeit: stackoverflow.com/questions/415953/...
Stapler
1
Für neue Leser dieses alten Threads: Der Favorit (MD5-Hash), auf den @stacker verweist, gilt jetzt als unsicher ( en.wikipedia.org/wiki/MD5 ).
Mortensi
1
Die Bedingung sollte output.length () <64 sein, nicht 32.
Sampo
Wie können wir zwei verschiedene Hash-Werte vergleichen, die mit demselben Salz erstellt wurden? Angenommen, einer stammt aus dem Formular-Login (muss vor dem Vergleich mit Salt gehasht werden) und ein anderer stammt aus der Datenbank und wie können wir diese beiden dann vergleichen?
Pra_A
16

Sie benötigen nicht unbedingt die BouncyCastle-Bibliothek. Der folgende Code zeigt, wie dies mit der Funktion Integer.toHexString gemacht wird

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

Besonderer Dank geht an user1452273 aus diesem Beitrag: Wie wird ein String mit sha256 in Java gehasht ?

Mach weiter so !

Schleudertrauma
quelle
9

Wenn Sie Hashcodes mit einem JCE-Anbieter verwenden, versuchen Sie zunächst, eine Instanz des Algorithmus abzurufen, aktualisieren ihn dann mit den Daten, die gehasht werden sollen, und rufen Sie Digest auf, um den Hash-Wert abzurufen.

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

Sie können den Digest verwenden, um eine Base64- oder Hex-codierte Version entsprechend Ihren Anforderungen zu erhalten

Nikolaus Gradwohl
quelle
Können Sie aus Neugier direkt digest()mit dem Eingabe-Byte-Array fortfahren und überspringen update()?
beladen
Eine Sache, die mir aufgefallen ist, ist, dass dies mit "SHA-256" funktioniert, während "SHA256" eine NoSuchAlgorithmException auslöst. Kein Problem.
Knpwrs
9
Verwenden Sie gemäß meinem Kommentar zu Brandon nichtString.getBytes() ohne Angabe einer Codierung. Derzeit kann dieser Code auf verschiedenen Plattformen unterschiedliche Ergebnisse liefern. Dies ist ein fehlerhaftes Verhalten für einen genau definierten Hash.
Jon Skeet
@ladenedge ja - wenn Ihre Zeichenfolge kurz genug ist @KPthunder Ihr rechtes @Jon Skeet hängt vom Inhalt der Zeichenfolge ab - aber ja, fügen Sie eine Codierungszeichenfolge getBytes hinzu, um auf der sicheren Seite zu sein
Nikolaus Gradwohl
7

Java 8: Base64 verfügbar:

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

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

Ich nehme an, Sie verwenden eine relativ alte Java-Version ohne SHA-256. Daher müssen Sie den BouncyCastle-Anbieter zu den bereits bereitgestellten "Sicherheitsanbietern" in Ihrer Java-Version hinzufügen.

    // 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
quelle
+1 für die Erwähnung von BouncyCastle, das im Vergleich zu der relativ dürftigen Auswahl im JDK einige neue MessageDigests hinzufügt.
Mjuarez
0
return new String(Hex.encode(digest));
Kay
quelle
4
Ohne Paket- / Anbieterinformationen ist die Klasse "Hex" nicht sehr hilfreich. Und wenn das Hex vom Apache Commons Codec ist, würde ich return Hex.encodeHexString(digest)stattdessen verwenden.
eckes
0

Verwenden von 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
quelle
-1

Dies funktioniert mit dem folgenden Paket "org.bouncycastle.util.encoders.Hex"

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

Es ist in Hüpfburg Glas.

Shrikant Karvade
quelle