Java的摘要与外部实用程序的结果不同

我写了一个简单的Java类来生成Windows计算器文件的哈希值。 我正在使用Windows 7 Professional with SP1 。 我已经尝试过Java 6.0.29Java 7.0.03 。 有人可以告诉我为什么我从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(); } } 

得到它了。 Windows文件系统的行为有所不同,具体取决于进程的体系结构。 这篇文章解释了这一切 – 特别是:

但是,32位应用程序的系统path硬编码,并在64位Windows中运行? 他们如何能够在没有改变程序代码的情况下find新的SysWOW64文件夹,你可能会想。 答案是模拟器透明地将调用System32文件夹redirect到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