2012-03-15 13 views
192

Ho scritto una semplice classe Java per generare i valori hash del file di Calcolatrice di Windows. Sto usando Windows 7 Professional with SP1. Ho provato Java 6.0.29 e Java 7.0.03. Qualcuno può dirmi perché sto ottenendo diversi valori hash da Java rispetto a (molti!) Utilità esterne e/o siti web? Tutto ciò che è esterno si combina, solo Java restituisce risultati diversi.Risultati diversi con il digest di Java rispetto alle utilità esterne

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import java.util.Map.Entry; 
import java.util.zip.CRC32; 
import java.security.DigestInputStream; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 

public class Checksum 
{ 
    private static int size = 65536; 
    private static File calc = new File("C:/Windows/system32/calc.exe"); 

    /* 
     C:\Windows\System32\calc.exe (verified via several different utilities) 
     ---------------------------- 
     CRC-32b = 8D8F5F8E 
     MD5  = 60B7C0FEAD45F2066E5B805A91F4F0FC 
     SHA-1 = 9018A7D6CDBE859A430E8794E73381F77C840BE0 
     SHA-256 = 80C10EE5F21F92F89CBC293A59D2FD4C01C7958AACAD15642558DB700943FA22 
     SHA-384 = 551186C804C17B4CCDA07FD5FE83A32B48B4D173DAC3262F16489029894FC008A501B50AB9B53158B429031B043043D2 
     SHA-512 = 68B9F9C00FC64DF946684CE81A72A2624F0FC07E07C0C8B3DB2FAE8C9C0415BD1B4A03AD7FFA96985AF0CC5E0410F6C5E29A30200EFFF21AB4B01369A3C59B58 


     Results from this class 
     ----------------------- 
     CRC-32 = 967E5DDE 
     MD5  = 10E4A1D2132CCB5C6759F038CDB6F3C9 
     SHA-1 = 42D36EEB2140441B48287B7CD30B38105986D68F 
     SHA-256 = C6A91CBA00BF87CDB064C49ADAAC82255CBEC6FDD48FD21F9B3B96ABF019916B  
    */  

    public static void main(String[] args)throws Exception { 
     Map<String, String> hashes = getFileHash(calc); 
     for (Map.Entry<String, String> entry : hashes.entrySet()) { 
      System.out.println(String.format("%-7s = %s", entry.getKey(), entry.getValue())); 
     } 
    } 

    private static Map<String, String> getFileHash(File file) throws NoSuchAlgorithmException, IOException { 
     Map<String, String> results = new LinkedHashMap<String, String>(); 

     if (file != null && file.exists()) { 
      CRC32 crc32 = new CRC32(); 
      MessageDigest md5 = MessageDigest.getInstance("MD5"); 
      MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); 
      MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); 

      FileInputStream fis = new FileInputStream(file); 
      byte data[] = new byte[size]; 
      int len = 0; 
      while ((len = fis.read(data)) != -1) { 
       crc32.update(data, 0, len); 
       md5.update(data, 0, len); 
       sha1.update(data, 0, len); 
       sha256.update(data, 0, len); 
      } 
      fis.close(); 

      results.put("CRC-32", toHex(crc32.getValue())); 
      results.put(md5.getAlgorithm(), toHex(md5.digest())); 
      results.put(sha1.getAlgorithm(), toHex(sha1.digest())); 
      results.put(sha256.getAlgorithm(), toHex(sha256.digest())); 
     } 
     return results; 
    } 

    private static String toHex(byte[] bytes) { 
     String result = ""; 
     if (bytes != null) { 
      StringBuilder sb = new StringBuilder(bytes.length * 2); 
      for (byte element : bytes) { 
       if ((element & 0xff) < 0x10) { 
        sb.append("0"); 
       } 
       sb.append(Long.toString(element & 0xff, 16)); 
      } 
      result = sb.toString().toUpperCase(); 
     } 
     return result; 
    } 

    private static String toHex(long value) { 
     return Long.toHexString(value).toUpperCase(); 
    } 

} 
+0

penso che la toHex è sbagliato. Se fai 'int newElement = ((int) element) & 0xff' e usalo invece che risolverebbe il tuo problema? – zapl

+0

@zapl: questo non cambierebbe nulla. –

+63

In parallelo al calcolo della somma di controllo, copiare il file in un file temporaneo, in modo da poter confrontare ciò che Java ottiene con ciò che si ottiene quando si utilizzano altri strumenti. Windows potrebbe essere strano ... Non ho mai visto Java commettere un errore nel calcolo degli hash ... –

risposta

238

Capito. Il file system di Windows si comporta in modo diverso a seconda dell'architettura del processo. Questo article explains it all - in particolare:

Ma che dire delle applicazioni a 32 bit con codifica del percorso del sistema e esecuzione in Windows a 64 bit? Come possono trovare la nuova cartella SysWOW64 senza modifiche nel codice del programma, si potrebbe pensare. La risposta è che l'emulatore reindirizza le chiamate alla cartella System32 alla cartella SysWOW64 in modo trasparente, quindi anche se la cartella è codificata in modo rigido nella cartella System32 (come C: \ Windows \ System32), l'emulatore si accerterà che venga utilizzata la cartella SysWOW64 . Quindi lo stesso codice sorgente, che utilizza la cartella System32, può essere compilato su entrambi i codici di programma a 32 e 64 bit senza alcuna modifica.

Provare a copiare da calc.exe altrove ... quindi eseguire di nuovo gli stessi strumenti. Otterrai gli stessi risultati di Java. Something riguardo al file system di Windows sta dando dati diversi agli strumenti di quanto non stia dando a Java ... Sono sicuro che si tratti di qualcosa che si trova nella directory di Windows, e quindi probabilmente gestito "diversamente".

Inoltre, l'ho riprodotto in C# ... e ho scoperto che dipende dall'architettura del processo in esecuzione. Quindi, ecco un esempio di programma:

using System; 
using System.IO; 
using System.Security.Cryptography; 

class Test 
{ 
    static void Main() 
    { 
     using (var md5 = MD5.Create()) 
     { 
      string path = "c:/Windows/System32/Calc.exe"; 
      var bytes = md5.ComputeHash(File.ReadAllBytes(path)); 
      Console.WriteLine(BitConverter.ToString(bytes)); 
     } 
    } 
} 

Ed ecco una sessione della console (meno chiacchiere dal compilatore):

c:\users\jon\Test>csc /platform:x86 Test.cs  

c:\users\jon\Test>test 
60-B7-C0-FE-AD-45-F2-06-6E-5B-80-5A-91-F4-F0-FC 

c:\users\jon\Test>csc /platform:x64 Test.cs 

c:\users\jon\Test>test 
10-E4-A1-D2-13-2C-CB-5C-67-59-F0-38-CD-B6-F3-C9 
+9

+1 ... quindi l'utente * "Pawel Veselov" * aveva ragione;) – TacticalCoder

+0

@TacticalCoder: Sì, sembra così. –

+63

Ci sono due versioni di 'calc.exe': 64bit in' C: \ Windows \ system32 \ 'e 32bit in' C: \ Windows \ SysWOW64 \ '. Per la compatibilità in un processo a 32 bit 'C: \ Windows \ system32 \' è mappato a 'C: \ Windows \ SysWOW64 \'. I processi a 64 bit lanceranno il calcolo a 64 bit, i processi a 32 bit il calcolo a 32 bit. Non sorprende che i loro checksum siano diversi. Se tieni il file aperto e guardi con 'handles.exe' o Process Explorer vedrai il percorso differente. – Richard