Получение контрольной суммы MD5 файла в Java

StackOverflow https://stackoverflow.com/questions/304268

  •  08-07-2019
  •  | 
  •  

Вопрос

Я хочу использовать Java для получения контрольной суммы MD5 файла.Я был очень удивлен, но мне не удалось найти ничего, что объясняло бы, как получить контрольную сумму MD5 файла.

Как это делается?

Это было полезно?

Решение

Существует декоратор входного потока, 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();

Другие советы

Используйте DigestUtils из библиотеки Apache Commons Codec :

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

Есть пример на Java-How-to Real с использованием класс MessageDigest .

Посмотрите на этой странице примеры использования 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();
       }
   }
}

Тем com.google.common.hash API предлагает:

  • Единый удобный API для всех хеш-функций.
  • Заполняемые 32- и 128-битные реализации murmur3
  • Адаптеры md5(), sha1(), sha256(), sha512() меняют всего одну строку кода для переключения между ними и бормочут.
  • GoodFastHash(int bits), если вам не важно, какой алгоритм вы используете.
  • Общие утилиты для экземпляров HashCode, такие как mergeOrdered/comboneUnordered.

Прочтите руководство пользователя (Объяснение ввода-вывода, Объяснение хеширования).

Для вашего случая использования Files.hash() вычисляет и возвращает значение дайджеста для файла.

Например расчет дайджеста (измените SHA-1 на MD5, чтобы получить дайджест MD5)

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

Обратите внимание, что намного быстрее, чем , поэтому используйте если вам не нужна криптографически безопасная контрольная сумма.Обратите внимание также, что не следует использовать для хранения паролей и т.п., поскольку их легко подобрать методом грубой силы, для паролей используйте , или вместо.

Для долгосрочной защиты с помощью хешей Схема подписи Меркла повышает безопасность, и Исследовательская группа по постквантовой криптографии, спонсируемая Европейской комиссией, рекомендовала использовать эту криптографию для долгосрочной защиты от квантовых компьютеров (ссылка).

Обратите внимание, что имеет более высокий уровень столкновений, чем другие.

Использование 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");

Guava теперь предоставляет новый согласованный API-интерфейс хэширования, который намного удобнее для пользователя, чем различные хэши. API предоставлены в JDK. См. объяснение хэширования . Для файла вы можете легко получить сумму 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();

Хорошо.Мне пришлось добавить.Однострочная реализация для тех, у кого уже есть зависимость от Spring и Apache Commons или кто планирует ее добавить:

DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))

Только для общего доступа Apache (кредит @duleshi):

DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))

Надеюсь, это кому-то поможет.

Простой подход без сторонних библиотек, использующих 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));

Если вам нужна шестнадцатеричная строка из этого дайджеста. Используйте как ниже

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

где DatatypeConverter - это javax.xml.bind.DatatypeConverter

Недавно я должен был сделать это только для динамической строки, 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();
}

Это, очевидно, не отвечает на ваш вопрос о том, как сделать это специально для файла, вышеупомянутый ответ прекрасно справляется с этой задачей. Я просто потратил много времени на то, чтобы сумма выглядела так, как показывает большинство приложений, и подумал, что вы можете столкнуться с той же проблемой.

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/

Мы использовали код, похожий на код, приведенный выше в предыдущем посте с использованием

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

Однако, следите за использованием BigInteger.toString () здесь, так как оно усекает ведущие нули ... (например, попробуйте s = " 27 " , контрольная сумма должна быть "02e74f10e0327ad868d138f2b4fdd6f0 " )

Я поддержал предложение использовать кодек Apache Commons, я заменил наш собственный код на него.

Очень быстро & amp; чистый 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);
}
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
   }
}
String checksum = DigestUtils.md5Hex(new FileInputStream(filePath));

Еще одна реализация: Быстрая реализация MD5 в Java

String hash = MD5.asHex(MD5.getHash(new File(filename)));

Стандартный способ среды выполнения Java :

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.

Вот простая функция, которая оборачивает код 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

Если вы используете ANT для сборки, это очень просто. Добавьте следующее в свой build.xml:

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

Где jarFile - это JAR, для которого вы хотите сгенерировать MD5, а toDir - это каталог, куда вы хотите поместить файл MD5.

Подробнее здесь.

Google guava предоставляет новый 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
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();
}

Вот удобный вариант, в котором используется InputStream.transferTo() из Java 9 и OutputStream.nullOutputStream() из Явы 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"
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top