Obtention de la somme de contrôle MD5 d'un fichier en Java
510
Je cherche à utiliser Java pour obtenir la somme de contrôle MD5 d'un fichier. J'ai été vraiment surpris, mais je n'ai rien trouvé qui montre comment obtenir la somme de contrôle MD5 d'un fichier.
Peut - être que cela vous aidera. Vous pouvez également rechercher la spécification, mais cela prendrait plus de temps car c'est compliqué.
waynecolvin
4
Gardez à l'esprit que, selon les recherches récentes, "le MD5 doit être considéré comme cryptographiquement cassé et impropre à une utilisation ultérieure". en.wikipedia.org/wiki/MD5
Zakharia Stanley
80
MD5 n'est plus considéré comme cryptographiquement sécurisé, mais il est toujours suffisant pour valider la cohérence des fichiers et il est plus rapide que SHA.
jiggy
2
@ZakhariaStanley Il s'agit d'une question sur le total de contrôle.
iPherian
L'utilisation canonique des sommes de contrôle MD5 sur les fichiers est d'éviter les remplacements hostiles des fichiers distribués. C'est là que ce n'est pas sûr. Mais dans un scénario où les exploits hostiles ne sont pas un problème, cela convient parfaitement.
Keith Tyler
Réponses:
541
Il existe un décorateur de flux d'entrée java.security.DigestInputStream, afin que vous puissiez calculer le résumé tout en utilisant le flux d'entrée comme vous le feriez normalement, au lieu d'avoir à effectuer un passage supplémentaire sur les données.
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();
Je suis d'accord, façon très élégante de calculer la somme de contrôle à la volée si vous faites déjà quelque chose avec les octets (c'est-à-dire en les lisant à partir d'une connexion HTTP).
Marc Novakowski
2
@AlPhaba Avez-vous déclaré le iscomme un InputStreamou un FileInputStream? Sonne comme vous l'avez utilisé FileInputStream, ce qui provoquerait cette erreur.
erickson
1
@barwnikk Cela fonctionne très bien en Java 8. MethodNotFoundne fait pas exception à Java standard; vous parlez peut-être d'une erreur de compilation? Dans tous les cas, si cela ne fonctionne pas pour vous, c'est un problème de configuration local ou un problème avec un autre code.
erickson
4
@barwnikk Encore une fois, c'est votre problème de configuration local. Il s'agit d'un code Java 7 et Java 8 valide. Si vous êtes coincé avec des outils de 2006, vous devrez vous adapter.
erickson
5
@erickson Vous ne mettez pas à jour l'objet MessageDigest avec le contenu du fichier. Rt? Ce code imprimera toujours un même résumé.
Ne fonctionne pas pour moi dans mon code Android, j'obtiens cette erreur ... java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString at org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUtils.java:215)
JPM
@JPM Supposez que vous avez déjà téléchargé et mis le commons-codec.jarsur votre chemin de classe ?
Leif Gruenwoldt
oui là-bas et j'ai exporté dans mon projet Android .. Je peux parcourir le code et la classe est là dans les fichiers source ... bizarre, ça doit être un problème avec Eclipse Android.
JPM
1
J'ai eu le même problème, mais il a été résolu par ce code `FileInputStream fis = new FileInputStream (new File (filePath)); octet de données [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (données); String md5 = String.valueOf (md5Chars); `
Dmitry_L
1
Agréable! Pour les nouveaux projets, je réfléchis toujours à deux fois avant d'ajouter une nouvelle dépendance, mais pour les projets existants, je n'ai qu'à vérifier si la bibliothèque est déjà là pour l'utiliser. +1
Pour votre cas d'utilisation, Files.hash()calcule et renvoie la valeur de résumé d'un fichier.
Par exemple un sha-1 calcul du résumé (changez SHA-1 en MD5 pour obtenir le résumé MD5)
HashCode hc =Files.asByteSource(file).hash(Hashing.sha1());"SHA-1: "+ hc.toString();
Notez que crc32 est beaucoup plus rapide que md5, alors utilisez crc32si vous n'avez pas besoin d'une somme de contrôle cryptographiquement sécurisée. Notez également quemd5 ne doit pas être utilisé pour stocker des mots de passe et similaires, car il est facile de forcer brutalement, pour l'utilisation des mots de passe bcrypt, déchiffrer ou sha-256 au lieu.
Pour une protection à long terme avec des hachages, un schéma de signature Merkle ajoute à la sécurité et le groupe d'étude post-quantique sur la cryptographie parrainé par la Commission européenne a recommandé l'utilisation de cette cryptographie pour une protection à long terme contre les ordinateurs quantiques ( réf .).
Notez que crc32 a un taux de collision plus élevé que les autres.
@Arash oui absolument - merci. J'ai mélangé la classe JDK Files et celle de Guava.
assylias
J'aime cette solution plus que celle d'Erickson car elle peut être emballée avec des options pour utiliser une programmation de style purement fonctionnelle
Gabriel Hernandez
2
Pour un gros fichier, cela utilisera beaucoup de mémoire puisque le fichier entier est lu puis alimenté dans le résumé au lieu de lire des morceaux et de les "digérer" au fur et à mesure qu'ils sont lus.
bernie
39
Guava fournit désormais une nouvelle API de hachage cohérente qui est beaucoup plus conviviale que les différentes API de hachage fournies dans le JDK. Voir Explication du hachage . Pour un fichier, vous pouvez obtenir facilement la somme MD5, CRC32 (avec la version 14.0+) ou bien d'autres hachages:
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 solution basée sur les communs de David Onter est meilleure car elle ne lit pas un fichier entier en mémoire.
Fran Marzoa
Au moins pour Spring 5 vous devez DigestUtils.md5Digest(InputStream inputStream)calculer le résumé MD5 et DigestUtils.md5DigestAsHex(InputStream inputStream)la représentation sous forme de chaîne hexadécimale des méthodes de résumé MD5 sans lire un fichier entier en mémoire.
Mike Shauneu
24
Une approche simple sans bibliothèques tierces utilisant Java 7
@edgecaseberg juste pour que la chaîne hexagonale soit bonne lors de l'impression sur la console
sunil
J'ai trouvé que je devais utiliser toLowerCase () au lieu de toUpperCase ().
Splendor
14
J'ai récemment dû le faire pour une chaîne dynamique, qui MessageDigestpeut représenter le hachage de nombreuses façons. Pour obtenir la signature du fichier comme vous obtiendrez avec la commande md5sum, j'ai dû faire quelque chose comme ceci:
Évidemment, cela ne répond pas à votre question sur la façon de le faire spécifiquement pour un fichier, la réponse ci-dessus traite bien ce calme. Je viens de passer beaucoup de temps à obtenir que la somme ressemble à la plupart des applications, et je pensais que vous pourriez rencontrer les mêmes problèmes.
La signature est le résumé au format hexadécimal. Moi aussi, j'ai trouvé que la représentation hexadécimale fonctionnait là où, comme vous le dites, d'autres représentations ne fonctionnent pas. Merci d'avoir mis cela en place.
Amit
C'est bien, mais .toString(16)cela supprimera les zéros de tête. String.format("%032x", ...)peut-être mieux.
Cependant, faites attention à l'utiliser BigInteger.toString()ici, car cela tronquera les zéros de tête ... (par exemple, essayez s = "27", la somme de contrôle devrait être "02e74f10e0327ad868d138f2b4fdd6f0")
J'appuie la suggestion d'utiliser Apache Commons Codec, j'ai remplacé notre propre code par cela.
Wow, je cherchais un problème où le MD5 fonctionnait parfaitement pour tout, sauf qu'un fichier ne nous donnait qu'une sortie à 31 chiffres hexadécimaux et échouait les md5checksums. cette troncature des 0 en tête est une énorme douleur ... Merci pour votre note.
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}}
Voici une fonction simple qui enveloppe le code de Sunil pour qu'il prenne un fichier comme paramètre. La fonction n'a pas besoin de bibliothèques externes, mais elle nécessite 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 goyave fournit une nouvelle API. Trouvez celui ci-dessous:
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
Voici une variante pratique qui utilise InputStream.transferTo()Java 9 et OutputStream.nullOutputStream()Java 11. Elle ne nécessite aucune bibliothèque externe et n'a pas besoin de charger le fichier entier en mémoire.
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()));}
Réponses:
Il existe un décorateur de flux d'entrée
java.security.DigestInputStream
, afin que vous puissiez calculer le résumé tout en utilisant le flux d'entrée comme vous le feriez normalement, au lieu d'avoir à effectuer un passage supplémentaire sur les données.la source
is
comme unInputStream
ou unFileInputStream
? Sonne comme vous l'avez utiliséFileInputStream
, ce qui provoquerait cette erreur.MethodNotFound
ne fait pas exception à Java standard; vous parlez peut-être d'une erreur de compilation? Dans tous les cas, si cela ne fonctionne pas pour vous, c'est un problème de configuration local ou un problème avec un autre code.Utilisez DigestUtils de la bibliothèque Apache Commons Codec :
la source
commons-codec.jar
sur votre chemin de classe ?Il y a un exemple à Java-How-to de Real utilisant la classe MessageDigest .
Consultez cette page pour des exemples utilisant CRC32 et SHA-1 également.
la source
read()
ne retournera pas zéro, et undo/while
n'est pas vraiment approprié.L' API com.google.common.hash offre:
Lisez le Guide de l' utilisateur ( IO Explained , Hashage Explained ).
Pour votre cas d'utilisation,
Files.hash()
calcule et renvoie la valeur de résumé d'un fichier.Par exemple un sha-1 calcul du résumé (changez SHA-1 en MD5 pour obtenir le résumé MD5)
Notez que crc32 est beaucoup plus rapide que md5, alors utilisez crc32si vous n'avez pas besoin d'une somme de contrôle cryptographiquement sécurisée. Notez également quemd5 ne doit pas être utilisé pour stocker des mots de passe et similaires, car il est facile de forcer brutalement, pour l'utilisation des mots de passe bcrypt, déchiffrer ou sha-256 au lieu.
Pour une protection à long terme avec des hachages, un schéma de signature Merkle ajoute à la sécurité et le groupe d'étude post-quantique sur la cryptographie parrainé par la Commission européenne a recommandé l'utilisation de cette cryptographie pour une protection à long terme contre les ordinateurs quantiques ( réf .).
Notez que crc32 a un taux de collision plus élevé que les autres.
la source
Files.hash()
est marqué comme obsolète, la méthode recommandée est:Files.asByteSource(file).hash(Hashing.sha1())
Hashing.sha1()
est devenu obsolète. La fonctionHashing.sha256()
est recommandée à la place. sourceUtilisation de nio2 (Java 7+) et pas de bibliothèques externes:
Pour comparer le résultat avec une somme de contrôle attendue:
la source
Guava fournit désormais une nouvelle API de hachage cohérente qui est beaucoup plus conviviale que les différentes API de hachage fournies dans le JDK. Voir Explication du hachage . Pour un fichier, vous pouvez obtenir facilement la somme MD5, CRC32 (avec la version 14.0+) ou bien d'autres hachages:
la source
D'accord. Je devais ajouter. Implémentation d'une ligne pour ceux qui ont déjà une dépendance Spring et Apache Commons ou qui prévoient de l'ajouter:
Option pour et Apache commons uniquement (crédit @duleshi):
J'espère que cela aide quelqu'un.
la source
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spring 5
vous devezDigestUtils.md5Digest(InputStream inputStream)
calculer le résumé MD5 etDigestUtils.md5DigestAsHex(InputStream inputStream)
la représentation sous forme de chaîne hexadécimale des méthodes de résumé MD5 sans lire un fichier entier en mémoire.Une approche simple sans bibliothèques tierces utilisant Java 7
Si vous devez imprimer ce tableau d'octets. Utilisez comme ci-dessous
Si vous avez besoin d'une chaîne hexadécimale hors de ce résumé. Utilisez comme ci-dessous
où DatatypeConverter est javax.xml.bind.DatatypeConverter
la source
toUpperCase
?J'ai récemment dû le faire pour une chaîne dynamique, qui
MessageDigest
peut représenter le hachage de nombreuses façons. Pour obtenir la signature du fichier comme vous obtiendrez avec la commande md5sum, j'ai dû faire quelque chose comme ceci:Évidemment, cela ne répond pas à votre question sur la façon de le faire spécifiquement pour un fichier, la réponse ci-dessus traite bien ce calme. Je viens de passer beaucoup de temps à obtenir que la somme ressemble à la plupart des applications, et je pensais que vous pourriez rencontrer les mêmes problèmes.
la source
.toString(16)
cela supprimera les zéros de tête.String.format("%032x", ...)
peut-être mieux.Ou vous pouvez obtenir plus d'informations http://www.asjava.com/core-java/java-md5-example/
la source
la source
Nous utilisions un code qui ressemble au code ci-dessus dans un article précédent en utilisant
Cependant, faites attention à l'utiliser
BigInteger.toString()
ici, car cela tronquera les zéros de tête ... (par exemple, essayezs = "27"
, la somme de contrôle devrait être"02e74f10e0327ad868d138f2b4fdd6f0"
)J'appuie la suggestion d'utiliser Apache Commons Codec, j'ai remplacé notre propre code par cela.
la source
la source
Méthode Java très rapide et propre qui ne repose pas sur des bibliothèques externes:
(Remplacez simplement MD5 par SHA-1, SHA-256, SHA-384 ou SHA-512 si vous le souhaitez)
la source
Une autre implémentation: Fast MD5 Implementation in Java
la source
MD5.asHex()
dans JDK 1.8.0 242.Méthode standard de l'environnement d'exécution Java :
Le résultat est égal à l'utilitaire linux md5sum.
la source
Voici une fonction simple qui enveloppe le code de Sunil pour qu'il prenne un fichier comme paramètre. La fonction n'a pas besoin de bibliothèques externes, mais elle nécessite Java 7.
Exemple de sortie:
la source
Si vous utilisez ANT pour construire, c'est extrêmement simple. Ajoutez ce qui suit à votre build.xml:
Où jarFile est le fichier JAR avec lequel vous souhaitez générer le MD5 et toDir est le répertoire dans lequel vous souhaitez placer le fichier MD5.
Plus d'infos ici.
la source
Google goyave fournit une nouvelle API. Trouvez celui ci-dessous:
la source
Voici une variante pratique qui utilise
InputStream.transferTo()
Java 9 etOutputStream.nullOutputStream()
Java 11. Elle ne nécessite aucune bibliothèque externe et n'a pas besoin de charger le fichier entier en mémoire.et
Retour
la source
la source