Tôi đang tìm cách sử dụng Java để lấy tổng kiểm MD5 của một tệp. Tôi thực sự ngạc nhiên nhưng tôi không thể tìm thấy bất cứ điều gì chỉ ra cách lấy tổng kiểm tra MD5 của một tệp.
Làm thế nào được thực hiện?
Tôi đang tìm cách sử dụng Java để lấy tổng kiểm MD5 của một tệp. Tôi thực sự ngạc nhiên nhưng tôi không thể tìm thấy bất cứ điều gì chỉ ra cách lấy tổng kiểm tra MD5 của một tệp.
Làm thế nào được thực hiện?
Câu trả lời:
Có một trình trang trí luồng đầu vào java.security.DigestInputStream
, để bạn có thể tính toán thông báo trong khi sử dụng luồng đầu vào như bình thường, thay vì phải truyền thêm dữ liệu.
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
là một InputStream
hay a FileInputStream
? Âm thanh như bạn đã sử dụng FileInputStream
, sẽ gây ra lỗi này.
MethodNotFound
không phải là ngoại lệ so với Java tiêu chuẩn; có lẽ bạn đang nói về một lỗi biên dịch? Trong mọi trường hợp, nếu nó không hoạt động với bạn, thì đó là sự cố cấu hình cục bộ hoặc sự cố với mã khác.
Sử dụng DigestUtils từ thư viện Codec Apache Commons :
try (InputStream is = Files.newInputStream(Paths.get("file.zip"))) {
String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
}
commons-codec.jar
vào classpath của bạn rồi?
Có một ví dụ tại Java - Cách sử dụng MessageDigest của Real lớp .
Kiểm tra trang đó để biết ví dụ sử dụng CRC32 và 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()
sẽ không trả về số 0 và do/while
không thực sự phù hợp.
Các com.google.common.hash Mời API:
Đọc Hướng dẫn sử dụng ( Giải thích IO , Giải thích băm ).
Đối với trường hợp sử dụng của bạn Files.hash()
tính toán và trả về giá trị tiêu hóa cho một tệp.
Ví dụ sha-1 tính toán tiêu hóa (thay đổi SHA-1 thành MD5 để nhận thông báo MD5)
HashCode hc = Files.asByteSource(file).hash(Hashing.sha1());
"SHA-1: " + hc.toString();
Lưu ý rằng crc32 nhanh hơn nhiều md5, nên sử dụng crc32nếu bạn không cần một tổng kiểm tra an toàn bằng mật mã. Cũng lưu ý rằngmd5 không nên được sử dụng để lưu trữ mật khẩu và những thứ tương tự vì nó dễ dàng để vũ trang, để sử dụng mật khẩu tiền điện tử, tiền điện tử hoặc là sha-256 thay thế.
Để bảo vệ lâu dài với băm, sơ đồ chữ ký Merkle tăng thêm tính bảo mật và Nhóm Nghiên cứu Mật mã học Lượng tử do Ủy ban Châu Âu tài trợ đã khuyến nghị sử dụng mật mã này để bảo vệ lâu dài đối với máy tính lượng tử ( ref ).
Lưu ý rằng crc32 có tỷ lệ va chạm cao hơn những người khác.
Files.hash()
được đánh dấu là bị phản đối, cách đề nghị là:Files.asByteSource(file).hash(Hashing.sha1())
Hashing.sha1()
được đánh dấu không dùng nữa. Các chức năng Hashing.sha256()
được đề nghị thay thế. nguồn
Sử dụng nio2 (Java 7+) và không có thư viện bên ngoài:
byte[] b = Files.readAllBytes(Paths.get("/path/to/file"));
byte[] hash = MessageDigest.getInstance("MD5").digest(b);
Để so sánh kết quả với tổng kiểm tra dự kiến:
String expected = "2252290BC44BEAD16AA1BF89948472E8";
String actual = DatatypeConverter.printHexBinary(hash);
System.out.println(expected.equalsIgnoreCase(actual) ? "MATCH" : "NO MATCH");
Guava hiện cung cấp API băm mới, phù hợp, thân thiện với người dùng hơn nhiều so với các API băm khác nhau được cung cấp trong JDK. Xem Băm giải thích . Đối với một tệp, bạn có thể nhận được tổng MD5, CRC32 (với phiên bản 14.0+) hoặc nhiều giá trị băm khác:
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();
Đồng ý. Tôi đã phải thêm. Triển khai một dòng cho những người đã có sự phụ thuộc của Spring và Apache Commons hoặc đang có kế hoạch thêm nó:
DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))
Tùy chọn chỉ dành cho và commons Apache (credit @duleshi):
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Hy vọng điều này sẽ giúp được ai đó.
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spring 5
bạn phải DigestUtils.md5Digest(InputStream inputStream)
tính toán tiêu hóa MD5 và DigestUtils.md5DigestAsHex(InputStream inputStream)
biểu diễn chuỗi thập lục phân của các phương thức phân loại MD5 mà không đọc toàn bộ tệp vào bộ nhớ.
Một cách tiếp cận đơn giản không có thư viện bên thứ ba sử dụng Java 7
String path = "your complete file path";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
byte[] digest = md.digest();
Nếu bạn cần in mảng byte này. Sử dụng như dưới đây
System.out.println(Arrays.toString(digest));
Nếu bạn cần chuỗi hex trong số này. Sử dụng như dưới đây
String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
System.out.println(digestInHex);
trong đó DatatypeConverter là javax.xml.bind.DatatypeConverter
toUpperCase
?
Gần đây tôi đã phải làm điều này chỉ vì một chuỗi động, MessageDigest
có thể đại diện cho hàm băm theo nhiều cách. Để có được chữ ký của tập tin như bạn sẽ nhận được bằng lệnh md5sum, tôi đã phải làm một cái gì đó như thế này:
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();
}
Điều này rõ ràng không trả lời câu hỏi của bạn về cách thực hiện cụ thể cho một tệp, câu trả lời ở trên xử lý sự yên tĩnh đó. Tôi chỉ mất rất nhiều thời gian để có được số tiền trông giống như hầu hết các ứng dụng hiển thị nó và nghĩ rằng bạn có thể gặp rắc rối tương tự.
.toString(16)
sẽ vứt bỏ số không hàng đầu. String.format("%032x", ...)
có thể tốt hơn.
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());
}
Hoặc bạn có thể biết thêm thông tin http://www.asjava.com/core-java/java-md5-example/
Chúng tôi đã sử dụng mã giống với mã ở trên trong bài viết trước bằng cách sử dụng
...
String signature = new BigInteger(1,md5.digest()).toString(16);
...
Tuy nhiên, coi chừng sử dụng BigInteger.toString()
ở đây, vì nó sẽ cắt bớt các số 0 đứng đầu ... (ví dụ: thử s = "27"
, tổng kiểm tra phải là"02e74f10e0327ad868d138f2b4fdd6f0"
)
Tôi thứ hai gợi ý sử dụng Apache Commons Codec, tôi đã thay thế mã của chúng tôi bằng mã đó.
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
}
}
Phương thức Java rất nhanh và sạch mà không phụ thuộc vào các thư viện bên ngoài:
(Chỉ cần thay MD5 bằng SHA-1, SHA-256, SHA-384 hoặc SHA-512 nếu bạn muốn
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);
}
Một triển khai khác: Triển khai MD5 nhanh trong Java
String hash = MD5.asHex(MD5.getHash(new File(filename)));
MD5.asHex()
trong JDK 1.8.0 242.
Cách môi trường thời gian chạy Java tiêu chuẩn :
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;
}
}
Kết quả là bằng tiện ích linux md5sum.
Đây là một hàm đơn giản bao bọc mã của Sunil để nó lấy Tệp làm tham số. Hàm này không cần bất kỳ thư viện bên ngoài nào, nhưng nó yêu cầu 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);
}
}
Ví dụ đầu ra:
hex=B117DD0C3CBBD009AC4EF65B6D75C97B
Nếu bạn đang sử dụng ANT để xây dựng, việc này rất đơn giản. Thêm phần sau vào tệp build.xml của bạn:
<checksum file="${jarFile}" todir="${toDir}"/>
Trong đó jarFile là JAR mà bạn muốn tạo MD5 và toDir là thư mục bạn muốn đặt tệp MD5.
Quả ổi của Google cung cấp một API mới. Tìm cái dưới đây:
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
Đây là một biến thể tiện dụng sử dụng InputStream.transferTo()
từ Java 9 và OutputStream.nullOutputStream()
từ Java 11. Nó không yêu cầu các thư viện bên ngoài và không cần phải tải toàn bộ tệp vào bộ nhớ.
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()));
}
và
hashFile("SHA-512", Path.of("src", "test", "resources", "some.txt").toFile());
trả lại
"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();
}