Obtener la suma de comprobación MD5 de un archivo en Java
510
Estoy buscando utilizar Java para obtener la suma de comprobación MD5 de un archivo. Me sorprendió mucho, pero no he podido encontrar nada que muestre cómo obtener la suma de comprobación MD5 de un archivo.
Quizás esto ayude. También puede buscar la especificación, pero eso requeriría más trabajo ya que es complicado.
waynecolvin
44
Tenga en cuenta que según la investigación reciente "MD5 debe considerarse criptográficamente roto y no apto para su uso posterior". en.wikipedia.org/wiki/MD5
Zakharia Stanley
80
MD5 ya no se considera criptográficamente seguro, pero sigue siendo suficiente para validar la consistencia del archivo y es más rápido que SHA.
jiggy
2
@ZakhariaStanley Esta es una pregunta sobre la suma de comprobación.
iPherian
El uso canónico para las sumas de verificación MD5 en los archivos es evitar reemplazos hostiles de archivos distribuidos. Ahí es donde no es seguro. Pero en un escenario donde las hazañas hostiles no son una preocupación, es perfectamente adecuado.
Keith Tyler
Respuestas:
541
Hay un decorador de flujo de entrada java.security.DigestInputStream, para que pueda calcular el resumen mientras usa el flujo de entrada como lo haría normalmente, en lugar de tener que hacer un pase adicional sobre los datos.
MessageDigest md =MessageDigest.getInstance("MD5");try(InputStream is =Files.newInputStream(Paths.get("file.txt"));DigestInputStream dis =newDigestInputStream(is, md)){/* Read decorated stream (dis) to EOF as normal... */}byte[] digest = md.digest();
Estoy de acuerdo, es una forma muy elegante de calcular la suma de verificación sobre la marcha si ya está haciendo algo con los bytes (es decir, leerlos desde una conexión HTTP).
Marc Novakowski,
2
@AlPhaba ¿Declaraste el iscomo un InputStreamo un FileInputStream? Suena como lo usaste FileInputStream, lo que causaría este error.
erickson
1
@barwnikk Funciona bien en Java 8. MethodNotFoundno es una excepción de Java estándar; tal vez estás hablando de un error del compilador? En cualquier caso, si no funciona para usted, es un problema de configuración local o un problema con otro código.
erickson
44
@barwnikk Nuevamente, ese es su problema de configuración local. Este es un código válido de Java 7 y Java 8. Si está atrapado con herramientas de 2006, tendrá que adaptarse.
erickson
55
@erickson No está actualizando el objeto MessageDigest con el contenido del archivo. Rt? Este código imprimirá siempre un mismo resumen.
No funciona para mí en mi código de Android Obtengo este error ... java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString en org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUtils.java:215)
JPM
@JPM ¿Presumiste que descargaste y pusiste el commons-codec.jaren tu classpath ya?
Leif Gruenwoldt
Sí, y exporté en mi proyecto de Android ... Puedo recorrer el código y la clase está allí en los archivos de origen ... raro, debe ser un problema de Android Eclipse.
JPM
1
Tuve el mismo problema, pero lo solucionó con este código `FileInputStream fis = new FileInputStream (nuevo archivo (filePath)); datos de bytes [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (datos); String md5 = String.valueOf (md5Chars); `
Dmitry_L
1
¡Agradable! Para proyectos nuevos, siempre lo pienso dos veces antes de agregar una nueva dependencia, pero para proyectos existentes solo tengo que verificar si la biblioteca ya está allí para usarla. +1
Para su caso de uso Files.hash() calcula y devuelve el valor de resumen para un archivo.
Por ejemplo un sha-1 Cálculo del resumen (cambie SHA-1 a MD5 para obtener el resumen MD5)
HashCode hc =Files.asByteSource(file).hash(Hashing.sha1());"SHA-1: "+ hc.toString();
Tenga en cuenta que crc32 es mucho más rápido que md5, entonces usa crc32si no necesita una suma de verificación criptográficamente segura. Tenga en cuenta también quemd5 no debe usarse para almacenar contraseñas y similares, ya que es fácil de aplicar fuerza bruta, para el uso de contraseñas brypt, scrypt o sha-256 en lugar.
Para la protección a largo plazo con hashes, un esquema de firma Merkle se suma a la seguridad y el Grupo de Estudio de Criptografía Post Quantum patrocinado por la Comisión Europea ha recomendado el uso de esta criptografía para la protección a largo plazo contra las computadoras cuánticas ( ref ).
Tenga en cuenta que crc32 tiene una tasa de colisión más alta que las demás.
@Arash sí, absolutamente, gracias. Mezclé la clase de archivos JDK y la de Guava.
Assylias
Esta solución me gusta más que la de Erickson, ya que puede envolverse con opciones para usar programación de estilo funcional puro
Gabriel Hernández
2
Para un archivo grande, esto usará mucha memoria ya que se lee todo el archivo y luego se alimenta al resumen en lugar de leer fragmentos y "digerirlos" a medida que se leen.
bernie
39
Guava ahora proporciona una nueva API de hashing coherente que es mucho más fácil de usar que las diversas API de hashing proporcionadas en el JDK. Ver Hashing explicado . Para un archivo, puede obtener fácilmente la suma MD5, CRC32 (con la versión 14.0+) o muchos otros hashes:
HashCode md5 =Files.hash(file,Hashing.md5());byte[] md5Bytes = md5.asBytes();String md5Hex = md5.toString();HashCode crc32 =Files.hash(file,Hashing.crc32());int crc32Int = crc32.asInt();// the Checksum API returns a long, but it's padded with 0s for 32-bit CRC// this is the value you would get if using that API directlylong checksumResult = crc32.padToLong();
La solución basada en los comunes de David Onter es mejor porque no lee un archivo completo en la memoria.
Fran Marzoa
Al menos Spring 5 , DigestUtils.md5Digest(InputStream inputStream)debe calcular el resumen MD5 y la DigestUtils.md5DigestAsHex(InputStream inputStream)representación de cadena hexadecimal de los métodos de resumen MD5 sin leer un archivo completo en la memoria.
Mike Shauneu
24
Un enfoque simple sin bibliotecas de terceros que utilizan Java 7
@edgecaseberg solo para que la cadena hexadecimal se vea bien mientras se imprime en la consola
sunil
Descubrí que necesitaba usar toLowerCase () en lugar de toUpperCase ().
Esplendor
14
Recientemente tuve que hacer esto solo para una cadena dinámica, MessageDigestpuede representar el hash de numerosas maneras. Para obtener la firma del archivo como lo haría con el comando md5sum , tuve que hacer algo como esto:
Obviamente, esto no responde a su pregunta sobre cómo hacerlo específicamente para un archivo, la respuesta anterior se ocupa muy bien de eso. Acabo de pasar mucho tiempo haciendo que la suma se vea como la mayoría de las aplicaciones lo muestran, y pensé que podría tener el mismo problema.
La firma es el resumen en formato hexadecimal. También encontré la representación hexadecimal para trabajar donde, como usted dice, otras representaciones no funcionan. Gracias por colgar esto.
amit
Esto es bueno, pero .toString(16)arrojará ceros a la izquierda. String.format("%032x", ...)quizás mejor.
Sin embargo, BigInteger.toString()tenga cuidado al usar aquí, ya que truncará los ceros a la izquierda ... (por ejemplo, intente s = "27", la suma de verificación debería ser "02e74f10e0327ad868d138f2b4fdd6f0")
Secundo la sugerencia de usar Apache Commons Codec, reemplacé nuestro propio código con eso.
Wow, estaba investigando un problema en el que el material MD5 funcionaba perfectamente para todo, excepto que un archivo solo nos daba una salida de 31 dígitos hexadecimales y fallaba las sumas de md5. que truncar los ceros iniciales es un gran dolor ... Gracias por su nota.
Mike
8
publicstaticString MD5Hash(String toHash)throwsRuntimeException{try{returnString.format("%032x",// produces lower case 32 char wide hexa left-padded with 0newBigInteger(1,// handles large POSITIVE numbers MessageDigest.getInstance("MD5").digest(toHash.getBytes())));}catch(NoSuchAlgorithmException e){// do whatever seems relevant}}
Aquí hay una función simple que envuelve el código de Sunil para que tome un archivo como parámetro. La función no necesita ninguna biblioteca externa, pero sí requiere Java 7.
import java.io.File;import java.io.IOException;import java.nio.file.Files;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import javax.xml.bind.DatatypeConverter;publicclassChecksum{/**
* Generates an MD5 checksum as a String.
* @param file The file that is being checksummed.
* @return Hex string of the checksum value.
* @throws NoSuchAlgorithmException
* @throws IOException
*/publicstaticString generate(File file)throwsNoSuchAlgorithmException,IOException{MessageDigest messageDigest =MessageDigest.getInstance("MD5");
messageDigest.update(Files.readAllBytes(file.toPath()));byte[] hash = messageDigest.digest();returnDatatypeConverter.printHexBinary(hash).toUpperCase();}publicstaticvoid main(String argv[])throwsNoSuchAlgorithmException,IOException{File file =newFile("/Users/foo.bar/Documents/file.jar");String hex =Checksum.generate(file);System.out.printf("hex=%s\n", hex);}}
Google guava ofrece una nueva API. Encuentra el siguiente:
publicstaticHashCode hash(File file,HashFunction hashFunction)throwsIOExceptionComputes the hash code of the file using hashFunction.Parameters:
file - the file to read
hashFunction - the hash function to use to hash the data
Returns:
the HashCode of all of the bytes in the file
Throws:IOException-if an I/O error occurs
Since:12.0
Aquí hay una variación práctica que utiliza InputStream.transferTo()Java 9 y OutputStream.nullOutputStream()Java 11. No requiere bibliotecas externas y no necesita cargar todo el archivo en la memoria.
publicstaticString hashFile(String algorithm,File f)throwsIOException,NoSuchAlgorithmException{MessageDigest md =MessageDigest.getInstance(algorithm);try(BufferedInputStream in =newBufferedInputStream((newFileInputStream(f)));DigestOutputStream out =newDigestOutputStream(OutputStream.nullOutputStream(), md)){
in.transferTo(out);}String fx ="%0"+(md.getDigestLength()*2)+"x";returnString.format(fx,newBigInteger(1, md.digest()));}
Respuestas:
Hay un decorador de flujo de entrada
java.security.DigestInputStream
, para que pueda calcular el resumen mientras usa el flujo de entrada como lo haría normalmente, en lugar de tener que hacer un pase adicional sobre los datos.fuente
is
como unInputStream
o unFileInputStream
? Suena como lo usasteFileInputStream
, lo que causaría este error.MethodNotFound
no es una excepción de Java estándar; tal vez estás hablando de un error del compilador? En cualquier caso, si no funciona para usted, es un problema de configuración local o un problema con otro código.Utilice DigestUtils de la biblioteca de códecs de Apache Commons :
fuente
commons-codec.jar
en tu classpath ya?Hay un ejemplo en Real-Java-How-to usando el MessageDigest clase .
Consulte esa página para ver ejemplos de uso de CRC32 y SHA-1 también.
fuente
read()
no devolverá cero, y ado/while
no es realmente apropiado.La API com.google.common.hash ofrece:
Lea la Guía del usuario ( IO explicado , Hash explicado ).
Para su caso de uso
Files.hash()
calcula y devuelve el valor de resumen para un archivo.Por ejemplo un sha-1 Cálculo del resumen (cambie SHA-1 a MD5 para obtener el resumen MD5)
Tenga en cuenta que crc32 es mucho más rápido que md5, entonces usa crc32si no necesita una suma de verificación criptográficamente segura. Tenga en cuenta también quemd5 no debe usarse para almacenar contraseñas y similares, ya que es fácil de aplicar fuerza bruta, para el uso de contraseñas brypt, scrypt o sha-256 en lugar.
Para la protección a largo plazo con hashes, un esquema de firma Merkle se suma a la seguridad y el Grupo de Estudio de Criptografía Post Quantum patrocinado por la Comisión Europea ha recomendado el uso de esta criptografía para la protección a largo plazo contra las computadoras cuánticas ( ref ).
Tenga en cuenta que crc32 tiene una tasa de colisión más alta que las demás.
fuente
Files.hash()
está marcado como obsoleto, la forma recomendada es:Files.asByteSource(file).hash(Hashing.sha1())
Hashing.sha1()
está marcado como obsoleto. La funciónHashing.sha256()
se recomienda en su lugar. fuenteUsando nio2 (Java 7+) y sin bibliotecas externas:
Para comparar el resultado con una suma de verificación esperada:
fuente
Guava ahora proporciona una nueva API de hashing coherente que es mucho más fácil de usar que las diversas API de hashing proporcionadas en el JDK. Ver Hashing explicado . Para un archivo, puede obtener fácilmente la suma MD5, CRC32 (con la versión 14.0+) o muchos otros hashes:
fuente
Okay. Tuve que agregar. Implementación de una línea para aquellos que ya tienen dependencia de Spring y Apache Commons o planean agregarla:
Opción para los comunes comunes de Apache (crédito @duleshi):
Espero que esto ayude a alguien.
fuente
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spring 5
,DigestUtils.md5Digest(InputStream inputStream)
debe calcular el resumen MD5 y laDigestUtils.md5DigestAsHex(InputStream inputStream)
representación de cadena hexadecimal de los métodos de resumen MD5 sin leer un archivo completo en la memoria.Un enfoque simple sin bibliotecas de terceros que utilizan Java 7
Si necesita imprimir esta matriz de bytes. Use como a continuación
Si necesita una cadena hexadecimal fuera de este resumen. Use como a continuación
donde DatatypeConverter es javax.xml.bind.DatatypeConverter
fuente
toUpperCase
?Recientemente tuve que hacer esto solo para una cadena dinámica,
MessageDigest
puede representar el hash de numerosas maneras. Para obtener la firma del archivo como lo haría con el comando md5sum , tuve que hacer algo como esto:Obviamente, esto no responde a su pregunta sobre cómo hacerlo específicamente para un archivo, la respuesta anterior se ocupa muy bien de eso. Acabo de pasar mucho tiempo haciendo que la suma se vea como la mayoría de las aplicaciones lo muestran, y pensé que podría tener el mismo problema.
fuente
.toString(16)
arrojará ceros a la izquierda.String.format("%032x", ...)
quizás mejor.O puede obtener más información http://www.asjava.com/core-java/java-md5-example/
fuente
fuente
Estábamos usando un código que se parece al código anterior en una publicación anterior usando
Sin embargo,
BigInteger.toString()
tenga cuidado al usar aquí, ya que truncará los ceros a la izquierda ... (por ejemplo, intentes = "27"
, la suma de verificación debería ser"02e74f10e0327ad868d138f2b4fdd6f0"
)Secundo la sugerencia de usar Apache Commons Codec, reemplacé nuestro propio código con eso.
fuente
fuente
Método Java muy rápido y limpio que no se basa en bibliotecas externas:
(Simplemente reemplace MD5 con SHA-1, SHA-256, SHA-384 o SHA-512 si lo desea)
fuente
Otra implementación: Implementación rápida de MD5 en Java
fuente
MD5.asHex()
en JDK 1.8.0 242.Forma estándar de Java Runtime Environment :
El resultado es igual a la utilidad linux md5sum.
fuente
Aquí hay una función simple que envuelve el código de Sunil para que tome un archivo como parámetro. La función no necesita ninguna biblioteca externa, pero sí requiere Java 7.
Salida de ejemplo:
fuente
Si está utilizando ANT para construir, esto es muy simple. Agregue lo siguiente a su build.xml:
Donde jarFile es el JAR en el que desea generar el MD5 y toDir es el directorio donde desea colocar el archivo MD5.
Más información aquí.
fuente
Google guava ofrece una nueva API. Encuentra el siguiente:
fuente
Aquí hay una variación práctica que utiliza
InputStream.transferTo()
Java 9 yOutputStream.nullOutputStream()
Java 11. No requiere bibliotecas externas y no necesita cargar todo el archivo en la memoria.y
devoluciones
fuente
fuente