Mendapatkan Checksum MD5 File di Jawa


510

Saya mencari untuk menggunakan Java untuk mendapatkan MD5 checksum dari suatu file. Saya benar-benar terkejut tetapi saya belum dapat menemukan apa pun yang menunjukkan cara mendapatkan MD5 checksum dari suatu file.

Bagaimana ini dilakukan?


Mungkin ini akan membantu. Anda juga bisa melihat speknya tetapi itu akan lebih sulit karena rumit.
waynecolvin

4
Perlu diingat bahwa menurut penelitian terbaru "MD5 harus dianggap rusak secara kriptografis dan tidak cocok untuk penggunaan lebih lanjut". en.wikipedia.org/wiki/MD5
Zakharia Stanley

80
MD5 tidak lagi dianggap aman secara kriptografis, tetapi masih cukup untuk memvalidasi konsistensi file dan lebih cepat daripada SHA.
jiggy

2
@ZakhariaStanley Ini adalah pertanyaan tentang checksumming.
iPherian

Penggunaan kanonik untuk checksum MD5 pada file adalah untuk menghindari penggantian file yang didistribusikan secara bermusuhan. Di situlah tidak aman. Tetapi dalam skenario di mana eksploitasi yang bermusuhan tidak menjadi perhatian, itu sangat cocok.
Keith Tyler

Jawaban:


541

Ada dekorator aliran input java.security.DigestInputStream,, sehingga Anda dapat menghitung intisari menggunakan aliran input seperti biasa, alih-alih harus membuat data tambahan.

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

4
Saya setuju, cara yang sangat elegan untuk menghitung checksum dengan cepat jika Anda sudah melakukan sesuatu dengan byte (yaitu membacanya dari koneksi HTTP).
Marc Novakowski

2
@AlPhaba Apakah Anda menyatakan issebagai InputStreamatau a FileInputStream? Kedengarannya seperti yang Anda gunakan FileInputStream, yang akan menyebabkan kesalahan ini.
erickson

1
@barwnikk berfungsi dengan baik di Java 8. MethodNotFoundtidak terkecuali dari Java standar; mungkin Anda berbicara tentang kesalahan kompiler? Bagaimanapun, jika itu tidak berhasil untuk Anda, itu adalah masalah konfigurasi lokal, atau masalah dengan kode lain.
erickson

4
@barwnikk Sekali lagi, itu adalah masalah konfigurasi lokal Anda. Ini adalah kode Java 7 dan Java 8 yang valid. Jika Anda terjebak dengan alat dari tahun 2006, Anda harus beradaptasi.
erickson

5
@erickson Anda tidak memperbarui objek MessageDigest dengan konten file. Rt? Kode ini akan mencetak intisari yang selalu sama.
sunil

302

Gunakan DigestUtils dari pustaka Codec Apache Commons :

try (InputStream is = Files.newInputStream(Paths.get("file.zip"))) {
    String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
}

1
Tidak berfungsi untuk saya dalam kode android saya, saya mendapatkan kesalahan ini ... java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString di org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUtils.java .: 15)
JPM

@ JPM Anggap Anda sudah mengunduh dan meletakkannya commons-codec.jardi classpath Anda?
Leif Gruenwoldt

ya di sana dan saya diekspor di proyek android saya .. Saya bisa melangkah melalui kode dan kelas ada di file sumber ... aneh, pasti ada masalah Android Eclipse.
JPM

1
Saya memiliki masalah yang sama, tetapi diperbaiki dengan kode ini `FileInputStream fis = FileInputStream baru (File baru (filePath)); data byte [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (data); String md5 = String.valueOf (md5Chars); `
Dmitry_L

1
Bagus! Untuk proyek baru, saya selalu berpikir dua kali sebelum menambahkan ketergantungan baru tetapi untuk proyek yang sudah ada saya hanya perlu memeriksa apakah perpustakaan sudah ada untuk menggunakannya. +1
OscarRyz

164

Ada contoh di Java-How-to Real menggunakan kelas MessageDigest .

Periksa halaman itu untuk contoh menggunakan CRC32 dan SHA-1 juga.

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

70
Yap ... masih online setelah 11 tahun! :-)
RealHowTo

Contoh di Java's How-To dari Real bekerja dengan sempurna, dan mudah diimplementasikan.
bakoyaro

Loop baca sedikit canggung. read()tidak akan mengembalikan nol, dan a do/whiletidak terlalu tepat.
Marquis of Lorne

10
@ EJP Terima kasih atas tanggapan Anda yang tepat waktu.
Bill the Lizard

byte [] buffer = byte baru [1024]; dapatkah kita mengubah ukuran dari 1024 menjadi sesuatu yang lebih optimal?
Jalpesh

90

The com.google.common.hash menawarkan API:

  • API ramah pengguna terpadu untuk semua fungsi hash
  • Implementasi murmur 32- dan 128-bit seedable3
  • md5 (), sha1 (), sha256 (), sha512 () adapter, ubah hanya satu baris kode untuk beralih di antara ini, dan bergumam.
  • goodFastHash (int bits), untuk saat Anda tidak peduli algoritma apa yang Anda gunakan
  • Utilitas umum untuk instance HashCode, seperti kombinasikanOrdered / kombinasikanTidak teratur

Baca Panduan Pengguna ( Dijelaskan IO , Dijelaskan Hashing ).

Untuk kasus penggunaan Anda Files.hash()menghitung dan mengembalikan nilai digest untuk file.

Misalnya a digest digest (ubah SHA-1 ke MD5 untuk mendapatkan MD5 digest)

HashCode hc = Files.asByteSource(file).hash(Hashing.sha1());
"SHA-1: " + hc.toString();

Catat itu jauh lebih cepat daripada , jadi gunakan jika Anda tidak memerlukan checksum yang aman secara kriptografis. Perhatikan juga itu tidak boleh digunakan untuk menyimpan kata sandi dan sejenisnya karena mudah untuk memaksa, untuk penggunaan kata sandi , atau sebagai gantinya.

Untuk perlindungan jangka panjang dengan hash, skema tanda tangan Merkle menambah keamanan dan The Post Quantum Cryptography Study Group yang disponsori oleh Komisi Eropa merekomendasikan penggunaan kriptografi ini untuk perlindungan jangka panjang terhadap komputer kuantum ( ref ).

Catat itu memiliki tingkat tabrakan yang lebih tinggi daripada yang lain.


Bagian Files.hash seperti apa yang disebutkan di atas yang tidak mencakup Files.hash?
Oluies

2
The Files.hash()ditandai sebagai usang, cara yang direkomendasikan adalah:Files.asByteSource(file).hash(Hashing.sha1())
erkfel

1
Dan pada Januari 2018 Hashing.sha1()ditandai usang. Fungsi Hashing.sha256()ini direkomendasikan sebagai gantinya. sumber
MagicLegend

60

Menggunakan nio2 (Java 7+) dan tidak ada perpustakaan eksternal:

byte[] b = Files.readAllBytes(Paths.get("/path/to/file"));
byte[] hash = MessageDigest.getInstance("MD5").digest(b);

Untuk membandingkan hasilnya dengan checksum yang diharapkan:

String expected = "2252290BC44BEAD16AA1BF89948472E8";
String actual = DatatypeConverter.printHexBinary(hash);
System.out.println(expected.equalsIgnoreCase(actual) ? "MATCH" : "NO MATCH");

@Arash ya benar - terima kasih. Saya mencampur kelas File JDK dan Guava.
assylias

Saya suka solusi ini lebih dari erickson karena dapat dibungkus dengan Opsional untuk menggunakan pemrograman gaya Fungsional murni
Gabriel Hernandez

2
Untuk file besar ini akan menggunakan banyak memori karena seluruh file dibaca dan kemudian diumpankan ke digest daripada membaca potongan dan "mencerna" mereka saat mereka membaca.
bernie

39

Guava sekarang menyediakan API hashing baru yang konsisten, yang jauh lebih ramah pengguna daripada berbagai API hashing yang disediakan di JDK. Lihat Hashing Dijelaskan . Untuk file, Anda bisa mendapatkan jumlah MD5, CRC32 (dengan versi 14.0+) atau banyak hash lainnya dengan mudah:

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

32

Baik. Saya harus menambahkan. Implementasi satu baris untuk mereka yang sudah memiliki ketergantungan Spring dan Apache Commons atau berencana untuk menambahkannya:

DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))

Opsi hanya untuk dan Apache commons (kredit @duleshi):

DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))

Semoga ini bisa membantu seseorang.


1
IniDigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
duleshi

Solusi berbasis David Onter commons lebih baik karena tidak membaca seluruh file ke dalam memori.
Fran Marzoa

Setidaknya bagi Spring 5 Anda harus DigestUtils.md5Digest(InputStream inputStream)menghitung MD5 digest dan DigestUtils.md5DigestAsHex(InputStream inputStream)untuk representasi string heksadesimal dari metode digest MD5 tanpa membaca seluruh file ke dalam memori.
Mike Shauneu

24

Pendekatan sederhana tanpa perpustakaan pihak ketiga menggunakan Java 7

String path = "your complete file path";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
byte[] digest = md.digest();

Jika Anda perlu mencetak array byte ini. Gunakan seperti di bawah ini

System.out.println(Arrays.toString(digest));

Jika Anda membutuhkan string hex keluar dari intisari ini. Gunakan seperti di bawah ini

String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
System.out.println(digestInHex);

di mana DatatypeConverter adalah javax.xml.bind.DatatypeConverter


Mengapa toUpperCase?
EdgeCaseBerg

@edgecaseberg hanya untuk string hex terlihat bagus saat mencetaknya ke konsol
sunil

Saya merasa perlu menggunakan toLowerCase () alih-alih toUpperCase ().
Kemegahan

14

Saya baru-baru ini harus melakukan ini hanya untuk string dinamis, MessageDigestdapat mewakili hash dengan berbagai cara. Untuk mendapatkan tanda tangan dari file seperti yang Anda dapatkan dengan perintah md5sum saya harus melakukan sesuatu seperti ini:

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

Ini jelas tidak menjawab pertanyaan Anda tentang bagaimana melakukannya secara khusus untuk file, jawaban di atas berkaitan dengan tenang itu. Saya hanya menghabiskan banyak waktu untuk mendapatkan jumlah agar terlihat seperti kebanyakan aplikasi menampilkannya, dan berpikir Anda mungkin mengalami masalah yang sama.


Tanda tangan adalah intisari dalam format heksadesimal. Saya juga menemukan representasi heksadesimal untuk bekerja di mana, seperti yang Anda katakan, representasi lain tidak berfungsi. Terima kasih telah menyiapkan ini.
amit

Ini bagus, tetapi .toString(16)akan membuang angka nol di depan. String.format("%032x", ...)mungkin lebih baik.
Harold

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

Atau Anda bisa mendapatkan info lebih lanjut http://www.asjava.com/core-java/java-md5-example/



9

Kami menggunakan kode yang menyerupai kode di atas dalam posting sebelumnya menggunakan

...
String signature = new BigInteger(1,md5.digest()).toString(16);
...

Namun, berhati-hatilah untuk menggunakannya di BigInteger.toString()sini, karena akan memotong nol di depan ... (misalnya, coba s = "27", checksum seharusnya "02e74f10e0327ad868d138f2b4fdd6f0")

Saya saran kedua untuk menggunakan Apache Commons Codec, saya mengganti kode kita sendiri dengan itu.


1
Wow, saya sedang mencari masalah di mana hal-hal MD5 bekerja dengan sempurna untuk semuanya, kecuali file hanya memberi kita 31 hex output, dan gagal pada md5checksums. bahwa memotong 0s memimpin adalah rasa sakit yang sangat besar ... Terima kasih atas catatan Anda.
Mike

8
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
   }
}

8

Metode Java yang sangat cepat & bersih yang tidak bergantung pada pustaka eksternal:

(Cukup ganti MD5 dengan SHA-1, SHA-256, SHA-384 atau SHA-512 jika Anda menginginkannya)

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


6

Cara Java Runtime Environment standar :

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

Hasilnya sama dengan utilitas linux md5sum.


6

Berikut adalah fungsi sederhana yang membungkus kode Sunil sehingga mengambil File sebagai parameter. Fungsi ini tidak memerlukan pustaka eksternal, tetapi membutuhkan 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);            
    }


}

Contoh output:

hex=B117DD0C3CBBD009AC4EF65B6D75C97B

3

Jika Anda menggunakan ANT untuk membangun, ini sangat sederhana. Tambahkan yang berikut ke build.xml Anda:

<checksum file="${jarFile}" todir="${toDir}"/>

Di mana jarFile adalah JAR yang ingin Anda hasilkan MD5, dan toDir adalah direktori tempat Anda ingin meletakkan file MD5.

Info lebih lanjut di sini.


3

Google jambu menyediakan API baru. Temukan yang di bawah ini:

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

3

Berikut ini adalah variasi praktis yang memanfaatkan InputStream.transferTo()dari Java 9, dan OutputStream.nullOutputStream()dari Java 11. Tidak memerlukan pustaka eksternal dan tidak perlu memuat seluruh file ke dalam memori.

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

dan

hashFile("SHA-512", Path.of("src", "test", "resources", "some.txt").toFile());

kembali

"e30fa2784ba15be37833d569280e2163c6f106506dfb9b07dde67a24bfb90da65c661110cf2c5c6f71185754ee5ae3fd83a5465c92f72abd888b03187229da29"

2
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();
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.