4

ファイル関連のアプリケーションを作成しています。そして、ファイルのチェックサムを計算する方法を探していました。この基準に基づいて、md5 や SHA-1 などのファイルのチェックサムを計算するための最適なハッシュ方法を知りたい

  • チェックサムは一意である必要があります。私はその理論を知っていますが、それでも衝突の確率を非常に小さくしたいと考えています。
  • チェックサムが等しいかどうかに関係なく、2 つのファイルを比較して等しいかどうかを確認できます。
  • 速度(あまり重要ではありませんが、それでも)

出来るだけ丁寧にお願いします。

4

4 に答える 4

6

ユースケースによって異なります。

偶発的な衝突だけが心配な場合は、MD5 と SHA-1 の両方で問題なく、一般的に MD5 の方が高速です。実際、MD4 はほとんどのユースケースで十分であり、通常はさらに高速ですが、広く実装されているわけではありません。(特に、それは含まれていませんhashlib.algorithms_guaranteed... ただし、hashlib_algorithms_availableほとんどのストック Mac、Windows、および Linux ビルドには含まれているはずです。)

一方、意図的な攻撃 (つまり、ハッシュに一致する偽のファイルを意図的に作成する誰か) を心配している場合は、保護しているものの価値を考慮する必要があります。MD4 ではほぼ間違いなく十分ではありません。MD5 ではおそらく十分ではありませんが、SHA-1 は限界です。現在、Keccak (まもなく SHA-3 になる予定) が最善の策であると考えられていますが、状況は毎年変化するため、これを常に把握しておく必要があります。

暗号化ハッシュ関数に関するウィキペディアのページには、通常かなり頻繁に更新される表があります。表を理解するには:

MD4 に対する衝突を生成するには 3 ラウンドしか必要としませんが、MD5 では約 200 万回、SHA-1 では 15 兆回必要です。これは、衝突を生成するのに (現在の価格で) 数百万ドルかかることを意味します。それはあなたにとって十分かもしれませんし、そうでないかもしれませんが、NIST にとっては十分ではありません。


また、「一般的に速い」ということは、「私のデータとプラットフォームでより速くテストされた」ということほど重要ではないことを覚えておいてください。それを念頭に置いて、私の Mac の 64 ビット Python 3.3.0 で、1MB のランダムbytesオブジェクトを作成し、次のようにしました。

In [173]: md4 = hashlib.new('md4')
In [174]: md5 = hashlib.new('md5')
In [175]: sha1 = hashlib.new('sha1')
In [180]: %timeit md4.update(data)
1000 loops, best of 3: 1.54 ms per loop
In [181]: %timeit md5.update(data)
100 loops, best of 3: 2.52 ms per loop
In [182]: %timeit sha1.update(data)
100 loops, best of 3: 2.94 ms per loop

ご覧のとおりmd4、他のものよりも大幅に高速です。

hashlib.md5()の代わりに をhashlib.new('md5')使用したテストとbytes、少ないエントロピー (string.ascii_lettersスペースで区切られた 1 ~ 8 の実行) を使用したテストでは、有意な差は見られませんでした。

また、私のインストールに付属のハッシュ アルゴリズムについては、以下でテストしたように、md4 に勝るものはありません。

for x in hashlib.algorithms_available:
    h = hashlib.new(x)
    print(x, timeit.timeit(lambda: h.update(data), number=100))

速度が非常に重要な場合は、これを改善するために使用できる優れたトリックがあります。 のような悪いが非常に高速なハッシュ関数を使用し、zlib.adler32各ファイルの最初の 256KB にのみ適用します。(ファイルの種類によっては、最後の 256KB や、最初の 256KB よりも中央に近い 256KB の方がよい場合があります。) 次に、衝突が見つかった場合は、MD4/SHA-1/Keccak/任意のハッシュを生成します。各ファイルのファイル全体。


最後に、誰かがコメントで、ファイル全体をメモリに読み込まずにファイルをハッシュする方法を尋ねたので:

def hash_file(path, algorithm='md5', bufsize=8192):
    h = hashlib.new(algorithm)
    with open(path, 'rb') as f:
        block = f.read(bufsize)
        if not block:
            break
        h.update(block)
    return h.digest()

すべてのパフォーマンスを引き出すことが重要な場合はbufsize、プラットフォームでさまざまな値 (4KB から 8MB までの 2 のべき乗) を試してください。os.open生のファイル ハンドル (および)を使用して実験することもできos.readます。これは、一部のプラットフォームでは高速になる場合があります。

于 2013-05-28T19:08:25.280 に答える
1

md5はチェックサムに最適な傾向があります... SHA-1と同じ...どちらも衝突の確率は非常に小さいですが、SHA-1はより多くのビットを使用するため、衝突の確率はわずかに小さいと思います

本当に心配なら、両方のチェックサム (1 つの md5 と 1 つの sha1) を使用できます。両方が一致し、ファイルが異なる可能性は非常に小さいです (まだ 100% 不可能ではありませんが、非常にありそうにありません) ... (これは悪いフォームとはるかに遅い解決策のように)

通常(読んだ:私がこれまでに遭遇したすべてのインスタンスで)MD5またはSHA1の一致は、一意性を想定するのに十分です

バイトごとの比較以外に一意性を 100% 保証する方法はありません

于 2013-05-28T19:06:11.980 に答える
0

数日前に小さな重複ファイル削除スクリプトを作成しました。これは、ファイルの内容を読み取ってハッシュを作成し、次のファイルと比較します。名前が異なっていても、チェックサムは同じになります。 .

import hashlib
import os

hash_table = {}
dups = []
path = "C:\\images"
for img in os.path.listdir(path):
    img_path = os.path.join(path, img)
    _file = open(img_path, "rb")
    content = _file.read()
    _file.close()
    md5 = hashlib.md5(content)
    _hash = md5.hexdigest()

    if _hash in hash_table.keys():
        dups.append(img)
    else:
        hash_table[_hash] = img    
于 2013-05-28T18:59:06.070 に答える