2010-06-11 14 views
23

Quando ho calcolato in Java uno SHA-256 di una stringa con il seguente metodoQuale SHA-256 è corretto? Il Java SHA-256 digest o la riga di comando di Linux strumento

public static void main(String[] args) throws NoSuchAlgorithmException { 

    MessageDigest md = MessageDigest.getInstance("SHA-256"); 

    byte[] hash = md.digest("password".getBytes()); 

    StringBuffer sb = new StringBuffer(); 
    for(byte b : hash) { 
     sb.append(Integer.toHexString(b & 0xff)); 
    } 

    System.out.println(sb.toString()); 
} 

ottengo:

5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8 

sulla riga di comando I effettuare le seguenti operazioni (ho bisogno del -n di non aggiungere una nuova riga):

echo -n "password" | sha256sum 

e ottenere

01.235.164,106 mila
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 

se confrontiamo questi più strettamente Trovo 2 sottili differenze

5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8 
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 

o:

5e884898da28 47151d0e56f8dc6292773603d d6aabbdd62a11ef721d1542d8 
5e884898da28 0 47151d0e56f8dc6292773603d 0 d6aabbdd62a11ef721d1542d8 

Quale delle due è corretta qui?

Risultato: Entrambi sono, ma mi sbagliavo ...

fissata esso utilizzando:

StringBuffer sb = new StringBuffer(); 
    for(byte b : hash) { 
     sb.append(String.format("%02x", b)); 
    } 

Grazie!

risposta

26

Prenderò un'ipotesi ragionevole: entrambi stanno emettendo lo stesso digest, ma nel codice Java che emette il risultato byte[] come una stringa esadecimale, si emettono valori di byte piccoli (meno di 16) senza uno zero iniziale. Quindi un byte con valore "0x0d" viene scritto come "d" non "0d".

+0

Yep, appena visto il tuo aggiornamento con codice - questo è il problema. 'Integer.toHexString()' non scriverà il numero iniziale 0. Potrebbe essere più semplice solo valori del caso speciale inferiori a 16 e scrivere uno '0' in primo piano. –

+0

Sciocco! Grazie per la rapida risposta! Sono appena stato fortunato con la mia implementazione MD5. Grande risparmio ... –

9

Il colpevole è lo toHexString. Sembra che stia emettendo 6 per il valore 6 mentre lo sha256sum sta emettendo 06. Documento Java per lo stato Integer.toHexString():

Questo valore viene convertito in una stringa di cifre ASCII in esadecimale (base 16) senza 0 iniziali supplementari.

Gli altri zeri nella stringa non vengono influenzati dal momento che sono la seconda metà del byte (ad esempio, 30).

Un modo per risolvere il problema sarebbe di cambiare:

for(byte b : hash) { 
    sb.append(Integer.toHexString(b & 0xff)); 
} 

a:

for(byte b : hash) { 
    if (b < 16) sb.append("0"); 
    sb.append(Integer.toHexString(b & 0xff)); 
} 
1

quello generato da sha256sum sembra corretto. La tua implementazione sembra far cadere quei due zeri.

6

Hanno entrambi ragione: è il tuo codice Java che è in errore, perché non sta stampando lo 0 iniziale per un valore esadecimale inferiore a 0x10.

3

hai ancora bisogno di "echo -n" per evitare che il finale \ n

1

Utilizzando @paxdiablo idea ha avuto problemi con il grande numero come apparire come negativo, in modo

Invece di:

for(byte b : hash) { 
    sb.append(Integer.toHexString(b & 0xff)); 
} 

si poteva fare:

for(byte b : hash) { 
    if (b > 0 && b < 16) { 
     sb.append("0"); 
    } 
    sb.append(Integer.toHexString(b & 0xff)); 
} 

E leggere @Sean Owen risposta.

0

È anche possibile ottenere il risultato giusto di utilizzare questo:

MessageDigest md = MessageDigest.getInstance("SHA-256"); 

byte[] hash = md.digest("password".getBytes()); 

BigInteger bI = new BigInteger(1, hash); 

System.out.println(bI.toString(16)); 
+1

No, questo codice è ancora sbagliato. BigInteger.toString (16) non conterrà gli zeri iniziali. – Nayuki