Sto cercando di utilizzare Java per ottenere il checksum MD5 di un file. Sono stato davvero sorpreso, ma non sono stato in grado di trovare nulla che mostri come ottenere il checksum MD5 di un file.
Com'è fatto?
Sto cercando di utilizzare Java per ottenere il checksum MD5 di un file. Sono stato davvero sorpreso, ma non sono stato in grado di trovare nulla che mostri come ottenere il checksum MD5 di un file.
Com'è fatto?
Risposte:
C'è un decoratore del flusso di input java.security.DigestInputStream
, in modo che tu possa calcolare il digest mentre usi il flusso di input come faresti normalmente, invece di dover fare un passaggio extra sui dati.
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();
is
come un InputStream
o un FileInputStream
? Sembra che tu l'abbia usato FileInputStream
, il che causerebbe questo errore.
MethodNotFound
non fa eccezione a Java standard; forse stai parlando di un errore del compilatore? In ogni caso, se non funziona per te, è un problema di configurazione locale o un altro codice.
Usa DigestUtils dalla libreria Codec di Apache Commons :
try (InputStream is = Files.newInputStream(Paths.get("file.zip"))) {
String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
}
commons-codec.jar
già il tuo percorso di classe?
C'è un esempio nel Java-How-to di Real che utilizza la classe MessageDigest .
Controlla quella pagina per esempi usando anche CRC32 e 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();
}
}
}
read()
non restituirà zero e a do/while
non è davvero appropriato.
L' API com.google.common.hash offre:
Leggi la Guida per l'utente ( IO spiegato , hash spiegato ).
Per il tuo caso d'uso Files.hash()
calcola e restituisce il valore digest per un file.
Ad esempio a sha-1 calcolo digest (modifica SHA-1 in MD5 per ottenere digest MD5)
HashCode hc = Files.asByteSource(file).hash(Hashing.sha1());
"SHA-1: " + hc.toString();
Nota che crc32 è molto più veloce di md5, quindi usa crc32se non hai bisogno di un checksum crittograficamente sicuro. Si noti anche chemd5 non dovrebbe essere usato per archiviare password e simili poiché è facile da forzare, per l'uso delle password bcrypt, scrypt o sha-256 anziché.
Per la protezione a lungo termine con hash uno schema di firma Merkle aggiunge sicurezza e il gruppo di studio sulla crittografia post quantistica sponsorizzato dalla Commissione europea ha raccomandato l'uso di questa crittografia per la protezione a lungo termine contro i computer quantistici ( rif ).
Nota che crc32 ha un tasso di collisione più elevato rispetto agli altri.
Files.hash()
è contrassegnato come deprecato, il metodo consigliato è:Files.asByteSource(file).hash(Hashing.sha1())
Hashing.sha1()
è contrassegnato come obsoleto. Si Hashing.sha256()
consiglia invece la funzione. fonte
Utilizzo di nio2 (Java 7+) e nessuna libreria esterna:
byte[] b = Files.readAllBytes(Paths.get("/path/to/file"));
byte[] hash = MessageDigest.getInstance("MD5").digest(b);
Per confrontare il risultato con un checksum previsto:
String expected = "2252290BC44BEAD16AA1BF89948472E8";
String actual = DatatypeConverter.printHexBinary(hash);
System.out.println(expected.equalsIgnoreCase(actual) ? "MATCH" : "NO MATCH");
Guava ora fornisce una nuova e coerente API di hash che è molto più user-friendly rispetto alle varie API di hashing fornite nel JDK. Vedi Hashing spiegato . Per un file, puoi ottenere facilmente la somma MD5, CRC32 (con la versione 14.0+) o molti altri hash:
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();
Ok. Ho dovuto aggiungere. Una linea di implementazione per coloro che hanno già la dipendenza da Spring e Apache Commons o hanno in programma di aggiungerlo:
DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))
Solo opzione for commons Apache (credit @duleshi):
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spero che questo aiuti qualcuno.
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spring 5
te devi DigestUtils.md5Digest(InputStream inputStream)
calcolare il digest MD5 e DigestUtils.md5DigestAsHex(InputStream inputStream)
per la rappresentazione esadecimale della stringa dei metodi digest MD5 senza leggere un intero file in memoria.
Un approccio semplice senza librerie di terze parti che utilizzano Java 7
String path = "your complete file path";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
byte[] digest = md.digest();
Se è necessario stampare questo array di byte. Usa come di seguito
System.out.println(Arrays.toString(digest));
Se hai bisogno di stringhe esadecimali da questo digest. Usa come di seguito
String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
System.out.println(digestInHex);
dove DatatypeConverter è javax.xml.bind.DatatypeConverter
toUpperCase
?
Di recente ho dovuto farlo solo per una stringa dinamica, in MessageDigest
grado di rappresentare l'hash in numerosi modi. Per ottenere la firma del file come si otterrebbe con il comando md5sum ho dovuto fare qualcosa del genere:
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();
}
Questo ovviamente non risponde alla tua domanda su come farlo specificamente per un file, la risposta di cui sopra si occupa di quella calma silenziosa. Ho appena trascorso molto tempo a fare in modo che la somma assomigliasse alla maggior parte delle applicazioni, e ho pensato che potresti avere lo stesso problema.
.toString(16)
eliminerà gli zeri iniziali. String.format("%032x", ...)
forse meglio.
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());
}
Oppure puoi ottenere maggiori informazioni http://www.asjava.com/core-java/java-md5-example/
String checksum = DigestUtils.md5Hex(new FileInputStream(filePath));
Stavamo usando un codice che ricorda il codice sopra in un post precedente usando
...
String signature = new BigInteger(1,md5.digest()).toString(16);
...
Tuttavia, fai attenzione all'utilizzo BigInteger.toString()
qui, poiché troncerà gli zeri iniziali ... (ad esempio, prova s = "27"
, il checksum dovrebbe essere"02e74f10e0327ad868d138f2b4fdd6f0"
)
Secondo il suggerimento di usare Apache Commons Codec, ho sostituito il nostro codice con quello.
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
}
}
Metodo Java molto veloce e pulito che non si basa su librerie esterne:
(Sostituisci semplicemente MD5 con SHA-1, SHA-256, SHA-384 o SHA-512 se vuoi quelli)
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);
}
Un'altra implementazione: implementazione MD5 veloce in Java
String hash = MD5.asHex(MD5.getHash(new File(filename)));
MD5.asHex()
in JDK 1.8.0 242.
Modo Java Runtime Environment standard :
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;
}
}
Il risultato è uguale all'utilità md5sum di linux.
Ecco una semplice funzione che avvolge il codice di Sunil in modo che prenda un file come parametro. La funzione non richiede librerie esterne, ma richiede 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);
}
}
Esempio di output:
hex=B117DD0C3CBBD009AC4EF65B6D75C97B
Se stai usando ANT per costruire, questo è semplicissimo. Aggiungi quanto segue a build.xml:
<checksum file="${jarFile}" todir="${toDir}"/>
Dove jarFile è il JAR su cui si desidera generare MD5 e toDir è la directory in cui si desidera posizionare il file MD5.
Google guava fornisce una nuova API. Trova quello qui sotto:
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
Ecco una comoda variante che utilizza InputStream.transferTo()
Java 9 e OutputStream.nullOutputStream()
Java 11. Non richiede librerie esterne e non è necessario caricare l'intero file in memoria.
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()));
}
e
hashFile("SHA-512", Path.of("src", "test", "resources", "some.txt").toFile());
ritorna
"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();
}