Harici yardımcı programlara karşı Java'nın özeti ile farklı sonuçlar


194

Windows Hesap Makinesi dosyasının karma değerlerini oluşturmak için basit bir Java sınıfı yazdım. Kullanıyorum Windows 7 Professional with SP1. Denedim Java 6.0.29ve Java 7.0.03. Birisi bana Java'dan (birçok!) Harici yardımcı programlara ve / veya web sitelerine karşı neden farklı karma değerler aldığımı söyleyebilir mi? Dıştaki her şey birbiriyle eşleşir, sadece Java farklı sonuçlar döndürür.

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

}

Sanırım toHex'iniz yanlış. Bunu yapar int newElement = ((int) element) & 0xffve kullanırsanız, bu sorununuzu çözer mi?
12'de zapl

64
Çek toplamının hesaplanmasına paralel olarak, dosyayı diğer geçici dosyaları kullandığınızda aldığınız ile karşılaştırabilmeniz için dosyayı geçici bir dosyaya kopyalayın. Windows böyle garip olabilir ... Java'nın karmaları hesaplarken hata yaptığını hiç görmedim ...
Pawel Veselov 15:12

3
Tüm programcılar böyle programlamalıdır! Kod çok temiz ve derli toplu.
Martijn Courteaux

2
@ user567496: kodunuza değer için diğer Java SHA-1 uygulamasına ve sha1sum util komut satırına kıyasla doğru SHA-1 karmalarını verir ... (calc.exe ile değil Linux'ta dosyalar ile test edilmiştir)
TacticalCoder

1
@Fido: Bu durumda OP ham bayt okuduğu için karakter takımı sorunu olamazdı: karakterleri çözmüyor.
TacticalCoder

Yanıtlar:


239

Anladım. Windows dosya sistemi, işleminizin mimarisine bağlı olarak farklı davranıyor. Bu makale her şeyi açıklıyor - özellikle:

Peki, sistem yolu sabit kodlanmış ve 64 bit Windows'ta çalışan 32 bit uygulamalara ne dersiniz? Yeni SysWOW64 klasörünü program kodunda değişiklik yapmadan nasıl bulabileceklerini düşünebilirsiniz. Yanıt, öykünücünün System32 klasörüne yapılan çağrıları SysWOW64 klasörüne şeffaf bir şekilde yönlendirmesidir, bu nedenle klasör System32 klasörüne sabit olarak kodlanmış olsa bile (C: \ Windows \ System32 gibi), öykünücü bunun yerine SysWOW64 klasörünün kullanıldığından emin olur . Bu nedenle, System32 klasörünü kullanan aynı kaynak kodu, herhangi bir değişiklik yapılmadan hem 32 bit hem de 64 bit program koduna derlenebilir.

calc.exeBaşka bir yere kopyalamayı deneyin ... sonra aynı araçları tekrar çalıştırın. Java ile aynı sonuçları alırsınız. Windows dosya sistemi ile ilgili bir şey , araçlara Java'ya verdiğinden farklı veriler veriyor ... Eminim Windows dizininde olmasıyla ilgili bir şeydir ve muhtemelen "farklı" olarak ele alınır.

Ayrıca, C # ... 'da çoğalttım ve çalıştırdığınız işlemin mimarisine bağlı olduğunu öğrendim . İşte örnek bir program:

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

Ve burada bir konsol oturumu (derleyiciden eksi sohbet):

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

64
İki sürümü vardır calc.exe: C:\Windows\system32` and 32bit in C: \ Windows \ SysWOW64` içinde 64bit . 32 bit işlemlerde uyumluluk için C:\Windows\system32` is mapped to C: \ Windows \ SysWOW64`. 64bit süreçler 64bit calc, 32bit süreçler 32bit calc başlatır. Checksum'ların farklı olması şaşırtıcı değil. Dosyayı açık tutarsanız handles.exeveya Process Explorer ile birlikte bakarsanız farklı yolu görürsünüz.
Richard

25
@Jon Bir şey Dosya Sistemi Yeniden Yönlendiricisi olarak bilinir.
David Heffernan

9
@DavidHeffernan Görüşler, belki de 'yaşayabilir' tanımıyla birlikte değişir. Tüm bu sanallaştırma, en az sürpriz ilkesini ihlal eder ve maliyetler (tahsis ve çalışma süresi) ekler. Diğer işletim sistemleri, daha az takılma / sızıntılı soyutlama ile hem daha iyi 32'ye 64 desteği hem de daha iyi uygulama sanallaştırması sağlamayı başarıyor (Wow64 üzerinde çöp toplama programları çalıştırmayı deneyin veya OP gibi md5 toplamlarını ve birkaç diğer niş durumu karşılaştırmayı deneyin).
Mart'ta selam

5
Bazen merak ediyorum, insanlar sadece cevap yüzünden değil, jon skeet sizsiniz . Ben cevap iyi değil ya da bir şey demiyorum, ama cevap "pencerelerde bir şey oluyor" olduğunda onaylar (adil olmak için bir bağlantı sağlamak, ama yine de) insanlar sadece cevap daha sonra düşünüyor gibi görünüyor onlar yükselir. Senden nefret etmiyorum, ama bu seni yakalamadan bir süre önce olacağı anlamına geliyor: P
Jason Ridge

5
Blog böyle buldum. Jon Skeet büyüsünü umuyordum ama "Hey, bunu yapabilirdim" gibi hissettim. Muhtemelen o kadar hızlı değil ama işte gidiyorsunuz. Tamam belki yapamadım ama yine de. Başlığa gelince, içinde küçük bir teselli var, çünkü bu sadece herhangi bir günün ona ulaşacağınız anlamına geliyor ve bu yüzden asla size yetişemiyorum. Oh iyi ...
Jason Ridge
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.