Unterschiedliche Ergebnisse mit dem Digest von Java im Vergleich zu externen Dienstprogrammen

Lesezeit: 7 Minuten

Benutzer-Avatar
Mike Viens

Ich habe eine einfache Java-Klasse geschrieben, um die Hash-Werte der Windows-Rechnerdatei zu generieren. ich benutze Windows 7 Professional with SP1. Ich habe versucht Java 6.0.29 und Java 7.0.03. Kann mir jemand sagen, warum ich unterschiedliche Hash-Werte von Java im Vergleich zu (vielen!) externen Dienstprogrammen und/oder Websites erhalte? Alles Äußere passt zusammen, nur Java liefert unterschiedliche Ergebnisse.

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

}

  • Ich denke, Ihr toHex ist falsch. Wenn Sie tun int newElement = ((int) element) & 0xff und verwenden Sie das stattdessen würde das Ihr Problem lösen?

    – zapl

    15. März 2012 um 21:07 Uhr

  • Kopieren Sie parallel zur Berechnung der Prüfsumme die Datei in eine temporäre Datei, damit Sie vergleichen können, was Java mit dem Ergebnis anderer Tools erhält. Windows mag so seltsam sein … Ich habe noch nie gesehen, dass Java einen Fehler beim Berechnen von Hashes gemacht hat …

    – Pawel Weselow

    15. März 2012 um 21:13 Uhr


  • Alle Programmierer sollten so programmieren! Der Code ist sehr sauber und ordentlich.

    – Martin Courteaux

    15. März 2012 um 21:15 Uhr

  • @ user567496: Für das, was es wert ist, gibt Ihr Code die richtigen SHA-1-Hashes im Vergleich zu anderen Java-SHA-1-Implementierungen und im Vergleich zur Befehlszeile an sha1sum util… (getestet mit Dateien unter Linux, nicht mit calc.exe)

    – TacticalCoder

    15. März 2012 um 21:16 Uhr


  • @Fido: In diesem Fall kann es sich nicht um ein Zeichensatzproblem handeln, da OP Rohbytes liest: Er decodiert keine Zeichen.

    – TacticalCoder

    15. März 2012 um 21:37 Uhr

Benutzer-Avatar
Jon Skeet

Ich habs. Das Windows-Dateisystem verhält sich je nach Architektur Ihres Prozesses unterschiedlich. Dies Artikel erklärt alles – im Speziellen:

Aber was ist mit 32-Bit-Anwendungen, bei denen der Systempfad fest codiert ist und die in einem 64-Bit-Windows ausgeführt werden? Wie können sie den neuen SysWOW64-Ordner ohne Änderungen im Programmcode finden, werden Sie vielleicht denken. Die Antwort ist, dass der Emulator Aufrufe an den System32-Ordner transparent an den SysWOW64-Ordner umleitet, sodass der Emulator sicherstellt, dass stattdessen der SysWOW64-Ordner verwendet wird, selbst wenn der Ordner fest auf den System32-Ordner (wie C:\Windows\System32) codiert ist . So kann derselbe Quellcode, der den System32-Ordner verwendet, ohne Änderungen sowohl in 32-Bit- als auch in 64-Bit-Programmcode kompiliert werden.

Versuchen Sie es mit Kopieren calc.exe an einen anderen Ort … und führen Sie dann dieselben Tools erneut aus. Sie erhalten die gleichen Ergebnisse wie Java. Etwas über das Windows-Dateisystem gibt den Tools andere Daten als Java … Ich bin mir sicher, dass es etwas damit zu tun hat, dass es sich im Windows-Verzeichnis befindet und daher wahrscheinlich “anders” behandelt wird.

Außerdem habe ich es in C# reproduziert … und herausgefunden, dass es davon abhängt Architektur des Prozesses, den Sie ausführen. Also hier ein Beispielprogramm:

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

Und hier ist eine Konsolensitzung (ohne Geschwätz vom Compiler):

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

  • Es gibt zwei Versionen von calc.exe: 64-Bit-Eingang C:\Windows\system32` and 32bit in C:\Windows\SysWOW64`. Für die Kompatibilität in einem 32-Bit-Prozess C:\Windows\system32` is mapped to C:\Windows\SysWOW64`. 64-Bit-Prozesse starten die 64-Bit-Berechnung, 32-Bit-Prozesse die 32-Bit-Berechnung. Kein Wunder, dass ihre Prüfsummen unterschiedlich sind. Halte die Datei offen und schaue mit handles.exe oder Process Explorer sehen Sie den anderen Pfad.

    – Richard

    15. März 2012 um 21:43 Uhr


  • @Jon Dieses Etwas ist als File System Redirector bekannt.

    – David Heffernan

    16. März 2012 um 7:21 Uhr

  • @DavidHeffernan Die Meinungen gehen auseinander, vielleicht zusammen mit der Definition von “lebensfähig”. All diese Virtualisierung verstößt gegen das Prinzip der geringsten Überraschung und verursacht zusätzliche Kosten (Belegung und Laufzeit). Andere Betriebssysteme schaffen es, sowohl eine bessere 32-auf-64-Unterstützung als auch eine bessere Anwendungsvirtualisierung mit weniger Fehlern/undichten Abstraktionen bereitzustellen (versuchen Sie, Garbage Collection-Programme auf Wow64 auszuführen, oder versuchen Sie, md5-Summen wie das OP und einige andere Nischenfälle zu vergleichen).

    – sehen

    16. März 2012 um 20:40 Uhr


  • Manchmal frage ich mich, ob die Leute dich positiv bewerten, weil du Jon Skeet bist, nicht einzig und allein wegen der antwort. Ich sage nicht, dass die Antwort nicht gut oder so ist, aber 145 Upvotes, wenn die Antwort “Etwas passiert in Windows” lautet (um fair zu sein, geben Sie einen Link an, aber trotzdem), scheinen die Leute mehr als nur Ihre Antwort in Betracht zu ziehen wann sie stimmen zu. Ich hasse dich nicht, aber das bedeutet nur, dass es eine Weile dauern wird, bis ich dich einhole 😛

    – Jason Ridge

    20. März 2012 um 13:50 Uhr


  • Der Blog ist, wie ich ihn gefunden habe. Ich hatte auf etwas Jon Skeet-Magie gehofft, aber ich hatte das Gefühl: “Hey, das hätte ich tun können”. Wahrscheinlich nicht annähernd so schnell, aber los geht’s. Ok vielleicht hätte ich es nicht haben können, aber trotzdem. Was die Obergrenze betrifft, so tröstet sie wenig, denn das bedeutet nur, dass Sie sie jeden Tag erreichen werden, und ich kann Sie daher niemals einholen. Nun ja…

    – Jason Ridge

    20. März 2012 um 14:05 Uhr

1352690cookie-checkUnterschiedliche Ergebnisse mit dem Digest von Java im Vergleich zu externen Dienstprogrammen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy