Java의 다이제스트와 외부 유틸리티의 다른 결과


194

Windows 계산기 파일의 해시 값을 생성하는 간단한 Java 클래스를 작성했습니다. 사용하고 Windows 7 Professional with SP1있습니다. 나는 시도 Java 6.0.29하고 Java 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) & 0xff하고 대신 사용하면 문제가 해결됩니까?
zapl

64
체크섬 계산과 병행하여 파일을 일부 임시 파일로 복사하여 Java가 얻는 것과 다른 도구를 사용할 때 얻는 것과 비교할 수 있습니다. Windows가 그렇게 이상 할 수도 있습니다 ... Java가 해시를 계산하는 실수를 본 적이 없습니다 ...
Pawel Veselov

3
모든 프로그래머는 이와 같이 프로그래밍해야합니다! 코드는 매우 깨끗하고 깔끔합니다.
Martijn Courteaux

2
@ user567496 : 코드의 가치에 따라 다른 Java SHA-1 구현과 비교하고 명령 줄 sha1sum util ... (calc.exe가 아닌 Linux에서 파일로 테스트)과 비교하여 올바른 SHA-1 해시를 제공합니다.
TacticalCoder

1
@Fido :이 경우 OP가 원시 바이트를 읽고 있기 때문에 문자 세트 문제가 될 수 없습니다 : 그는 문자를 디코딩하지 않습니다.
TacticalCoder

답변:


239

알았다. 프로세스의 아키텍처에 따라 Windows 파일 시스템이 다르게 작동합니다. 이 기사는 특히 다음을 설명합니다 .

그러나 시스템 경로가 하드 코딩되어 있고 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

64
C : \ Windows \ SysWOW64 calc.exe에는 64 비트 의 두 가지 버전이 있습니다 C:\Windows\system32` and 32bit in . 32 비트 프로세스 C:\Windows\system32` is mapped to C : \ Windows \ SysWOW64 에서 호환됩니다 . 64 비트 프로세스는 64 비트 계산을 시작하고 32 비트 프로세스는 32 비트 계산을 시작합니다. 그들의 체크섬이 다르다는 것은 놀라운 일이 아닙니다. 파일을 열어 놓고 handles.exe또는 프로세스 탐색기를 보면 다른 경로가 표시됩니다.
Richard

25
@Jon 저것은 파일 시스템 리디렉터로 알려져 있습니다.
David Heffernan

9
@DavidHeffernan 의견은 아마도 'viable'의 정의와 함께 다양합니다. 이 모든 가상화는 최소한의 놀람 원칙을 위반하고 비용 (할당 및 런타임)을 추가합니다. 다른 운영 체제는 더 적은 스낵 / 누수 추상화 (Wow64에서 가비지 수집 프로그램을 실행하거나 OP와 같은 md5 합계와 다른 틈새 사례를 비교해보십시오)로 더 나은 32-64 지원 및 응용 프로그램 가상화를 모두 제공합니다.
sehe

5
당신은 존이 아닌, 스키트 때문에 사람들이 당신을 upvote에 때로는 궁금 단독 때문에 대답. 나는 대답이 좋지 않다고 말하지는 않지만 대답이 "창문에서 일어나는 일"(링크를 제공하는 것은 공정하지만)은 사람들이 당신의 대답보다 더 많은 것을 고려하고있는 것처럼 보일 때 145 upvotes 그들은 공감합니다. 나는 당신을 싫어하지 않지만 이것은 단지 내가 당신에게 따라 잡기 전에 시간이 걸릴 것을 의미합니다 : P
Jason Ridge

5
블로그는 내가 찾은 방법입니다. 나는 Jon Skeet의 마술을 원했지만 "이봐, 내가 할 수있을 것"이라고 느꼈다. 아마 빨리는 아니지만 당신은 간다. 좋아, 어쩌면 가질 수는 없지만 여전히. 모자에 관해서는, 그 위로는 거의 없습니다. 왜냐하면 그것은 주어진 날이 당신이 그것을 도달 할 것이라는 것을 의미하기 때문에, 나는 결코 당신을 따라 잡을 수 없습니다. 잘 ..
Jason Ridge
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.