Je cherche à utiliser Java pour obtenir la somme de contrôle MD5 d'un fichier. J'étais vraiment surpris mais je n'ai rien trouvé qui montre comment obtenir la somme de contrôle MD5 d'un fichier.
Comment est-il fait?
Il existe un décorateur de flux d'entrée, Java.security.DigestInputStream
, qui vous permet de calculer le résumé en utilisant le flux d'entrée comme vous le feriez normalement, au lieu de devoir 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 = new DigestInputStream(is, md))
{
/* Read decorated stream (dis) to EOF as normal... */
}
byte[] digest = md.digest();
Utilisez DigestUtils à partir de Apache Commons Codec library:
try (InputStream is = Files.newInputStream(Paths.get("file.Zip"))) {
String md5 = org.Apache.commons.codec.digest.DigestUtils.md5Hex(is);
}
Il y a un exemple à Real-Java-How-to en utilisant la classe MessageDigest .
Consultez cette page pour des exemples utilisant CRC32 et SHA-1.
import Java.io.*;
import Java.security.MessageDigest;
public class MD5Checksum {
public static byte[] createChecksum(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5");
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
complete.update(buffer, 0, numRead);
}
} while (numRead != -1);
fis.close();
return complete.digest();
}
// see this How-to for a faster way to convert
// a byte array to a HEX string
public static String getMD5Checksum(String filename) throws Exception {
byte[] b = createChecksum(filename);
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
public static void main(String args[]) {
try {
System.out.println(getMD5Checksum("Apache-Tomcat-5.5.17.exe"));
// output :
// 0bb2827c5eacf570b6064e24e0e6653b
// ref :
// http://www.Apache.org/dist/
// Tomcat/tomcat-5/v5.5.17/bin
// /Apache-Tomcat-5.5.17.exe.MD5
// 0bb2827c5eacf570b6064e24e0e6653b *Apache-Tomcat-5.5.17.exe
}
catch (Exception e) {
e.printStackTrace();
}
}
}
L'API com.google.common.hash == := offre:
Lisez le Guide de l’utilisateur ( IO Explained , Hashing 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 de résumé (changez SHA-1 en MD5 pour obtenir un résumé MD5)
HashCode hc = Files.asByteSource(file).hash(Hashing.sha1());
"SHA-1: " + hc.toString();
Notez que crc32 est beaucoup plus rapide que md5 , utilisez donc crc32 si vous n'avez pas besoin d'une somme de contrôle sécurisée par cryptographie. Notez également que md5 ne doit pas être utilisé pour stocker des mots de passe, car il est trop facile de forcer brutalement. Pour les mots de passe, utilisez bcrypt , scrypt ou sha-256 ==.
Pour la protection à long terme avec les hachages a Merkle signature system ajoute à la sécurité et au groupe d'étude sur la cryptographie post-quantum parrainé par la Commission européenne a recommandé l'utilisation de cette cryptographie pour la protection à long terme contre le quantum ordinateurs ( ref ).
Notez que crc32 a un taux de collision plus élevé que les autres.
Utilisation de nio2 (Java 7+) et d’aucune bibliothèque externe:
byte[] b = Files.readAllBytes(Paths.get("/path/to/file"));
byte[] hash = MessageDigest.getInstance("MD5").digest(b);
Pour comparer le résultat avec une somme de contrôle attendue:
String expected = "2252290BC44BEAD16AA1BF89948472E8";
String actual = DatatypeConverter.printHexBinary(hash);
System.out.println(expected.equalsIgnoreCase(actual) ? "MATCH" : "NO MATCH");
Guava fournit désormais une nouvelle API de hachage cohérente, 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 de nombreux autres:
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 directly
long checksumResult = crc32.padToLong();
D'accord. Je devais ajouter. Implémentation sur une ligne pour ceux qui ont déjà une dépendance Spring et Apache Commons ou envisagent de l’ajouter:
DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))
Pour les options communes à Apache et seulement (crédit @duleshi):
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
J'espère que ça aide quelqu'un.
Une approche simple sans bibliothèques tierces utilisant Java 7
String path = "your complete file path";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
byte[] digest = md.digest();
Si vous devez imprimer ce tableau d'octets. Utiliser comme ci-dessous
System.out.println(Arrays.toString(digest));
Si vous avez besoin d'une chaîne hexadécimale en dehors de ce résumé. Utiliser comme ci-dessous
String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
System.out.println(digestInHex);
où DatatypeConverter est javax.xml.bind.DatatypeConverter
J'ai récemment eu à le faire pour une chaîne dynamique, MessageDigest
peut représenter le hachage de nombreuses façons. Pour obtenir la signature du fichier comme vous le feriez avec la commande md5sum, je devais faire quelque chose comme ceci:
try {
String s = "TEST STRING";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(s.getBytes(),0,s.length());
String signature = new BigInteger(1,md5.digest()).toString(16);
System.out.println("Signature: "+signature);
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
Cela ne répond évidemment pas à votre question sur la manière de le faire spécifiquement pour un fichier, la réponse ci-dessus traite de ce problème en douceur. Je viens de passer beaucoup de temps à faire en sorte que la somme ressemble à celle de la plupart des applications, et je pensais que vous pourriez rencontrer le même problème.
public static void main(String[] args) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
FileInputStream fis = new FileInputStream("c:\\Apache\\cxf.jar");
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = fis.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
};
byte[] mdbytes = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < mdbytes.length; i++) {
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Digest(in hex format):: " + sb.toString());
}
Ou vous pouvez obtenir plus d'informations http://www.asjava.com/core-Java/java-md5-example/
Nous utilisions du code qui ressemble au code ci-dessus dans un post précédent en utilisant
...
String signature = new BigInteger(1,md5.digest()).toString(16);
...
Cependant, faites bien attention à utiliser BigInteger.toString()
ici, car cela tronquera les zéros de gauche ... (pour un exemple, essayez s = "27"
, la somme de contrôle doit être "02e74f10e0327ad868d138f2b4fdd6f0"
)
J'appuie la suggestion d'utiliser Apache Commons Codec, j'ai remplacé notre propre code par cela.
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)
public String calcMD5() throws Exception{
byte[] buffer = new byte[8192];
MessageDigest md = MessageDigest.getInstance("MD5");
DigestInputStream dis = new DigestInputStream(new FileInputStream(new File("Path to file")), md);
try {
while (dis.read(buffer) != -1);
}finally{
dis.close();
}
byte[] bytes = md.digest();
// bytesToHex-method
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static String MD5Hash(String toHash) throws RuntimeException {
try{
return String.format("%032x", // produces lower case 32 char wide hexa left-padded with 0
new BigInteger(1, // handles large POSITIVE numbers
MessageDigest.getInstance("MD5").digest(toHash.getBytes())));
}
catch (NoSuchAlgorithmException e) {
// do whatever seems relevant
}
}
String checksum = DigestUtils.md5Hex(new FileInputStream(filePath));
Voici une fonction simple qui enveloppe le code de Sunil pour qu’il prenne un fichier comme paramètre. La fonction ne nécessite aucune bibliothèque externe, mais requiert 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;
public class Checksum {
/**
* 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
*/
public static String generate(File file) throws NoSuchAlgorithmException,IOException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(Files.readAllBytes(file.toPath()));
byte[] hash = messageDigest.digest();
return DatatypeConverter.printHexBinary(hash).toUpperCase();
}
public static void main(String argv[]) throws NoSuchAlgorithmException, IOException {
File file = new File("/Users/foo.bar/Documents/file.jar");
String hex = Checksum.generate(file);
System.out.printf("hex=%s\n", hex);
}
}
Exemple de sortie:
hex=B117DD0C3CBBD009AC4EF65B6D75C97B
méthode standard Java de l'environnement d'exécution :
public String checksum(File file) {
try {
InputStream fin = new FileInputStream(file);
Java.security.MessageDigest md5er =
MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024];
int read;
do {
read = fin.read(buffer);
if (read > 0)
md5er.update(buffer, 0, read);
} while (read != -1);
fin.close();
byte[] digest = md5er.digest();
if (digest == null)
return null;
String strDigest = "0x";
for (int i = 0; i < digest.length; i++) {
strDigest += Integer.toString((digest[i] & 0xff)
+ 0x100, 16).substring(1).toUpperCase();
}
return strDigest;
} catch (Exception e) {
return null;
}
}
Le résultat est égal à l'utilitaire linux md5sum.
Autre implémentation: Fast MD5 Implementation in Java
String hash = MD5.asHex(MD5.getHash(new File(filename)));
Si vous utilisez ANT pour construire, c'est très simple. Ajoutez ce qui suit à votre build.xml:
<checksum file="${jarFile}" todir="${toDir}"/>
Où jarFile est le fichier JAR contre lequel vous souhaitez générer le MD5 et toDir est le répertoire dans lequel vous souhaitez placer le fichier MD5.
Google Gava fournit une nouvelle API. Trouvez celui ci-dessous:
public static HashCode hash(File file,
HashFunction hashFunction)
throws IOException
Computes 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()
de Java 9, et OutputStream.nullOutputStream()
de Java 11. Il ne nécessite aucune bibliothèque externe et n'a pas besoin de charge le fichier entier en mémoire.
public static String hashFile(String algorithm, File f) throws IOException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm);
try(BufferedInputStream in = new BufferedInputStream((new FileInputStream(f)));
DigestOutputStream out = new DigestOutputStream(OutputStream.nullOutputStream(), md)) {
in.transferTo(out);
}
String fx = "%0" + (md.getDigestLength()*2) + "x";
return String.format(fx, new BigInteger(1, md.digest()));
}
et
hashFile("SHA-512", Path.of("src", "test", "resources", "some.txt").toFile());
résultats
"e30fa2784ba15be37833d569280e2163c6f106506dfb9b07dde67a24bfb90da65c661110cf2c5c6f71185754ee5ae3fd83a5465c92f72abd888b03187229da29"
public static String getMd5OfFile(String filePath)
{
String returnVal = "";
try
{
InputStream input = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
MessageDigest md5Hash = MessageDigest.getInstance("MD5");
int numRead = 0;
while (numRead != -1)
{
numRead = input.read(buffer);
if (numRead > 0)
{
md5Hash.update(buffer, 0, numRead);
}
}
input.close();
byte [] md5Bytes = md5Hash.digest();
for (int i=0; i < md5Bytes.length; i++)
{
returnVal += Integer.toString( ( md5Bytes[i] & 0xff ) + 0x100, 16).substring( 1 );
}
}
catch(Throwable t) {t.printStackTrace();}
return returnVal.toUpperCase();
}