Одновременно рассчитать несколько дайджестов (md5, sha256)?

25

В предположении, что дисковый ввод-вывод и свободная оперативная память являются узким местом (хотя процессорное время не является ограничением), существует ли инструмент, который может рассчитывать несколько дайджестов сообщений одновременно?

Меня особенно интересует вычисление дайджестов больших файлов MD-5 и SHA-256 (размер в гигабайтах), предпочтительно параллельно. Я пытался openssl dgst -sha256 -md5, но он вычисляет только хэш, используя один алгоритм.

Псевдокод для ожидаемого поведения:

for each block:
    for each algorithm:
        hash_state[algorithm].update(block)
for each algorithm:
    print algorithm, hash_state[algorithm].final_hash()
Lekensteyn
источник
Вы можете просто запустить один экземпляр в фоновом режиме, тогда оба хэша будут работать параллельно:for i in file1 file2 …; do sha256 "$i"& md5sum "$i"; done
Marco
2
@Marco Проблема этого подхода заключается в том, что одна команда может быть быстрее другой, что приводит к тому, что дисковый кэш очищается и пополняется позже теми же данными.
Лекенштейн
1
Если вас беспокоит дисковый кеш, вы можете прочитать в файле только один раз: for i in file1 file2 …; do tee < "$i" >(sha256sum) | md5sum ; doneЗатем вам нужно добавить дополнительный код, чтобы пометить имя файла, потому что оно отправляется как стандартный ввод в md5sumи sha256sum.
Марко

Ответы:

28

Проверить pee(" tee standard input to pipes") из moreutils. Это в основном эквивалентно teeкоманде Марко , но немного проще для ввода.

$ echo foo | pee md5sum sha256sum
d3b07384d113edec49eaa6238ad5ff00  -
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
$ pee md5sum sha256sum <foo.iso
f109ffd6612e36e0fc1597eda65e9cf0  -
469a38cb785f8d47a0f85f968feff0be1d6f9398e353496ff7aa9055725bc63e  -
Мэтт Нордхофф
источник
Хорошая команда! У меня уже установлен этот очень полезный пакет, я не знал об этой утилите с забавным названием.
Лекенштейн
1
peeимеет лучший интерфейс, сравнение времени с другими инструментами можно найти в этом посте, который также демонстрирует многопоточный инструмент Python.
Лекенштейн
К сожалению, moreutilsконфликтует с GNU parallelмоей системой Debian ... хотя, приятно знать, что есть такой инструмент.
Лиори
@Lekensteyn: я получаю конфликт на уровне пакетов (то есть. aptitudeНе позволяет мне иметь оба пакета одновременно).
Лиори
@liori Очень жаль, что Debian реализовал это таким образом, возможно, стоит сообщить об ошибке. На Arch Linux есть moreutils-parallelимя, чтобы избежать конфликта.
Лекенштейн
10

Вы можете использовать forцикл для зацикливания отдельных файлов, а затем использовать в tee сочетании с подстановкой процессов (работает в Bash и Zsh среди других) для передачи к различным контрольным суммам.

Пример:

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

Вы также можете использовать более двух контрольных сумм:

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

Это имеет тот недостаток, что контрольные суммы не знают имя файла, потому что оно передается как стандартный ввод. Если это неприемлемо, вы должны указать имена файлов вручную. Полный пример:

for file in *.mkv; do
  echo "$file"
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
  echo
done > hashfilelist
Marco
источник
1
Чтобы сделать вывод совместимым с *sumсемейством инструментов, вместо этого можно использовать это выражение sed: sed "s;-\$;${file//;/\\;};(замените конечный символ -именем файла, но убедитесь, что имя файла правильно экранировано).
Лекенштейн
AFAICS, это работает только в zsh. В ksh93 и bash вывод sha256sum идет в md5sum. Вы хотите: { tee < "$file" >(sha256sum >&3) | md5sum; } 3>&1. Обратитесь к unix.stackexchange.com/q/153896/22565 для решения обратной проблемы.
Стефан Шазелас
6

Жаль, что утилита openssl не принимает несколько команд дайджеста; Я предполагаю, что выполнение одной и той же команды для нескольких файлов - более распространенный способ использования. FWIW, версия утилиты openssl в моей системе (Mepis 11) имеет только команды для sha и sha1, но не какие-либо другие варианты sha. Но у меня есть программа sha256sum, а также md5sum.

Вот простая программа на Python, dual_hash.py, которая делает то, что вы хотите. Размер блока в 64 Кб, по-видимому, является оптимальным для моей машины (Intel Pentium 4 2,00 ГГц с 2 ГБ оперативной памяти), YMMV. Для небольших файлов его скорость примерно такая же, как при последовательном запуске md5sum и sha256sum. Но для больших файлов это значительно быстрее. Например, для файла размером 1967063040 байт (образ диска с SD-картой, полной файлов mp3), md5sum + sha256sum занимает около 1m44,9 с, dual_hash.py занимает 1 м 0,332 с.

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))

Я полагаю , версия С / С ++ этой программы будет немного быстрее, но не так много, так как большая часть работы делается модулем hashlib, который будет написан на C (или C ++). И, как вы заметили выше, узким местом для больших файлов является скорость ввода-вывода.

PM 2Ring
источник
Для файла 2.3G, эта версия была уже сопоставимая скорость по сравнению с md5sumи в sha256sumсочетании (4.7s + 14.2s против 18.7s для этого Python скрипта, файл в кэше, 33.6s для холодного запуска). 64 КБ против 1 МБ не изменили ситуацию. С прокомментированным кодом 5,1 с было потрачено на md5 (n = 3), 14,6 с на sha1 (n = 3). Протестировано на i5-460M с 8 ГБ оперативной памяти. Я думаю, что это может быть улучшено за счет использования большего количества потоков.
Лекенштейн
C или C ++, вероятно, не будут иметь значения, так как большая часть времени выполнения тратится в любом случае на модуль OpenSSL (используется hashlib). Больше потоков улучшает скорость, смотрите этот пост о многопоточном скрипте Python .
Лекенштейн
@PM 2Ring - просто записка. После того, как операторы print в вашей функции digests (), вам нужно очистить хотя бы sha. Я не могу сказать, следует ли вам очистить MD5 или нет. Я бы просто использовал "Del Sha". Если вы этого не сделаете, каждый файл после первого будет иметь неправильный хэш. Чтобы доказать это, создайте каталог tmp и скопируйте в него файл. Теперь сделайте 2 копии этого файла и запустите ваш скрипт. Вы получите 3 разных хеша, а это не то, что вам нужно. Редактировать: я думал, что функция считывает набор файлов, а не просто читает один файл за раз ... Не обращайте внимания на это использование. ;)
Терри Вендт
1
@TerryWendt Вы заставили меня волноваться там на секунду. :) Да, digestsобрабатывает только один файл при каждом вызове. Таким образом, даже если вы вызывали его в цикле, он будет создавать новые контексты md5 & sha при каждом вызове. FWIW, вам может понравиться мой возобновляемый хэш SHA-256 .
PM 2Ring
5

Вы всегда можете использовать что-то вроде параллельной GNU :

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

В качестве альтернативы, просто запустите один из двух в фоновом режиме:

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

Или сохраните вывод в разные файлы и запустите несколько заданий в фоновом режиме:

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

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

Тердон
источник
1
Смотрите комментарий к Марко, меня беспокоит то, что хотя команда будет параллельной, к медленному диску дважды обращаются к одним и тем же данным.
Лекенштейн
Но разве наличие дискового кэша не сделает ваши заботы ненужными?
Мерцает
2
@Twinkles Цитируя Лекенштейна выше: «Проблема этого подхода в том, что одна команда может быть быстрее другой, что приводит к кешу диска, который позже очищается и пополняется теми же данными».
Мэтт Нордхофф
2
@MattNordhoff Еще одна вещь, которую интеллектуальный планировщик ввода-вывода должен заметить и оптимизировать для. Кто-то может подумать: «Насколько сложно для планировщика ввода-вывода принять этот сценарий во внимание?» Но при достаточном количестве различных сценариев, которые должен учитывать планировщик ввода / вывода, это внезапно становится сложной проблемой. Поэтому я согласен с тем, что не следует предполагать, что кеширование позаботится о проблеме.
Касперд
1
Предполагая, что IO значительно медленнее, чем любой из задействованных инструментов, оба инструмента должны быть замедлены до одинаковой скорости из-за IO. Поэтому, если одному инструменту удастся получить несколько блоков данных больше, чем другому, другой инструмент быстро догонит вычисления с использованием данных в кеше диска. Это теория, я бы хотел увидеть некоторые экспериментальные результаты, доказывающие это ...
liori
3

Из любопытства , будет ли многопоточный сценарий Python сократить время работы, я создал этот digest.pyскрипт , который использует threading.Thread, threading.Queueи hashlibдля вычисления хэш для нескольких файлов.

Многопоточная реализация Python действительно немного быстрее, чем при использовании peeс coreutils. Ява с другой стороны это ... ме. Результаты доступны в этом сообщении фиксации :

Для сравнения, для файла 2,3 ГиБ (мин / ср / макс / сд сек для n = 10):

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

Вывод хеша совместим с выводом coreutils. Поскольку длина зависит от алгоритма хеширования, этот инструмент не печатает его. Использование (для сравнения peeтакже было добавлено):

$ ./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  -
Lekensteyn
источник
Я собирался предложить сравнение pee "openssl sha256" "openssl md5" < file, но, честно говоря, я просто попробовал, и он не побил digest.py. Это сократило разрыв, хотя.
Мэтт Нордхофф
1

Jacksum - это бесплатная и независимая от платформы утилита для вычисления и проверки контрольных сумм, CRC и хешей (дайджестов сообщений), а также временных меток файлов. (взято из справочной страницы jacksum )

Он поддерживает большие файлы, он может обрабатывать файлы размером до 8 эксабайт (= 8 000 000 000 гигабайт), что предполагает вашу операционную систему, соответственно, ваша файловая система также поддерживает большие файлы. (взято из http://www.jonelo.de/java/jacksum/ )

Пример использования:

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

Образец вывода:

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

В Ubuntu запустите команду, apt-get install jacksumчтобы получить его.

Кроме того, исходные коды доступны на

pallxk
источник
Хотя это выдает правильные контрольные суммы, эта Java-программа вычисляет в два раза медленнее, чем coreutils. Смотрите это сообщение коммита .
Лекенштейн