Aynı anda birden fazla özeti hesapla (md5, sha256)?


25

Disk G / Ç ve boş RAM'in bir darboğaz olduğu varsayımı altında (CPU süresi sınırlama olmasa da), aynı anda birden fazla mesaj özeti hesaplayabilen bir araç var mı?

MD-5 ve SHA-256 büyük dosyaların özetini (gigabayt cinsinden boyut), tercihen paralel olarak hesaplamakla özellikle ilgileniyorum. Denedim openssl dgst -sha256 -md5, ancak yalnızca bir algoritma kullanarak karma hesaplar.

Beklenen davranış için sözde kod:

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

Arka planda yalnızca bir örneği başlatabilirsiniz, ardından her iki karma da paralel olarak çalışır:for i in file1 file2 …; do sha256 "$i"& md5sum "$i"; done
Marco

2
@Marco Bu yaklaşımla ilgili sorun, bir komutun diğerinden daha hızlı olması ve daha sonra aynı verilerle boşaltılıp yeniden doldurulması gereken bir disk önbelleği oluşmasıdır.
Lekensteyn

1
Disk önbelleği endişe ediyorsanız, sadece bir kez dosyasında okuyabilirsiniz: for i in file1 file2 …; do tee < "$i" >(sha256sum) | md5sum ; donestandart girdi olarak gönderildiği için O zaman, dosya adını işaretlemek için ek kod eklemek zorunda md5sumve sha256sum.
Marco

Yanıtlar:


28

Adlı kullanıcıdan pee(" tee standard input to pipes") göz atın moreutils. Bu temelde Marco'nun teekomutuna eşdeğerdir , ancak yazması biraz basittir.

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

Güzel emir! Zaten bu çok kullanışlı bir pakete sahibim, bu komik ismi taşıyan programı bilmiyordum.
Lekensteyn

1
peeEn iyi arayüze sahip, çok dipli bir Python aracını da gösteren bu yazıda diğer araçlarla bir zaman karşılaştırması bulunabilir .
Lekensteyn

Ne yazık ki, Debian sistemimle moreutilsçatışıyor GNU parallel… yine de böyle bir araç olduğunu bilmek güzel.
liori

@Lekensteyn: Paket düzeyinde bir çelişki alıyorum (yani aptitude, her iki paketi de aynı anda almama izin vermiyor).
liori

@liori Debian'ın bu şekilde uygulaması çok kötü, bu konuda bir hata bildirmeye değebilir. Linux'ta moreutils-parallel, çatışmadan kaçınmak için bir isim var .
Lekensteyn

10

Tek fortek dosyalar üzerinde döngü yapmak için bir döngü kullanabilir ve daha sonra tee farklı sağlama toplamlarına yönlendirmek için işlem değiştirme (birlikte Bash ve Zsh'de çalışır) ile birlikte kullanabilirsiniz .

Örnek:

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

İkiden fazla sağlama toplamı da kullanabilirsiniz:

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

Bu, sağlama toplamı sahibinin dosya adını bilmemesinin dezavantajı vardır; çünkü standart girdi olarak geçirilir. Bu kabul edilebilir değilse, dosya adlarını manuel olarak yayınlamanız gerekir. Tam örnek:

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

1
Çıktının *sumaraçlar ailesiyle uyumlu hale getirilmesi için , bu sed ifadesi bunun yerine kullanılabilir: sed "s;-\$;${file//;/\\;};( -dosya adının izini değiştirdi , ancak dosya adının doğru şekilde kaçtığından emin olun).
Lekensteyn

AFAICS, sadece işe yarıyor zsh. Ksh93 ve bash'te sha256sum'un çıktısı md5sum'a gider. Sen isteyebilirsiniz: { tee < "$file" >(sha256sum >&3) | md5sum; } 3>&1. Bkz unix.stackexchange.com/q/153896/22565 ters sorun.
Stéphane Chazelas 24:14

6

Openssl yardımcı programının birden fazla özet komutunu kabul etmemesi üzücü; Sanırım aynı komutu birden fazla dosyada yapmak daha yaygın bir kullanım şeklidir. FWIW, sistemimdeki openssl yardımcı programının sürümü (Mepis 11), diğer sha değişkenlerinden hiçbirinde değil, sadece sha ve sha1 komutlarını içerir. Ancak sha256sum ve md5sum adında bir programım var.

İşte istediğini yapan basit bir Python programı, dual_hash.py. Benim makine için 64k'lık bir blok büyüklüğü en uygun gibi görünüyor (2G RAM ile Intel Pentium 4 2.00GHz), YMMV. Küçük dosyalar için hızı, md5sum ve sha256sum'ları art arda çalıştırmakla hemen hemen aynıdır. Ancak daha büyük dosyalar için çok daha hızlıdır. Örneğin, 1967063040 bayt bir dosyada (mp3 dosyalarıyla dolu bir SD kartın bir disk görüntüsü), md5sum + sha256sum yaklaşık 1m44.9s, dual_hash.py ise 1m0.312s alır.

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

Sanırım bu programın C / C ++ sürümü biraz daha hızlı olacaktı ama çok fazla değil, çünkü işlerin çoğu C (veya C ++) ile yazılmış hashlib modülü tarafından yapılıyor . Yukarıda belirttiğiniz gibi, büyük dosyalar için tıkanıklık IO hızıdır.


2.3G bir dosya için, bu sürüm ile karşılaştırıldığında md5sumve sha256sumbirleştirilmiş karşılaştırılabilir bir hıza sahipti (4.7s + 14.2s - bu Python betiği için 18.7, önbellekte dosya; soğuk çalışma için 33.6). 64KiB vs 1MiB durumu değiştirmedi. Yorumlanan kod ile 5.1 saniye md5 (n = 3), 14.6 saniye sha1 (n = 3) harcandı. İ5-460M'de 8GB RAM ile test edilmiştir. Sanırım bu daha fazla iş parçacığı kullanılarak daha da geliştirilebilir.
Lekensteyn

C veya C ++ muhtemelen çalışma zamanının büyük bir kısmının OpenSSL modülünde (hashlib tarafından kullanılan) ne kadar harcandığı önemli değildir. Daha fazla iş parçacığı hızı artırır, çok iş parçacıklı Python komut dosyası hakkında bu yazıya bakın .
Lekensteyn

@ PM 2Ring - Sadece bir not. Digests () fonksiyonunuzdaki print ifadelerinden sonra, en azından sha'yı temizlemeniz gerekir. MD5'i temizlemeniz gerekip gerekmediğini söyleyemem. Sadece "del sha" kullanırdım. Bunu yapmazsanız, ilk dosyadan sonraki her dosya yanlış bir karmaya sahip olacaktır. Kanıtlamak için bir tmp dir yapın ve bir dosyayı kopyalayın. Şimdi bu dosyanın 2 kopyasını alın ve betiğinizi çalıştırın. İstediğiniz ne değil 3 farklı karma elde edersiniz. Düzenleme: İşlevin sadece bir seferde tek bir dosyayı okumak yerine, bir dosya dizisi üzerinde okuduğunu sanıyordum ... Bu kullanım için dikkate almayın. ;)
Terry Wendt

1
@TerryWendt Bana bir saniye endişelenmemi sağladın. :) Evet, digestsher aramada yalnızca tek bir dosyayı işler. Böylece bir döngüde çağırmış olsanız bile, her aramada yeni md5 & sha bağlamları yapacaktır. FWIW, yeniden başlatılabilir SHA-256 hastamın tadını çıkarabilirsiniz .
PM 2Ring

5

GNU paralel gibi bir şey her zaman kullanabilirsiniz :

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

Alternatif olarak, arka plandaki ikisinden birini çalıştırmanız yeterlidir:

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

Veya çıktıyı farklı dosyalara kaydedin ve arka planda birden fazla işi çalıştırın:

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

Bu, dosyalarınız kadar çok md5sumve sha256sumörnek başlatacak ve çıktılarını karşılık gelen dosya adlarına kaydederek hepsi paralel olarak çalışacaktır. Dikkatli ol, çok fazla dosya varsa, bu ağır alabilirsiniz.


1
Marco yorumuna bakın, benim endişem, komut paralel olmasına rağmen, aynı veri için yavaş diske iki kez erişilebilmesi.
Lekensteyn

Ancak disk önbelleğinin varlığı endişelerinizi gereksiz kılmaz mı?
Pırıltılar

2
@Twinkles Lekensteyn'e yukarıdaki alıntıda, "Bu yaklaşımla ilgili sorun, bir komutun diğerinden daha hızlı olabileceği ve daha sonra aynı verilerle boşaltılan ve yeniden doldurulan bir disk önbelleği oluşmasıdır."
Matt Nordhoff

2
@MattNordhoff Akıllı bir G / Ç programlayıcısının fark etmesi ve optimize etmesi gereken başka bir şey var. Bir kişi şöyle düşünebilir: "Bir G / Ç programlayıcısının bu senaryoyu dikkate alması ne kadar zor olabilir?" Ancak bir G / Ç programlayıcısının göz önünde bulundurması gereken farklı senaryolarda aniden zor bir problem haline gelir. Bu nedenle, önbelleklemenin sorunla ilgileneceği varsayılmamalıdır.
kasperd

1
IO'nun ilgili tüm araçlardan önemli ölçüde yavaş olduğu varsayılırsa, her iki aracın da IO nedeniyle aynı hızda yavaşlatılması gerekir. Bu nedenle, bir araç diğerinden daha az veri bloğu almayı başarırsa, diğer araç disk önbelleğindeki verileri kullanarak hesaplamaları hızlı bir şekilde yakalar. Bu teori, kanıtlayan bazı deneysel sonuçları görmeyi çok isterdim…
liori

3

Çok iş parçacıklı bir Python betiğinin çalışma süresini kısaltıp düşürmeyeceği merakından , digest.pykullanan bu komut dosyasını ve birden fazla dosya için hash hesaplarını yaptım .threading.Threadthreading.Queuehashlib

Çok iş parçacıklı Python uygulaması aslında peecoreutils ile kullanmaktan biraz daha hızlıdır . Diğer taraftan Java ise ... meh. Sonuçlar bu işlem mesajında ​​mevcuttur :

Karşılaştırma için, 2.3 GiB'lik bir dosya için (n = 10 için min / avg / max / sd sn.):

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

Karma çıktı, coreutils tarafından üretilen çıktıyla uyumludur. Uzunluk karma algoritmaya bağlı olduğundan, bu araç onu yazdırmaz. Kullanım (karşılaştırma peeiçin ayrıca eklendi):

$ ./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  -

Karşılaştırma yapmak önerecektim pee "openssl sha256" "openssl md5" < file, ama dürüst olmak gerekirse, daha yeni denedim ve digest.py'yi geçmedi. Yine de açığı daralttı.
Matt Nordhoff

1

Jacksum, sağlama toplamları, CRC'ler ve hash'lerin (mesaj özeti) ve dosyaların zaman damgalarını hesaplamak ve doğrulamak için ücretsiz ve platformdan bağımsız bir yardımcı programdır. ( jacksum man sayfasından alınmıştır )

Dosya farkında, büyük ölçüde 8 Exabyte'a (= 8.000.000.000 Gigabyte) kadar dosya işleme yapabilir, işletim sisteminizin sırasıyla dosya sisteminizin de farkında olduğunu varsayar. ( http://www.jonelo.de/java/jacksum/ adresinden alıntılanmıştır )

Kullanım örneği:

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

Örnek çıktı:

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

Ubuntu'da apt-get install jacksumonu almak için komutu çalıştırın .

Alternatif olarak, kaynak kodları


Bu doğru sağlama toplamlarını verirken, bu Java programı coreutils'in iki katı kadar yavaş hesaplar. Bu mesaja bakın .
Lekensteyn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.