2012-03-15 45 views
192

我寫了一個簡單的Java類來生成Windows計算器文件的哈希值。我正在使用Windows 7 Professional with SP1。我試過Java 6.0.29Java 7.0.03。有人能告訴我爲什麼我從Java與(很多!)外部實用程序和/或網站獲得不同的哈希值?一切外部匹配,只有Java返回不同的結果。Java的摘要與外部實用程序的不同結果

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

我猜你的toHex是錯誤的。如果你做'int newElement =((int)element)&0xff'並用它來解決你的問題? – zapl 2012-03-15 21:07:39

+0

@zapl:那不會改變任何東西。 – 2012-03-15 21:08:34

+63

在計算校驗和的同時,將文件複製到某個臨時文件,以便您可以比較使用其他工具時獲得的Java與您獲得的內容。 Windows可能很奇怪......我從來沒有見過Java計算散列錯誤...... – 2012-03-15 21:13:10

回答

238

明白了。 Windows文件系統的行爲有所不同,具體取決於進程的體系結構。這article explains it all - 特別是:

但是,32位應用程序的系統路徑硬編碼並運行在64位Windows?他們如何能夠在不改變程序代碼的情況下找到新的SysWOW64文件夾,你可能會想。答案是模擬器透明地將調用System32文件夾重定向到SysWOW64文件夾,所以即使該文件夾硬編碼到System32文件夾(如C:\ Windows \ System32),模擬器也會確保使用SysWOW64文件夾。因此,使用System32文件夾的相同源代碼可以在不做任何更改的情況下編譯爲32位和64位程序代碼。

嘗試將calc.exe複製到其他地方...然後再次運行相同的工具。您將獲得與Java相同的結果。 關於Windows文件系統的一些東西正在給這些工具提供不同的數據,而不是它給予Java的......我確定這是與它在Windows目錄中的事情有關,因此可能處理「不同」。

此外,我已經轉載它在C#中...發現它取決於您正在運行的進程的體系結構。所以這裏有一個示例程序:

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

和這裏(從編譯器減顫)是一個控制檯會話:

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 ...因此用戶*「Pawel Veselov」*是正確的; ) – TacticalCoder 2012-03-15 21:22:41

+0

@TacticalCoder:是的,看起來像。 – 2012-03-15 21:23:49

+63

'calc.exe'有兩個版本:'C:\ Windows \ system32 \'中的64位和'C:\ Windows \ SysWOW64 \'中的32位。爲了在32位進程中兼容'C:\ Windows \ system32 \'映射到'C:\ Windows \ SysWOW64 \'。 64位進程將啓動64位計算,32位進程將32位計算。毫不奇怪,他們的校驗和是不同的。如果您打開文件並使用'handles.exe'或Process Explorer查看,您將看到不同的路徑。 – Richard 2012-03-15 21:43:45

相關問題