Java에서 파일의 MD5 체크섬 가져 오기


510

Java를 사용하여 파일의 MD5 체크섬을 얻으려고합니다. 정말 놀랐지 만 파일의 MD5 체크섬을 얻는 방법을 보여주는 것을 찾을 수 없었습니다.

어떻게 되나요?


아마도 이것이 도움 될 것입니다. 사양을 찾아 볼 수도 있지만 복잡하기 때문에 더 많은 작업이 필요합니다.
waynecolvin

4
최근의 연구에 따르면 "MD5는 암호화 적으로 깨져서 더 이상 사용하기에 부적합한 것으로 간주됩니다". en.wikipedia.org/wiki/MD5
Zakharia Stanley

80
MD5는 더 이상 암호로 안전한 것으로 간주되지 않지만 여전히 파일 일관성을 검증하기에 충분하며 SHA보다 빠릅니다.
jiggy

2
@ZakhariaStanley 이것은 체크섬에 관한 질문입니다.
iPherian

파일에서 MD5 체크섬을 정식으로 사용하면 분산 파일을 적대적으로 교체하지 않아도됩니다. 그것이 안전하지 않은 곳입니다. 그러나 적대적인 익스플로잇이 문제가되지 않는 시나리오에서는 완벽하게 적합합니다.
Keith Tyler

답변:


541

입력 스트림 데코레이터 java.security.DigestInputStream가있어 데이터를 추가로 전달하지 않고 입력 스트림을 정상적으로 사용하면서 다이제스트를 계산할 수 있습니다.

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
이미 바이트로 무언가를하고 있다면 (즉, HTTP 연결에서 읽음) 체크섬을 계산하는 매우 우아한 방법에 동의합니다.
Marc Novakowski

2
@AlPhaba 또는 is로 선언 했습니까 ? 사용한 것처럼 들리므로이 오류가 발생합니다. InputStreamFileInputStreamFileInputStream
erickson

1
@barwnikk Java 8 MethodNotFound에서는 제대로 작동합니다 . 표준 Java에서는 예외가 아닙니다. 아마도 컴파일러 오류에 대해 이야기하고 있습니까? 어쨌든 작동하지 않으면 로컬 구성 문제 또는 다른 코드 문제입니다.
erickson

4
@barwnikk 다시 한 번, 이것이 로컬 구성 문제입니다. 이것은 유효한 Java 7 및 Java 8 코드입니다. 2006 년부터 도구를 사용하고 있다면 적응해야합니다.
erickson

5
@erickson 파일 내용으로 MessageDigest 객체를 업데이트하지 않습니다. Rt? 이 코드는 항상 동일한 다이제스트를 인쇄합니다.
sunil

302

Apache Commons 코덱 라이브러리 에서 DigestUtils 를 사용하십시오 .

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

1
내 안드로이드 코드에서 작동하지 않습니다.이 오류가 발생합니다 ... java.lang.NoSuchMethodError : org.apache.commons.codec.binary.Hex.encodeHexString at org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUtils.java:215)
JPM

@JPM 다운로드하고 commons-codec.jar클래스 경로에 이미 넣었다고 가정 하십니까?
Leif Gruenwoldt

예, 안드로이드 프로젝트에서 내보냈습니다. 코드를 단계별로 볼 수 있으며 클래스는 소스 파일에 있습니다 ... 이상한, 안드로이드 이클립스 문제 일 것입니다.
JPM

1
같은 문제가 있었지만이 코드로 해결되었습니다.`FileInputStream fis = new FileInputStream (new File (filePath)); 바이트 데이터 [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (data); String md5 = String.valueOf (md5Chars);`
Dmitry_L

1
좋은! 새로운 프로젝트의 경우 항상 새로운 의존성을 추가하기 전에 두 번 생각하지만 기존 프로젝트의 경우 라이브러리가 이미 사용 중인지 확인해야합니다. +1
OscarRyz

164

MessageDigest 클래스 사용 하는 Real의 Java-How-to 예제가 있습니다 .

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

70
그렇습니다 ... 11 년 후에도 온라인 상태입니다! :-)
RealHowTo 2010

Real의 Java-How-To 예제는 완벽하게 작동하며 구현이 간단했습니다.
bakoyaro 2016 년

읽기 루프는 약간 어색합니다. read()0을 반환하지 않으며 a do/while는 실제로 적절하지 않습니다.
Lorne의 후작

10
@EJP 적시에 피드백을 보내 주셔서 감사합니다.
Bill the Lizard

바이트 [] 버퍼 = 새로운 바이트 [1024]; 크기를 1024에서 더 최적의 것으로 바꿀 수 있습니까?
Jalpesh

90

com.google.common.hash의 API 제공 :

  • 모든 해시 함수를위한 통합 된 사용자 친화적 API
  • murmur3의 시드 가능한 32 비트 및 128 비트 구현
  • md5 (), sha1 (), sha256 (), sha512 () 어댑터는 한 줄의 코드 만 변경하여 이들 사이를 전환합니다.
  • goodFastHash (int bits), 사용하는 알고리즘에 신경 쓰지 않을 때
  • CombineOrdered / CombineUnorder와 같은 HashCode 인스턴스의 일반 유틸리티

사용자 안내서 ( IO Explained , Hashing Explained )를 읽으십시오 .

사용 사례의 경우 Files.hash()파일의 다이제스트 값을 계산하고 반환합니다.

예를 들어 다이제스트 계산 (MD-1 다이제스트를 얻기 위해 SHA-1을 MD5로 변경)

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

참고 보다 훨씬 빠르다 그래서 사용하십시오 암호로 안전한 체크섬이 필요하지 않은 경우 또한 암호 사용을 위해 무차별 대입하기 쉽기 때문에 암호 등을 저장하는 데 사용해서는 안됩니다 , 또는 대신에.

해시를 사용한 장기 보호의 경우 Merkle 서명 체계 가 보안에 추가되며 유럽위원회가 후원하는 Post Quantum Cryptography Study Group은 양자 컴퓨터 ( ref ) 에 대한 장기 보호를 위해이 암호화를 사용할 것을 권장했습니다 .

참고 다른 것보다 충돌 률이 높습니다.


위에서 언급 한 Files.hash의 어떤 부분이 Files.hash를 다루지 않습니까?
oluies

2
Files.hash()되지 않는 것으로 표시되면, 권장되는 방법은 다음과 같습니다Files.asByteSource(file).hash(Hashing.sha1())
erkfel

1
그리고 2018 년 1 월 기준 Hashing.sha1()으로 더 이상 사용되지 않습니다. Hashing.sha256()대신 이 기능 이 권장됩니다. 출처
MagicLegend

60

외부 라이브러리없이 nio2 (Java 7+) 사용 :

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

결과를 예상 체크섬과 비교하려면

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

@Arash yes 절대적으로-감사합니다. JDK 파일 클래스와 구아바를 섞었습니다.
assylias

에릭슨의보다이 솔루션과 같은 I은 순수한 기능적 스타일의 프로그래밍을 사용하는 선택적 개체로 포장 할 수 있기 때문에
가브리엘 헤르 난 데스

2
큰 파일의 경우 전체 파일을 읽은 다음 청크를 읽지 않고 "소화"하는 대신 다이제스트에 공급하기 때문에 많은 메모리가 사용됩니다.
bernie

39

구아바는 이제 JDK에서 제공되는 다양한 해싱 API보다 훨씬 사용자 친화적 인 새롭고 일관된 해싱 API를 제공합니다. 해싱 설명을 참조하십시오 . 파일의 경우 MD5 합계, CRC32 (버전 14.0 이상) 또는 기타 여러 해시를 쉽게 얻을 수 있습니다.

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

확인. 나는 추가해야했다. Spring과 Apache Commons에 이미 의존하거나 추가 할 계획 인 사람들을위한 한 줄 구현 :

DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))

For Apache Apache Commons Only 옵션 (credit @duleshi) :

DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))

이것이 누군가를 돕기를 바랍니다.


1
그것은이다DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
duleshi

David Onter 공통 기반 솔루션은 전체 파일을 메모리로 읽지 않기 때문에 더 좋습니다.
Fran Marzoa

에 적어도 Spring 5 당신이 DigestUtils.md5Digest(InputStream inputStream)는 MD5 다이제스트 계산하기 위해 DigestUtils.md5DigestAsHex(InputStream inputStream)메모리에 전체 파일을 읽을없이 MD5 다이제스트 방법의 진수 문자열 표현을.
Mike Shauneu

24

Java 7을 사용하는 타사 라이브러리가없는 간단한 접근 방식

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

이 바이트 배열을 인쇄해야하는 경우 아래와 같이 사용

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

이 다이제스트에서 16 진수 문자열이 필요한 경우. 아래와 같이 사용

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

여기서 DatatypeConverter는 javax.xml.bind.DatatypeConverter입니다.


toUpperCase?
EdgeCaseBerg

16 진수 문자열에 대해서만 @edgecaseberg 콘솔에 인쇄하는 동안 좋아 보인다
sunil

toUpperCase () 대신 toLowerCase ()를 사용해야한다는 것을 알았습니다.
Splendor

14

나는 최근에 동적 문자열에 대해이 작업을 수행해야 MessageDigest했으며 여러 가지 방법으로 해시를 나타낼 수 있습니다. md5sum 명령 을 사용하여 파일의 서명을 얻으려면 다음과 같이해야합니다.

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

이것은 분명히 파일에 대해 구체적으로 수행하는 방법에 대한 귀하의 질문에 대답하지는 않지만 위의 대답은 그 조용히 잘 처리합니다. 방금 대부분의 응용 프로그램이 표시하는 것처럼 합계를 얻는 데 많은 시간을 보냈으며 동일한 문제가 발생할 수 있다고 생각했습니다.


서명은 16 진수 형식의 다이제스트입니다. 나도 말했듯이 다른 표현이 작동하지 않는 16 진수 표현이 작동한다는 것을 알았습니다. 이것을 올려 주셔서 감사합니다.
amit

이것은 좋지만 .toString(16)선행 0을 버릴 것입니다. String.format("%032x", ...)더 나을 수 있습니다.
해롤드

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

또는 더 많은 정보를 얻을 수 있습니다 http://www.asjava.com/core-java/java-md5-example/



9

우리는 이전 게시물에서 위의 코드와 유사한 코드를 사용했습니다.

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

그러나 BigInteger.toString()앞에 0을 자르므로 여기에서 사용 하십시오. (예를 들어, try s = "27", checksum이어야 함 "02e74f10e0327ad868d138f2b4fdd6f0")

Apache Commons Codec을 사용하라는 제안을 두 번째로, 우리 자신의 코드를 그 코드로 대체했습니다.


1
와우, 나는 파일이 우리에게 31 16 진수 출력만을 제공하고 md5checksums가 실패한다는 것을 제외하고 MD5가 모든 것에 완벽하게 작동하는 문제를 조사하고있었습니다. 선행 0을 자르는 것은 큰 고통입니다 ... 참고해 주셔서 감사합니다.
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

외부 라이브러리에 의존하지 않는 매우 빠르고 깨끗한 Java 메소드 :

(원하는 경우 MD5를 SHA-1, SHA-256, SHA-384 또는 SHA-512로 간단히 교체하십시오)

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

표준 Java Runtime Environment 방법 :

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

결과는 Linux md5sum 유틸리티와 같습니다.


6

다음은 Sunil의 코드를 감싸서 File을 매개 변수로 사용하는 간단한 함수입니다. 이 함수에는 외부 라이브러리가 필요하지 않지만 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);            
    }


}

출력 예 :

hex=B117DD0C3CBBD009AC4EF65B6D75C97B

3

ANT를 사용하여 빌드하는 경우 이는 매우 간단합니다. build.xml에 다음을 추가하십시오.

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

여기서 jarFile은 MD5를 생성하려는 JAR이고 toDir은 MD5 파일을 배치하려는 디렉토리입니다.

자세한 정보는 여기에 있습니다.


3

구글 구아바는 새로운 API를 제공합니다. 아래에서 하나를 찾으십시오.

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

다음은 InputStream.transferTo()Java 9 및 OutputStream.nullOutputStream()Java 11 을 사용하는 편리한 변형입니다 . 외부 라이브러리가 필요하지 않으며 전체 파일을 메모리에로드 할 필요가 없습니다.

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

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

보고

"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();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.