Chcę użyć Java, aby uzyskać sumę kontrolną MD5 pliku. Byłem naprawdę zaskoczony, ale nie byłem w stanie znaleźć niczego, co pokazuje, jak uzyskać sumę kontrolną MD5 pliku.
Może to pomoże. Możesz także sprawdzić specyfikację, ale zajęłoby to więcej, ponieważ jest to skomplikowane.
waynecolvin,
4
Należy pamiętać, że zgodnie z najnowszymi badaniami „MD5 należy uznać za uszkodzony kryptograficznie i nieodpowiedni do dalszego użycia”. en.wikipedia.org/wiki/MD5
Zakharia Stanley
80
MD5 nie jest już uważany za kryptograficznie bezpieczny, ale nadal wystarcza do sprawdzania spójności plików i jest szybszy niż SHA.
jiggy
2
@ZakhariaStanley To pytanie dotyczy sumy kontrolnej.
iPherian
Kanonicznym zastosowaniem sum kontrolnych MD5 w plikach jest unikanie wrogich zamian plików rozproszonych. Tam jest niepewnie. Ale w scenariuszu, w którym wrogie exploity nie stanowią problemu, jest to całkowicie odpowiednie.
Keith Tyler,
Odpowiedzi:
541
Istnieje dekorator strumienia wejściowego java.security.DigestInputStream, dzięki czemu można obliczyć podsumowanie podczas korzystania ze strumienia wejściowego w normalny sposób, bez konieczności dodatkowego przekazywania danych.
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();
Zgadzam się, bardzo elegancki sposób obliczania sumy kontrolnej w locie, jeśli już robisz coś z bajtami (tj. Odczytujesz je z połączenia HTTP).
Marc Novakowski,
2
@AlPhaba Czy zadeklarowałeś isjako InputStreama FileInputStream? Wygląda na to, że został użyty FileInputStream, co spowodowałoby ten błąd.
erickson,
1
@barwnikk Działa dobrze w Javie 8. MethodNotFoundnie jest wyjątkiem od standardowej Java; może mówisz o błędzie kompilatora? W każdym razie, jeśli to nie działa, oznacza to lokalny problem z konfiguracją lub problem z innym kodem.
erickson
4
@barwnikk Znowu, to jest twój problem z lokalną konfiguracją. Jest to poprawny kod Java 7 i Java 8. Jeśli utkniesz z narzędziami z 2006 roku, będziesz musiał się dostosować.
erickson
5
@erickson Nie aktualizujesz obiektu MessageDigest o zawartość pliku. Rt? Ten kod wydrukuje zawsze ten sam skrót.
Nie działa dla mnie w moim kodzie Android Otrzymuję ten błąd ... java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString at org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUtils.java:215)
JPM
@JPM Zakładasz, że pobrałeś i umieściłeś już commons-codec.jarna ścieżce klasy?
Leif Gruenwoldt
tak tam i wyeksportowałem w moim projekcie Android .. Mogę przejść przez kod, a klasa jest w plikach źródłowych ... dziwne, to musi być problem z Androidem Eclipse.
JPM
1
Miałem ten sam problem, ale został rozwiązany przez ten kod `FileInputStream fis = new FileInputStream (new File (filePath)); bajty danych [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (dane); String md5 = String.valueOf (md5Chars); `
Dmitry_L
1
Miły! W przypadku nowych projektów zawsze zastanawiam się dwa razy przed dodaniem nowej zależności, ale w przypadku istniejącego projektu muszę tylko sprawdzić, czy biblioteka już tam jest, aby z niej skorzystać. +1
Dla twojego przypadku użycia Files.hash()oblicza i zwraca wartość skrótu dla pliku.
Na przykład sha-1 obliczanie skrótu (zmień SHA-1 na MD5, aby uzyskać skrót MD5)
HashCode hc =Files.asByteSource(file).hash(Hashing.sha1());"SHA-1: "+ hc.toString();
Zauważ, że crc32 jest znacznie szybszy niż md5, więc użyj crc32jeśli nie potrzebujesz kryptograficznie bezpiecznej sumy kontrolnej. Zauważ też, żemd5 nie powinny być używane do przechowywania haseł i tym podobnych, ponieważ łatwo jest użyć siły, do użycia haseł bcrypt, scrypt lub sha-256 zamiast.
W celu zapewnienia długoterminowej ochrony za pomocą skrótów program sygnatury Merkle zwiększa bezpieczeństwo, a sponsorowana przez Komisję Europejską grupa analityczna ds. Kryptografii post kwantowej zaleciła stosowanie tej kryptografii w celu długoterminowej ochrony przed komputerami kwantowymi ( zob .).
Zauważ, że crc32 ma wyższy współczynnik kolizji niż inne.
@Arash tak absolutnie - dzięki. Pomieszałem klasę JDK Files i klasę Guava.
assylias
I jakby tego rozwiązania więcej niż Ericksona, ponieważ może być owinięte opcjonalne użycie programowania czystym stylu funkcjonalna
Gabriel Hernandez
2
W przypadku dużego pliku zajmie to dużo pamięci, ponieważ cały plik jest odczytywany, a następnie podawany do podsumowania zamiast odczytywania fragmentów i „trawienia” ich podczas odczytywania.
bernie,
39
Guava udostępnia teraz nowy, spójny interfejs API mieszania, który jest o wiele bardziej przyjazny dla użytkownika niż różne interfejsy API mieszania dostępne w JDK. Zobacz Wyjaśnienie skrótu . W przypadku pliku można łatwo uzyskać sumę MD5, CRC32 (z wersją 14.0+) lub wiele innych skrótów:
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();
Rozwiązanie oparte na wspólnym systemie David Onter jest lepsze, ponieważ nie odczytuje całego pliku do pamięci.
Fran Marzoa,
Przynajmniej Spring 5 musisz DigestUtils.md5Digest(InputStream inputStream)obliczyć skrót MD5 i DigestUtils.md5DigestAsHex(InputStream inputStream)szesnastkową reprezentację ciągu metod skrótu MD5 bez wczytywania całego pliku do pamięci.
Mike Shauneu,
24
Proste podejście bez bibliotek stron trzecich korzystających z Java 7
@edgecaseberg tylko dla szesnastkowego łańcucha wygląda dobrze podczas drukowania go na konsolę
sunil
Odkryłem, że muszę użyć toLowerCase () zamiast toUpperCase ().
Splendor
13
Niedawno musiałem to zrobić tylko dla dynamicznego ciągu, MessageDigestmoże reprezentować skrót na wiele sposobów. Aby uzyskać podpis pliku, tak jak w przypadku polecenia md5sum , musiałem zrobić coś takiego:
To oczywiście nie odpowiada na twoje pytanie, jak to zrobić specjalnie dla pliku, powyższa odpowiedź ładnie radzi sobie z tym spokojem. Spędziłem dużo czasu, aby suma wyglądała tak, jakby wyświetlała ją większość aplikacji, i pomyślałem, że możesz mieć takie same problemy.
Podpis jest skrótem w formacie szesnastkowym. Ja też znalazłem reprezentację szesnastkową do pracy tam, gdzie, jak mówisz, inne reprezentacje nie działają. Dziękuję za postawienie tego.
Uważaj jednak na użycie BigInteger.toString()tutaj, ponieważ spowoduje to obcięcie wiodących zer ... (na przykład spróbuj s = "27", suma kontrolna powinna wynosić"02e74f10e0327ad868d138f2b4fdd6f0" )
Popieram sugestię użycia kodeka Apache Commons, zastąpiłem tym kodem.
Wow, szukałem problemu, w którym rzeczy z MD5 działały idealnie we wszystkim, z wyjątkiem tego, że plik dawał nam tylko 31 cyfr szesnastkowych i nie sprawdzał sum kontrolnych md5. obcinanie wiodących zer to ogromny ból ... Dziękuję za twoją notatkę.
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}}
Oto prosta funkcja, która owija się wokół kodu Sunila, dzięki czemu przyjmuje parametr File jako parametr. Ta funkcja nie wymaga żadnych zewnętrznych bibliotek, ale wymaga 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 guava zapewnia nowy interfejs API. Znajdź ten poniżej:
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
Oto przydatna odmiana, która korzysta InputStream.transferTo()z Java 9 i OutputStream.nullOutputStream()Java 11. Nie wymaga zewnętrznych bibliotek i nie musi ładować całego pliku do pamięci.
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()));}
Odpowiedzi:
Istnieje dekorator strumienia wejściowego
java.security.DigestInputStream
, dzięki czemu można obliczyć podsumowanie podczas korzystania ze strumienia wejściowego w normalny sposób, bez konieczności dodatkowego przekazywania danych.źródło
is
jakoInputStream
aFileInputStream
? Wygląda na to, że został użytyFileInputStream
, co spowodowałoby ten błąd.MethodNotFound
nie jest wyjątkiem od standardowej Java; może mówisz o błędzie kompilatora? W każdym razie, jeśli to nie działa, oznacza to lokalny problem z konfiguracją lub problem z innym kodem.Użyj DigestUtils z biblioteki kodeków Apache Commons :
źródło
commons-codec.jar
na ścieżce klasy?Jest przykład w Javie Real'a dotyczącej korzystania z klasy MessageDigest .
Sprawdź na tej stronie również przykłady użycia CRC32 i SHA-1.
źródło
read()
nie zwróci zera, a ado/while
nie jest naprawdę właściwe.W com.google.common.hash oferty API:
Przeczytaj Podręcznik użytkownika ( wyjaśnienie IO , wyjaśnienie skrótu ).
Dla twojego przypadku użycia
Files.hash()
oblicza i zwraca wartość skrótu dla pliku.Na przykład sha-1 obliczanie skrótu (zmień SHA-1 na MD5, aby uzyskać skrót MD5)
Zauważ, że crc32 jest znacznie szybszy niż md5, więc użyj crc32jeśli nie potrzebujesz kryptograficznie bezpiecznej sumy kontrolnej. Zauważ też, żemd5 nie powinny być używane do przechowywania haseł i tym podobnych, ponieważ łatwo jest użyć siły, do użycia haseł bcrypt, scrypt lub sha-256 zamiast.
W celu zapewnienia długoterminowej ochrony za pomocą skrótów program sygnatury Merkle zwiększa bezpieczeństwo, a sponsorowana przez Komisję Europejską grupa analityczna ds. Kryptografii post kwantowej zaleciła stosowanie tej kryptografii w celu długoterminowej ochrony przed komputerami kwantowymi ( zob .).
Zauważ, że crc32 ma wyższy współczynnik kolizji niż inne.
źródło
Files.hash()
Jest oznaczony jako przestarzałe, zalecanym sposobem jest:Files.asByteSource(file).hash(Hashing.sha1())
Hashing.sha1()
Jest oznaczony jako przestarzały.Hashing.sha256()
Zamiast tego zalecana jest funkcja . źródłoKorzystanie z nio2 (Java 7+) i bez bibliotek zewnętrznych:
Aby porównać wynik z oczekiwaną sumą kontrolną:
źródło
Guava udostępnia teraz nowy, spójny interfejs API mieszania, który jest o wiele bardziej przyjazny dla użytkownika niż różne interfejsy API mieszania dostępne w JDK. Zobacz Wyjaśnienie skrótu . W przypadku pliku można łatwo uzyskać sumę MD5, CRC32 (z wersją 14.0+) lub wiele innych skrótów:
źródło
Ok. Musiałem dodać. Jednowierszowa implementacja dla tych, którzy mają już zależność Spring i Apache Commons lub planują ją dodać:
Dla i tylko wspólne opcje Apache (kredyt @duleshi):
Mam nadzieję, że to komuś pomoże.
źródło
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spring 5
musiszDigestUtils.md5Digest(InputStream inputStream)
obliczyć skrót MD5 iDigestUtils.md5DigestAsHex(InputStream inputStream)
szesnastkową reprezentację ciągu metod skrótu MD5 bez wczytywania całego pliku do pamięci.Proste podejście bez bibliotek stron trzecich korzystających z Java 7
Jeśli musisz wydrukować tę tablicę bajtów. Użyj jak poniżej
Jeśli potrzebujesz ciągu szesnastkowego z tego skrótu. Użyj jak poniżej
gdzie DatatypeConverter to javax.xml.bind.DatatypeConverter
źródło
toUpperCase
?Niedawno musiałem to zrobić tylko dla dynamicznego ciągu,
MessageDigest
może reprezentować skrót na wiele sposobów. Aby uzyskać podpis pliku, tak jak w przypadku polecenia md5sum , musiałem zrobić coś takiego:To oczywiście nie odpowiada na twoje pytanie, jak to zrobić specjalnie dla pliku, powyższa odpowiedź ładnie radzi sobie z tym spokojem. Spędziłem dużo czasu, aby suma wyglądała tak, jakby wyświetlała ją większość aplikacji, i pomyślałem, że możesz mieć takie same problemy.
źródło
Lub możesz uzyskać więcej informacji http://www.asjava.com/core-java/java-md5-example/
źródło
źródło
Używaliśmy kodu, który przypomina kod powyżej w poprzednim poście przy użyciu
Uważaj jednak na użycie
BigInteger.toString()
tutaj, ponieważ spowoduje to obcięcie wiodących zer ... (na przykład spróbujs = "27"
, suma kontrolna powinna wynosić"02e74f10e0327ad868d138f2b4fdd6f0"
)Popieram sugestię użycia kodeka Apache Commons, zastąpiłem tym kodem.
źródło
źródło
Bardzo szybka i czysta metoda Java, która nie polega na bibliotekach zewnętrznych:
(Po prostu zamień MD5 na SHA-1, SHA-256, SHA-384 lub SHA-512, jeśli chcesz)
źródło
Kolejna implementacja: szybka implementacja MD5 w Javie
źródło
MD5.asHex()
w JDK 1.8.0 242.Standardowy sposób Java Runtime Environment :
Wynik jest równy narzędziu Linux md5sum.
źródło
Oto prosta funkcja, która owija się wokół kodu Sunila, dzięki czemu przyjmuje parametr File jako parametr. Ta funkcja nie wymaga żadnych zewnętrznych bibliotek, ale wymaga Java 7.
Przykładowe dane wyjściowe:
źródło
Jeśli używasz ANT do budowania, jest to bardzo proste. Dodaj następujące elementy do pliku build.xml:
Gdzie jarFile to plik JAR, dla którego chcesz wygenerować MD5, a toDir to katalog, w którym chcesz umieścić plik MD5.
Więcej informacji tutaj.
źródło
Google guava zapewnia nowy interfejs API. Znajdź ten poniżej:
źródło
Oto przydatna odmiana, która korzysta
InputStream.transferTo()
z Java 9 iOutputStream.nullOutputStream()
Java 11. Nie wymaga zewnętrznych bibliotek i nie musi ładować całego pliku do pamięci.i
zwroty
źródło
źródło