Stringa hash tramite SHA-256 in Java


111

Guardando qui intorno e su Internet in generale, ho trovato Bouncy Castle . Voglio usare Bouncy Castle (o qualche altra utility disponibile gratuitamente) per generare un hash SHA-256 di una stringa in Java. Guardando la loro documentazione non riesco a trovare alcun buon esempio di quello che voglio fare. Qualcuno qui può aiutarmi?

Risposte:


264

Per eseguire l'hashing di una stringa, utilizzare la classe MessageDigest incorporata :

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

Nello snippet precedente, digestcontiene la stringa con hash e hexuna stringa ASCII esadecimale con spaziatura interna zero a sinistra.


2
@Harry Pham, l'hash dovrebbe essere sempre lo stesso, ma senza ulteriori informazioni sarebbe difficile dire perché ne stai ottenendo di diversi. Probabilmente dovresti aprire una nuova domanda.
Brendan Long

2
@Harry Pham: Dopo aver chiamato digestlo stato interno viene ripristinato; quindi quando lo chiami di nuovo senza aggiornare prima, ottieni l'hash della stringa vuota.
Debilski

3
@BrendanLong Ora, come recuperare digestdi nuovo su String?
Sajad

1
@Sajjad Usa la tua funzione di codifica base64 preferita. Personalmente mi piace quello in Apache Commons .
Brendan Long,

1
@Adam No, questo è fuorviante. Chiamare ´toString´ su un array di byte produce un risultato diverso rispetto alla conversione del contenuto dell'array di byte in String, la risposta di Brendan Longs è più appropriata
max.mustermann

30

Questo è già implementato nelle librerie di runtime.

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 un ambiente JEE6 + si potrebbe anche utilizzare JAXB DataTypeConverter :

import javax.xml.bind.DatatypeConverter;

String hash = DatatypeConverter.printHexBinary( 
           MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));

3
questa versione ha un bug (almeno ad oggi e con java8 @ win7). prova ad eseguire l'hash "1234". il risultato deve iniziare con "03ac67 ..." ma in realtà inizia con "3ac67 ..."
Chris

@ Chris, grazie, ho risolto questo problema qui, ma ho trovato una soluzione migliore, la mia preferita è attualmente: stackoverflow.com/questions/415953/…
stacker

1
Per i nuovi lettori di questo vecchio thread: il preferito (hash MD5) a cui fa riferimento @stacker è ora considerato insicuro ( en.wikipedia.org/wiki/MD5 ).
mortensi

1
La condizione dovrebbe essere output.length () <64, non 32.
Sampo

Come possiamo confrontare due diversi valori hash creati usando lo stesso sale? Supponiamo che uno provenga dal modulo di accesso (è necessario eseguire l'hashing utilizzando Salt prima del confronto) e un altro provenga da db e quindi come possiamo confrontare questi due?
Pra_A

16

Non hai necessariamente bisogno della libreria BouncyCastle. Il codice seguente mostra come eseguire questa operazione utilizzando la funzione 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 ringraziamento speciale a user1452273 da questo post: Come eseguire l'hashing di una stringa con sha256 in Java?

Continua così !


9

Quando si utilizzano codici hash con qualsiasi provider jce, si tenta prima di ottenere un'istanza dell'algoritmo, quindi aggiornarlo con i dati che si desidera sottoporre ad hashing e quando si è terminato si chiama digest per ottenere il valore hash.

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

puoi utilizzare il digest per ottenere una versione con codifica base64 o hex in base alle tue esigenze


Per curiosità, puoi andare direttamente digest()con l'array di byte di input, saltando update()?
ladenedge

Una cosa che ho notato è che funziona con "SHA-256" mentre "SHA256" genera un'eccezione NoSuchAlgorithmException. Nessun problema.
knpwrs

9
Secondo il mio commento a Brandon, non utilizzare String.getBytes()senza specificare una codifica. Attualmente questo codice può fornire risultati diversi su piattaforme diverse, il che è un comportamento errato per un hash ben definito.
Jon Skeet

@ladenedge sì - se la tua stringa è abbastanza corta @KPthunder la tua destra @Jon Skeet dipende dal contenuto della stringa - ma sì aggiungi una stringa di codifica getBytes per essere dalla parte del salvataggio
Nikolaus Gradwohl

7

Java 8: Base64 disponibile:

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

    String outEncoded = Base64.getEncoder().encodeToString( aMessageDigest );
    return( outEncoded );

5

Suppongo che tu stia utilizzando una versione Java relativamente vecchia senza SHA-256. Quindi è necessario aggiungere il provider BouncyCastle ai "Provider di sicurezza" già forniti nella versione 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();

+1 per aver menzionato BouncyCastle, che aggiunge parecchi nuovi MessageDigest rispetto alla selezione relativamente irrisoria disponibile nel JDK.
mjuarez

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

4
Senza le informazioni sul pacchetto / provider la classe "Hex" non è molto utile. E se quello è Hex da Apache Commons Codec, lo userei return Hex.encodeHexString(digest)invece.
eckes il

0

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

-1

Questo funzionerà con il pacchetto successivo "org.bouncycastle.util.encoders.Hex"

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

È in un barattolo di castello.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.