【问题标题】:Different results with Java's digest versus external utilitiesJava 的摘要与外部实用程序的不同结果
【发布时间】:2012-04-01 10:51:33
【问题描述】:

我编写了一个简单的 Java 类来生成 Windows Calculator 文件的哈希值。我正在使用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();
    }

}

【问题讨论】:

  • 我猜你的 toHex 是错误的。如果您使用int newElement = ((int) element) &amp; 0xff 并改用它,那会解决您的问题吗?
  • 在计算校验和的同时,将文件复制到某个临时文件中,这样您就可以比较 Java 获得的结果与您使用其他工具时获得的结果。 Windows 可能会像那样奇怪...我从未见过 Java 在计算哈希时出错...
  • 所有程序员都应该这样编程!代码非常干净整洁。
  • @user567496:与其他 Java SHA-1 实现相比,与命令行 sha1sum 实用程序相比,您的代码提供了正确的 SHA-1 哈希值。 (在 Linux 上使用文件进行测试,而不是使用 calc.exe)
  • @Fido:在这种情况下,它不可能是字符集问题,因为 OP 正在读取原始字节:他没有解码字符。

标签: java windows md5 digest wow64


【解决方案1】:

知道了。 Windows 文件系统的行为因进程的体系结构而异。这个article explains it all - 特别是:

但是对于系统路径硬编码并在 64 位 Windows 中运行的 32 位应用程序呢?您可能会想,他们如何在不更改程序代码的情况下找到新的 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

【讨论】:

  • calc.exe: 64bit 在C:\Windows\system32` and 32bit in C:\Windows\SysWOW64`中有两个版本。为了兼容 32 位进程 C:\Windows\system32` is mapped to C:\Windows\SysWOW64`。 64 位进程将启动 64 位计算,32 位进程将启动 32 位计算。他们的校验和不同也就不足为奇了。如果您打开文件并使用 handles.exe 或 Process Explorer 查看,您会看到不同的路径。
  • @Jon 这就是所谓的文件系统重定向器。
  • @DavidHeffernan 意见不一,也许与“可行”的定义有关。所有这些虚拟化确实违反了最小意外原则并增加了成本(分配和运行时间)。其他操作系统设法提供更好的 32-on-64 支持和更好的应用程序虚拟化,减少障碍/泄漏抽象(尝试在 Wow64 上运行垃圾收集程序,或尝试像 OP 一样比较 md5 总和,以及其他一些小众案例)。
  • 有时我想知道人们是否支持你是因为你是 jon skeet,而不是仅仅因为答案。我并不是说答案不好或任何东西,但是当答案是“Windows 中发生了某些事情”时,有 145 人赞成(公平地说,您确实提供了一个链接,但仍然)似乎人们正在考虑的不仅仅是您的答案他们赞成。我不是讨厌你,但这只是意味着我需要一段时间才能赶上你:P
  • 博客是我找到的。我希望有一些 Jon Skeet 魔术,但我觉得“嘿,我本可以做到的”。可能没有那么快,但你去了。好吧,也许我不能,但仍然。至于上限,它几乎没有什么安慰,因为那只是意味着任何一天你都会达到它,因此我永远赶不上你。哦,好吧...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-21
  • 2012-11-16
  • 1970-01-01
  • 2021-09-29
  • 1970-01-01
  • 2012-04-25
相关资源
最近更新 更多