複数のダイジェスト(md5、sha256)を同時に計算しますか?


25

ディスクI / Oと空きRAMがボト​​ルネックであるという仮定の下で(CPU時間は制限ではありません)、複数のメッセージダイジェストを一度に計算できるツールが存在しますか?

大きなファイル(サイズはギガバイト)のMD-5およびSHA-256ダイジェストを、できれば並列に計算することに特に興味があります。試しましたがopenssl dgst -sha256 -md5、1つのアルゴリズムを使用してハッシュを計算するだけです。

予想される動作の擬似コード:

for each block:
    for each algorithm:
        hash_state[algorithm].update(block)
for each algorithm:
    print algorithm, hash_state[algorithm].final_hash()

あなただけのバックグラウンド内の1つのインスタンスを起動することができ、その後、両方のハッシュが並行して実行しますfor i in file1 file2 …; do sha256 "$i"& md5sum "$i"; done
マルコ

2
@Marcoこのアプローチの問題は、1つのコマンドが他のコマンドよりも高速であるため、ディスクキャッシュが空になり、後で同じデータで補充されることです。
Lekensteyn

1
ディスクキャッシュが心配な場合は、ファイルを1回だけ読み込むことができます。for i in file1 file2 …; do tee < "$i" >(sha256sum) | md5sum ; doneその後、ファイル名をマークするための追加のコードを追加する必要がmd5sumありsha256sumます。
マルコ14年

回答:


28

からチェックアウトpee( " tee standard input to pipes")しmoreutilsます。これは基本的にMarcoのteeコマンドと同等ですが、入力が少し簡単です。

$ echo foo | pee md5sum sha256sum
d3b07384d113edec49eaa6238ad5ff00  -
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
$ pee md5sum sha256sum <foo.iso
f109ffd6612e36e0fc1597eda65e9cf0  -
469a38cb785f8d47a0f85f968feff0be1d6f9398e353496ff7aa9055725bc63e  -

素敵なコマンド!私はこの非常に便利なパッケージをすでにインストールしていますが、このおかしな名前のユーティリティを知りませんでした。
Lekensteyn

1
pee最適なインターフェースがあり、他のツールとの時間比較はこの投稿で見つけることができます。これはマルチスレッドPythonツールも示しています。
Lekensteyn

残念ながら、私のDebianシステムmoreutilsと競合しGNU parallelています...しかし、そのようなツールがあることを知っておくのは良いことです。
liori

@Lekensteyn:パッケージレベルで競合が発生しました(つまりaptitude、両方のパッケージを同時に使用できません)。
liori

@liori Debianがそのように実装したのは残念ですが、これについてバグを報告する価値があるかもしれません。Arch Linuxにはmoreutils-parallel、競合を避けるための名前があります。
Lekensteyn

10

forループを使用して個々のファイルをループした後tee 、プロセス置換(特にBashおよびZshで動作)と組み合わせて使用して、異なるチェックサムにパイプできます。

例:

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

3つ以上のチェックサムを使用することもできます。

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

1
出力*sumをツールファミリと互換性を持たせるには、代わりに次のsed式を使用できますsed "s;-\$;${file//;/\\;};-ファイル名で末尾を置き換えますが、ファイル名が適切にエスケープされることを確認してください)。
Lekensteyn

AFAICS、それはでのみ動作しzshます。ksh93およびbashでは、sha256sumの出力はmd5sumに送られます。あなたはお勧めします:{ tee < "$file" >(sha256sum >&3) | md5sum; } 3>&1。逆の問題については、unix.stackexchange.com / q / 153896/22565を参照してください。
ステファンシャゼル

6

opensslユーティリティが複数のダイジェストコマンドを受け付けないのは残念です。複数のファイルで同じコマンドを実行するのがより一般的な使用パターンだと思います。私のシステム(Mepis 11)のopensslユーティリティのバージョンであるFWIWには、shaとsha1のコマンドしかありません。他のshaバリアントはありません。しかし、私はsha256sumと呼ばれるプログラムとmd5sumを持っています。

以下に、単純なPythonプログラムdual_hash.pyを示します。64kのブロックサイズは、私のマシン(2GのRAMを搭載したIntel Pentium 4 2.00GHz)、YMMVに最適なようです。小さなファイルの場合、その速度は、md5sumとsha256sumを連続して実行するのとほぼ同じです。ただし、大きなファイルの場合は、かなり高速です。たとえば、1967063040バイトのファイル(mp3ファイルでいっぱいのSDカードのディスクイメージ)では、md5sum + sha256sumは約1m44.9sかかり、dual_hash.pyは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))

作品のほとんどはhashlibモジュールによって行われているので、私は、あまりない、このプログラムのC / C ++のバージョンが少し速くなりますと仮定される C(またはC ++)で記述されました。また、前述のように、大きなファイルのボトルネックはIO速度です。


2.3Gのファイルの場合、このバージョンは、比較md5sumおよびsha256sum結合された速度に匹敵します(このPythonスクリプトの4.7s + 14.2s対18.7s、キャッシュ内のファイル、コールドランの33.6s)。64KiB対1MiBは状況を変えませんでした。コードをコメントすると、md5(n = 3)に5.1秒、sha1(n = 3)に14.6秒が費やされました。8GB RAMを搭載したi5-460Mでテスト済み。これは、より多くのスレッドを使用することでさらに改善できると思います。
Lekensteyn

とにかく、CまたはC ++は、ランタイムの大部分がOpenSSLモジュール(hashlibで使用される)で費やされるほど重要ではないでしょう。スレッドを増やすと速度が向上しますマルチスレッドPythonスクリプトに関するこの投稿を参照してください。
Lekensteyn

@PM 2Ring-ご注意ください。digests()関数のprintステートメントの後、少なくともshaをクリアする必要があります。md5をクリアする必要があるかどうかは言えません。「デルシャ」を使用します。そうしないと、最初以降のすべてのファイルのハッシュが正しくなくなります。それを証明するために、tmpディレクトリを作成し、ファイルをコピーします。そのファイルの2つのコピーを作成し、スクリプトを実行します。3つの異なるハッシュが得られますが、これは望みのものではありません。編集:私は機能がファイルのセットを読んで、一度に1つのファイルを読むだけではないと思った...この使用を無視してください。;)
テリーウェント

1
@TerryWendtちょっと心配していました。:)はい、digests各呼び出しで1つのファイルのみを処理します。したがって、ループで呼び出した場合でも、呼び出しごとに新しいmd5&shaコンテキストが作成されます。FWIW、私の再開可能なSHA-256ハッシュをお楽しみください。
PM 2リング

5

GNU parallelのようなものを常に使用できます。

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

または、バックグラウンドで2つのうち1つを実行するだけです:

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

または、出力を異なるファイルに保存し、バックグラウンドで複数のジョブを実行します。

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

それは多くのように起動しますmd5sumsha256sum、あなたがファイルを持っているとして、インスタンスと、それらはすべて、対応するファイル名に出力を保存し、並行して実行されます。ただし、多くのファイルがある場合は注意が必要です。


1
マルコへのコメントを参照してください。私の心配は、コマンドは並列になりますが、同じデータに対して低速のディスクが2回アクセスされることです。
Lekensteyn

しかし、ディスクキャッシュが存在することで心配は不要になりませんか?
きらめき

2
@Twinkles上記のLekensteynを引用すると、「このアプローチの問題は、1つのコマンドが他のコマンドよりも高速であるため、ディスクキャッシュが空になり、後で同じデータで補充されることです。」
マットのNordhoff

2
@MattNordhoffインテリジェントI / Oスケジューラーが気づき、最適化する必要があるもう1つのこと。「I / Oスケジューラがこのシナリオを考慮に入れるのはどれほど難しいでしょうか?」しかし、I / Oスケジューラーが考慮すべきシナリオが十分にあると、突然難しい問題になります。そのため、キャッシングが問題を処理すると考えるべきではないことに同意します。
カスペルド14年

1
IOが関連するどのツールよりも大幅に遅いと仮定すると、IOのために両方のツールを同じ速度に減速する必要があります。したがって、1つのツールが他のツールよりもデータのブロック数が少ない場合、他のツールはディスクキャッシュ内のデータを使用した計算にすぐに追いつきます。理論、私は...いくつかの実験結果は、それを証明する見てみたいこと
liori

3

マルチスレッドのPythonスクリプトの実行時間を短縮するかどうか好奇心のうち、私はこの作成されたdigest.py用途は、スクリプトthreading.Threadthreading.Queueおよびhashlib複数のファイルのハッシュを計算するために。

実際、マルチスレッドPython実装はpee、coreutils で使用するよりもわずかに高速です。一方、Javaは...まあです。結果は次のコミットメッセージで確認できます

比較のために、2.3 GiBのファイルの場合(n = 10の最小/ 平均 /最大/ sd秒):

  • おしっこ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  -

私は比較することを提案pee "openssl sha256" "openssl md5" < fileしようとしていましたが、正直なところ、私は試してみましたが、digest.pyに勝るものはありませんでした。しかし、それはギャップを狭めました。
マットノルドホフ14年

1

Jacksumは、ファイルのタイムスタンプだけでなく、チェックサム、CRC、ハッシュ(メッセージダイジェスト)を計算および検証するための、プラットフォームに依存しない無料のユーティリティです。jacksum man pageから抜粋)

大規模ファイルを認識し、最大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を実行して取得します。

または、ソースコードは


これは正しいチェックサムを出力しますが、このJavaプログラムはcoreutilsの2倍の速度で計算します。このコミットメッセージを参照してください。
Lekensteyn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.