Obtendo a soma de verificação MD5 de um arquivo em Java
510
Eu estou olhando para usar Java para obter a soma de verificação MD5 de um arquivo. Fiquei realmente surpreso, mas não consegui encontrar nada que mostre como obter a soma de verificação MD5 de um arquivo.
Talvez isso ajude. Você também pode procurar as especificações, mas isso exigiria mais, pois é complicado.
waynecolvin
4
Lembre-se de que, de acordo com a pesquisa recente, "o MD5 deve ser considerado criptograficamente quebrado e inadequado para uso posterior". en.wikipedia.org/wiki/MD5
Zakharia Stanley
80
O MD5 não é mais considerado criptograficamente seguro, mas ainda é suficiente para validar a consistência do arquivo e é mais rápido que o SHA.
Jiggy #
2
@ZakhariaStanley Esta é uma pergunta sobre soma de verificação.
iPherian
O uso canônico das somas de verificação MD5 nos arquivos é evitar substituições hostis de arquivos distribuídos. É aí que é inseguro. Mas em um cenário em que explorações hostis não são uma preocupação, é perfeitamente adequado.
Keith Tyler
Respostas:
541
Há um decorador de fluxo de entrada java.security.DigestInputStream, para que você possa calcular o resumo enquanto usa o fluxo de entrada como faria normalmente, em vez de precisar fazer uma passagem extra pelos dados.
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();
Concordo, maneira muito elegante de calcular a soma de verificação em tempo real, se você já estiver fazendo algo com os bytes (ou seja, lendo-os em uma conexão HTTP).
Marc Novakowski
2
@AlPhaba Você declarou o iscomo um InputStreamou um FileInputStream? Parece que você usou FileInputStream, o que causaria esse erro.
Erickson
1
@barwnikk Funciona bem no Java 8. MethodNotFoundnão é uma exceção do Java padrão; talvez você esteja falando de um erro do compilador? De qualquer forma, se não funcionar, é um problema de configuração local ou outro código.
21714
4
@barwnikk Novamente, esse é o seu problema de configuração local. Este é um código Java 7 e Java 8 válido. Se você está preso às ferramentas de 2006, terá que se adaptar.
21714
5
@erickson Você não está atualizando o objeto MessageDigest com o conteúdo do arquivo. Rt? Esse código sempre imprimirá o mesmo resumo.
Não funciona para mim no meu código do Android. Eu recebo esse erro ... java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString em org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUtils.java:215)
JPM
@JPM Suponha que você baixou e colocou o commons-codec.jarcaminho de classe já?
Leif Gruenwoldt
sim lá e eu exportado no meu projeto android .. Eu posso percorrer o código e a classe está lá nos arquivos de origem ... estranho, deve haver algum problema no Android Eclipse.
JPM
1
Eu tive o mesmo problema, mas foi corrigido por este código `FileInputStream fis = new FileInputStream (new File (filePath)); dados de bytes [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (dados); String md5 = String.valueOf (md5Chars); `
Dmitry_L
1
Agradável! Para novos projetos, eu sempre penso duas vezes antes de adicionar uma nova dependência, mas para o projeto existente, basta verificar se a biblioteca já existe para usá-la. 1
Para o seu caso de uso, Files.hash()calcula e retorna o valor de resumo de um arquivo.
Por exemplo, um sha-1 cálculo de resumo (altere SHA-1 para MD5 para obter o resumo MD5)
HashCode hc =Files.asByteSource(file).hash(Hashing.sha1());"SHA-1: "+ hc.toString();
Observe que crc32 é muito mais rápido que md5então use crc32se você não precisar de uma soma de verificação criptograficamente segura. Note também quemd5 não deve ser usado para armazenar senhas e similares, uma vez que é muito fácil usar força bruta, para usar senhas bcrypt, escrever ou sha-256 em vez de.
Para proteção de longo prazo com hashes, um esquema de assinatura Merkle aumenta a segurança e o The Post Quantum Cryptography Study Group patrocinado pela Comissão Europeia recomendou o uso dessa criptografia para proteção de longo prazo contra computadores quânticos ( ref ).
Observe que crc32 tem uma taxa de colisão mais alta que as outras.
@ Arash sim absolutamente - obrigado. Eu misturei a classe JDK Files e a goiaba.
Assylias 23/05
I como esta solução mais de erickson de uma vez que pode ser embrulhado com Opcionais de usar estilo de programação funcional pura
Gabriel Hernandez
2
Para um arquivo grande, isso consumirá muita memória, pois o arquivo inteiro é lido e, em seguida, alimentado para o resumo, em vez de ler os pedaços e "digeri-los" à medida que são lidos.
bernie
39
O Guava agora oferece uma nova API de hash consistente e muito mais amigável ao usuário do que as várias APIs de hash fornecidas no JDK. Consulte Hashing Explained . Para um arquivo, você pode obter facilmente a soma MD5, CRC32 (com versão 14.0+) ou muitos outros hashes:
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();
A solução baseada em David Onter é melhor porque não lê um arquivo inteiro na memória.
precisa
Pelo menos para Spring 5 você ter DigestUtils.md5Digest(InputStream inputStream)que calcular o resumo MD5 e DigestUtils.md5DigestAsHex(InputStream inputStream)a representação de sequência hexadecimal dos métodos de resumo MD5 sem ler um arquivo inteiro na memória.
Mike Shauneu
24
Uma abordagem simples sem bibliotecas de terceiros usando Java 7
@edgecaseberg apenas para a cadeia hex olhar bom durante a impressão de que a consola
Sunil
Descobri que precisava usar toLowerCase () em vez de toUpperCase ().
Splendour
14
Recentemente, tive que fazer isso por apenas uma sequência dinâmica, MessageDigestpode representar o hash de várias maneiras. Para obter a assinatura do arquivo como você obteria com o comando md5sum , tive que fazer algo parecido com isto:
Obviamente, isso não responde à sua pergunta sobre como fazê-lo especificamente para um arquivo, a resposta acima lida muito bem com isso. Passei muito tempo fazendo com que a soma parecesse com a maioria dos aplicativos e achei que você poderia ter o mesmo problema.
A assinatura é o resumo em formato hexadecimal. Também achei que a representação hexadecimal funcionava onde, como você diz, outras representações não funcionam. Obrigado por colocar isso.
Amit
Isso é bom, mas .toString(16)jogará fora os zeros à esquerda. String.format("%032x", ...)talvez melhor.
No entanto, tenha cuidado ao usar BigInteger.toString()aqui, pois truncará os zeros à esquerda ... (por exemplo, tente s = "27", a soma de verificação deve ser "02e74f10e0327ad868d138f2b4fdd6f0")
Segundo a sugestão de usar o Apache Commons Codec, substituí nosso código por isso.
Uau, eu estava investigando um problema em que o material MD5 estava funcionando perfeitamente para tudo, exceto que um arquivo estava nos fornecendo apenas uma saída de 31 dígitos hexadecimais e estava com falha nos md5checksums. esse truncamento dos 0s principais é uma dor enorme ... Obrigado pela sua observação.
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}}
Aqui está uma função simples que envolve o código do Sunil para que ele use um arquivo como parâmetro. A função não precisa de bibliotecas externas, mas requer o 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);}}
A goiaba do Google fornece uma nova API. Encontre o abaixo:
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
Aqui está uma variação prática que utiliza o InputStream.transferTo()Java 9 e o OutputStream.nullOutputStream()Java 11. Ele não requer bibliotecas externas e não precisa carregar o arquivo inteiro na memória.
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()));}
Respostas:
Há um decorador de fluxo de entrada
java.security.DigestInputStream
, para que você possa calcular o resumo enquanto usa o fluxo de entrada como faria normalmente, em vez de precisar fazer uma passagem extra pelos dados.fonte
is
como umInputStream
ou umFileInputStream
? Parece que você usouFileInputStream
, o que causaria esse erro.MethodNotFound
não é uma exceção do Java padrão; talvez você esteja falando de um erro do compilador? De qualquer forma, se não funcionar, é um problema de configuração local ou outro código.Use DigestUtils da biblioteca de códigos Apache Commons :
fonte
commons-codec.jar
caminho de classe já?Há um exemplo no Java-How-to do Real, usando a classe MessageDigest .
Verifique essa página para ver exemplos usando CRC32 e SHA-1 também.
fonte
read()
não retornará zero e ado/while
não é realmente apropriado.A API com.google.common.hash oferece:
Leia o Guia do Usuário ( IO Explained , Hashing Explained ).
Para o seu caso de uso,
Files.hash()
calcula e retorna o valor de resumo de um arquivo.Por exemplo, um sha-1 cálculo de resumo (altere SHA-1 para MD5 para obter o resumo MD5)
Observe que crc32 é muito mais rápido que md5então use crc32se você não precisar de uma soma de verificação criptograficamente segura. Note também quemd5 não deve ser usado para armazenar senhas e similares, uma vez que é muito fácil usar força bruta, para usar senhas bcrypt, escrever ou sha-256 em vez de.
Para proteção de longo prazo com hashes, um esquema de assinatura Merkle aumenta a segurança e o The Post Quantum Cryptography Study Group patrocinado pela Comissão Europeia recomendou o uso dessa criptografia para proteção de longo prazo contra computadores quânticos ( ref ).
Observe que crc32 tem uma taxa de colisão mais alta que as outras.
fonte
Files.hash()
é marcado como obsoleto, a maneira recomendada é:Files.asByteSource(file).hash(Hashing.sha1())
Hashing.sha1()
está marcado como obsoleto. A funçãoHashing.sha256()
é recomendada. fonteUsando o nio2 (Java 7+) e nenhuma biblioteca externa:
Para comparar o resultado com uma soma de verificação esperada:
fonte
O Guava agora oferece uma nova API de hash consistente e muito mais amigável ao usuário do que as várias APIs de hash fornecidas no JDK. Consulte Hashing Explained . Para um arquivo, você pode obter facilmente a soma MD5, CRC32 (com versão 14.0+) ou muitos outros hashes:
fonte
Está bem. Eu tive que adicionar. Implementação de uma linha para aqueles que já têm dependência do Spring e Apache Commons ou planejam adicioná-lo:
Opção apenas para e Apache commons (credit @duleshi):
Espero que isso ajude alguém.
fonte
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Spring 5
você terDigestUtils.md5Digest(InputStream inputStream)
que calcular o resumo MD5 eDigestUtils.md5DigestAsHex(InputStream inputStream)
a representação de sequência hexadecimal dos métodos de resumo MD5 sem ler um arquivo inteiro na memória.Uma abordagem simples sem bibliotecas de terceiros usando Java 7
Se você precisar imprimir essa matriz de bytes. Use como abaixo
Se você precisar de uma sequência hexadecimal desse resumo. Use como abaixo
em que DatatypeConverter é javax.xml.bind.DatatypeConverter
fonte
toUpperCase
?Recentemente, tive que fazer isso por apenas uma sequência dinâmica,
MessageDigest
pode representar o hash de várias maneiras. Para obter a assinatura do arquivo como você obteria com o comando md5sum , tive que fazer algo parecido com isto:Obviamente, isso não responde à sua pergunta sobre como fazê-lo especificamente para um arquivo, a resposta acima lida muito bem com isso. Passei muito tempo fazendo com que a soma parecesse com a maioria dos aplicativos e achei que você poderia ter o mesmo problema.
fonte
.toString(16)
jogará fora os zeros à esquerda.String.format("%032x", ...)
talvez melhor.Ou você pode obter mais informações http://www.asjava.com/core-java/java-md5-example/
fonte
fonte
Estávamos usando um código semelhante ao código acima em uma postagem anterior usando
No entanto, tenha cuidado ao usar
BigInteger.toString()
aqui, pois truncará os zeros à esquerda ... (por exemplo, tentes = "27"
, a soma de verificação deve ser"02e74f10e0327ad868d138f2b4fdd6f0"
)Segundo a sugestão de usar o Apache Commons Codec, substituí nosso código por isso.
fonte
fonte
Método Java muito rápido e limpo, que não depende de bibliotecas externas:
(Simplesmente substitua o MD5 por SHA-1, SHA-256, SHA-384 ou SHA-512, se desejar)
fonte
Outra implementação: Implementação rápida do MD5 em Java
fonte
MD5.asHex()
no JDK 1.8.0 242.Maneira padrão do Java Runtime Environment :
O resultado é igual ao utilitário linux md5sum.
fonte
Aqui está uma função simples que envolve o código do Sunil para que ele use um arquivo como parâmetro. A função não precisa de bibliotecas externas, mas requer o Java 7.
Exemplo de saída:
fonte
Se você estiver usando o ANT para criar, isso é simples. Adicione o seguinte ao seu build.xml:
Onde jarFile é o JAR no qual você deseja gerar o MD5 e toDir é o diretório no qual você deseja colocar o arquivo MD5.
Mais informações aqui.
fonte
A goiaba do Google fornece uma nova API. Encontre o abaixo:
fonte
Aqui está uma variação prática que utiliza o
InputStream.transferTo()
Java 9 e oOutputStream.nullOutputStream()
Java 11. Ele não requer bibliotecas externas e não precisa carregar o arquivo inteiro na memória.e
retorna
fonte
fonte