2012-03-15 21 views
192

He escrito una clase Java simple para generar los valores hash del archivo Calculador de Windows. Estoy usando Windows 7 Professional with SP1. He intentado Java 6.0.29 y Java 7.0.03. ¿Puede alguien decirme por qué obtengo diferentes valores de hash de Java frente a (¡muchos!) Utilidades externas y/o sitios web. Todo lo externo coincide entre sí, solo que Java devuelve resultados diferentes.Diferentes resultados con el resumen de Java versus utilidades externas

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

} 
+0

pienso que su toHex está mal. Si haces 'int newElement = ((int) element) & 0xff' y usas eso, ¿eso resolvería tu problema? – zapl

+0

@zapl: Eso no cambiaría nada. –

+63

Paralelamente al cálculo de la suma de verificación, copie el archivo en algún archivo temporal, de modo que pueda comparar lo que obtiene Java con lo que obtiene cuando usa otras herramientas. Windows puede ser raro así ... Nunca vi que Java cometiera un error al calcular hashes ... –

Respuesta

238

Lo tengo. El sistema de archivos de Windows se comporta de manera diferente según la arquitectura de su proceso. Esto article explains it all - en particular:

Pero, ¿qué pasa con las aplicaciones de 32 bits que tienen la ruta del sistema codificada y que se ejecuta en un Windows de 64 bits? ¿Cómo pueden encontrar la nueva carpeta SysWOW64 sin cambios en el código del programa? La respuesta es que el emulador redirige las llamadas a la carpeta System32 a la carpeta SysWOW64 de forma transparente, incluso si la carpeta está codificada en la carpeta System32 (como C: \ Windows \ System32), el emulador se asegurará de que se use la carpeta SysWOW64. . Por lo tanto, el mismo código fuente, que usa la carpeta System32, se puede compilar para el código del programa de 32 bits y de 64 bits sin ningún cambio.

Intente copiar calc.exe en otro lugar ... luego vuelva a ejecutar las mismas herramientas. Obtendrás los mismos resultados que Java. Algo sobre el sistema de archivos de Windows está dando datos diferentes a las herramientas de lo que le está dando a Java ... Estoy seguro de que tiene algo que ver con que está en el directorio de Windows, y por lo tanto probablemente se maneje "de manera diferente".

Además, lo he reproducido en C# ... y descubrí que depende de la arquitectura del proceso que está ejecutando. Así que aquí hay un programa de ejemplo:

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

Y aquí hay una sesión de consola (menos charla del compilador):

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 
+9

+1 ... así que el usuario * "Pawel Veselov" * tenía razón;) – TacticalCoder

+0

@TacticalCoder: Sí, parece que sí. –

+63

Hay dos versiones de 'calc.exe': 64 bits en' C: \ Windows \ system32 \ 'y 32 bits en' C: \ Windows \ SysWOW64 \ '. Para la compatibilidad en un proceso de 32 bits, 'C: \ Windows \ system32 \' está mapeado a 'C: \ Windows \ SysWOW64 \'. Los procesos de 64 bits lanzarán el cálculo de 64 bits, 32 bits procesa el cálculo de 32 bits. No es sorprendente que sus sumas de comprobación sean diferentes. Si mantiene el archivo abierto y mira con 'handles.exe' o Process Explorer, verá la ruta diferente. – Richard

Cuestiones relacionadas