Simultaneamente calcular vários resumos (md5, sha256)?

23

Supondo que a E / S do disco e a RAM livre sejam um gargalo (embora o tempo de CPU não seja a limitação), existe uma ferramenta que possa calcular vários resumos de mensagens de uma só vez?

Estou particularmente interessado em calcular os arquivos MD-5 e SHA-256 de arquivos grandes (tamanho em gigabytes), preferencialmente em paralelo. Eu tentei openssl dgst -sha256 -md5 , mas ele calcula apenas o hash usando um algoritmo.

Pseudo-código para o comportamento esperado:

for each block:
    for each algorithm:
        hash_state[algorithm].update(block)
for each algorithm:
    print algorithm, hash_state[algorithm].final_hash()
    
por Lekensteyn 23.10.2014 / 12:00

6 respostas

26

Confira pee (" tee standard input to pipes ") de moreutils . Isso é basicamente equivalente ao comando tee do Marco, mas é um pouco mais simples de digitar.

$ echo foo | pee md5sum sha256sum
d3b07384d113edec49eaa6238ad5ff00  -
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
$ pee md5sum sha256sum <foo.iso
f109ffd6612e36e0fc1597eda65e9cf0  -
469a38cb785f8d47a0f85f968feff0be1d6f9398e353496ff7aa9055725bc63e  -
    
por 23.10.2014 / 16:12
10

Você pode usar um loop for para percorrer os arquivos individuais e usar tee combinado com a substituição de processos (trabalha em Bash e Zsh entre outros) para tubo para diferentes checksummers.

Exemplo:

for file in *.mkv; do
  tee < "$file" >(sha256sum) | md5sum
done

Você também pode usar mais de dois verificadores de verificação:

for file in *.mkv; do
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
done

Isso tem a desvantagem de os verificadores de verificação não saberem o nome do arquivo,   porque é passado como entrada padrão. Se isso não for aceitável, você tem que   emitem os nomes dos arquivos manualmente. Exemplo completo:

for file in *.mkv; do
  echo "$file"
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
  echo
done > hashfilelist
    
por 23.10.2014 / 15:12
6

É uma pena que o utilitário openssl não aceite vários comandos de resumo; Eu acho que executar o mesmo comando em vários arquivos é um padrão de uso mais comum. FWIW, a versão do utilitário openssl no meu sistema (Mepis 11), só tem comandos para sha e sha1, não para qualquer outra das variantes sha. Mas eu tenho um programa chamado sha256sum, assim como md5sum.

Aqui está um programa Python simples, dual_hash.py, que faz o que você quer. Um tamanho de bloco de 64k parece ser ideal para minha máquina (Intel Pentium 4 2.00GHz com 2G de RAM), YMMV. Para arquivos pequenos, sua velocidade é aproximadamente a mesma que a execução de md5sum e sha256sum em sucessão. Mas para arquivos maiores é significativamente mais rápido. Por exemplo, em um arquivo de bytes 1967063040 (uma imagem de disco de um cartão SD cheio de arquivos mp3), md5sum + sha256sum leva cerca de 1m44.9s, dual_hash.py leva 1m0.312s.

dual_hash.py

#! /usr/bin/env python

''' Calculate MD5 and SHA-256 digests of a file simultaneously

    Written by PM 2Ring 2014.10.23
'''

import sys
import hashlib

def digests(fname, blocksize):
    md5 = hashlib.md5()
    sha = hashlib.sha256()
    with open(fname, 'rb') as f:
        while True:
            block = f.read(blocksize)
            if not block:
                break
            md5.update(block)
            sha.update(block)

    print("md5: %s" % md5.hexdigest())
    print("sha256: %s" % sha.hexdigest())

def main(*argv):
    blocksize = 1<<16 # 64kB
    if len(argv) < 2:
        print("No filename given!\n")
        print("Calculate md5 and sha-256 message digests of a file.")
        print("Usage:\npython %s filename [blocksize]\n" % sys.argv[0])
        print("Default blocksize=%d" % blocksize)
        return 1

    fname = argv[1]

    if len(argv) > 2:
        blocksize = int(sys.argv[2])

    print("Calculating MD5 and SHA-256 digests of %r using a blocksize of %d" % (fname, blocksize))
    digests(fname, blocksize)

if __name__ == '__main__':
    sys.exit(main(*sys.argv))

Suponho que uma versão C / C ++ deste programa seria um pouco mais rápida, mas não muito, já que a maior parte do trabalho está sendo feita pelo módulo hashlib, que é escrito em C (ou C ++). E como você observou acima, o gargalo para arquivos grandes é a velocidade de E / S.

    
por 23.10.2014 / 13:36
5

Você sempre pode usar algo como paralelo GNU :

echo "/path/to/file" | parallel 'md5sum {} & sha256sum {}'

Como alternativa, basta executar um dos dois em segundo plano:

md5sum /path/to/file & sha256sum /path/to/file

Ou salve a saída em arquivos diferentes e execute várias tarefas em segundo plano:

for file in *; do
    md5sum "$file" > "$file".md5 &
    sha256sum "$file" > "$file".sha &
done

Isso executará quantas instâncias de md5sum e sha256sum , à medida que você tiver arquivos, e todos serão executados em paralelo, salvando a saída deles nos nomes de arquivos correspondentes. Cuidado, porém, isso pode ficar pesado se você tiver muitos arquivos.

    
por 23.10.2014 / 13:59
3

Por curiosidade, se um script Python multi-threaded reduziria o tempo de execução, criei este digest.py script que usa threading.Thread , threading.Queue e hashlib para calcular os hashes para vários arquivos.

A implementação multi-thread do Python é de fato um pouco mais rápida do que usar pee com o coreutils. Java, por outro lado é ... meh. Os resultados estão disponíveis em esta mensagem de confirmação :

For comparison, for a file of 2.3 GiB (min/avg/max/sd secs for n=10):

  • pee sha256sum md5sum < file: 16.5/16.9/17.4/.305
  • python3 digest.py -sha256 -md5 < file: 13.7/15.0/18.7/1.77
  • python2 digest.py -sha256 -md5 < file: 13.7/15.9/18.7/1.64
  • jacksum -a sha256+md5 -F '#CHECKSUM{i} #FILENAME': 32.7/37.1/50/6.91

A saída hash é compatível com a saída produzida por coreutils. Como o comprimento depende do algoritmo de hashing, essa ferramenta não imprime. Uso (para comparação, pee também foi adicionado):

$ ./digest.py -sha256 -md5 digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  digest.py
b575edf6387888a68c93bf89291f611c  digest.py
$ ./digest.py -sha256 -md5 <digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  -
b575edf6387888a68c93bf89291f611c  -
$ pee sha256sum md5sum <digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  -
b575edf6387888a68c93bf89291f611c  -
    
por 24.10.2014 / 13:07
1

O Jacksum é um utilitário gratuito e independente de plataforma para calcular e verificar somas de verificação, CRCs e hashes (resumos de mensagens), bem como registros de data e hora de arquivos. (extraído de página de manual do jacksum )

É grande arquivo ciente, ele pode processar arquivos de até 8 Exabytes (= 8.000.000.000 Gigabytes), pressupõe o seu sistema operacional, respectivamente, o sistema de arquivos é grande arquivo ciente também. (extraído de link )

Exemplo de uso:

jacksum -a md5+sha256 -F "#ALGONAME{i} (#FILENAME) = #CHECKSUM{i}" jacksum-testfile

Exemplo de saída:

md5 (jacksum-testfile) = d41d8cd98f00b204e9800998ecf8427e
sha256 (jacksum-testfile) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

No Ubuntu, execute o comando apt-get install jacksum para obtê-lo.

Alternativamente, os códigos fonte estão disponíveis em

por 24.10.2014 / 10:28