Mencirikan file dengan Python

101

Saya ingin python membaca ke EOF sehingga saya bisa mendapatkan hash yang sesuai, apakah itu sha1 atau md5. Tolong bantu. Inilah yang saya miliki sejauh ini:

import hashlib

inputFile = raw_input("Enter the name of the file:")
openedFile = open(inputFile)
readFile = openedFile.read()

md5Hash = hashlib.md5(readFile)
md5Hashed = md5Hash.hexdigest()

sha1Hash = hashlib.sha1(readFile)
sha1Hashed = sha1Hash.hexdigest()

print "File Name: %s" % inputFile
print "MD5: %r" % md5Hashed
print "SHA1: %r" % sha1Hashed
pengguna3358300
sumber
6
dan apa masalahnya?
isedev
1
Saya ingin file tersebut dapat di-hash. Saya membutuhkannya untuk membaca hingga EOF, berapa pun ukuran filenya.
pengguna3358300
3
itulah yang file.read()dilakukannya - baca seluruh file.
isedev
Dokumentasi untuk read()metode tersebut mengatakan?
Ignacio Vazquez-Abrams
Anda harus melalui "apa hashing?".
Sharif Mamun

Jawaban:

141

TL; DR menggunakan buffer untuk tidak menggunakan banyak memori.

Kami sampai ke inti masalah Anda, saya yakin, ketika kami mempertimbangkan implikasi memori dari bekerja dengan file yang sangat besar . Kami tidak ingin bocah nakal ini mengaduk-aduk 2 giga ram untuk file 2 gigabyte jadi, seperti yang ditunjukkan pasztorpisti , kami harus menangani file-file yang lebih besar itu dalam potongan!

import sys
import hashlib

# BUF_SIZE is totally arbitrary, change for your app!
BUF_SIZE = 65536  # lets read stuff in 64kb chunks!

md5 = hashlib.md5()
sha1 = hashlib.sha1()

with open(sys.argv[1], 'rb') as f:
    while True:
        data = f.read(BUF_SIZE)
        if not data:
            break
        md5.update(data)
        sha1.update(data)

print("MD5: {0}".format(md5.hexdigest()))
print("SHA1: {0}".format(sha1.hexdigest()))

Apa yang telah kami lakukan adalah memperbarui hash kami dari bocah nakal ini dalam potongan 64kb saat kami mengikuti metode pembaruan keren yang berguna dari hashlib . Dengan cara ini kami menggunakan memori yang jauh lebih sedikit daripada 2gb yang diperlukan untuk melakukan hash sekaligus!

Anda dapat mengujinya dengan:

$ mkfile 2g bigfile
$ python hashes.py bigfile
MD5: a981130cf2b7e09f4686dc273cf7187e
SHA1: 91d50642dd930e9542c39d36f0516d45f4e1af0d
$ md5 bigfile
MD5 (bigfile) = a981130cf2b7e09f4686dc273cf7187e
$ shasum bigfile
91d50642dd930e9542c39d36f0516d45f4e1af0d  bigfile

Semoga membantu!

Juga semua ini diuraikan dalam pertanyaan terkait di sisi kanan: Dapatkan hash MD5 file besar dengan Python


Tambahan!

Secara umum saat menulis python, ada baiknya membiasakan diri mengikuti pep-8 . Misalnya, dalam variabel python biasanya dipisahkan garis bawah, bukan camelCased. Tapi itu hanya gaya dan tidak ada yang benar-benar peduli tentang hal-hal itu kecuali orang yang harus membaca gaya yang buruk ... yang mungkin Anda membaca kode ini bertahun-tahun dari sekarang.

Randall Hunt
sumber
@ranman Halo, saya tidak bisa mendapatkan bagian {0} ". format (sha1.hexdigest ()). Mengapa kita menggunakannya daripada hanya menggunakan sha1.hexdigest ()?
Belial
@Belial Apa yang tidak berhasil? Saya hanya menggunakan itu untuk membedakan antara dua hash ...
Randall Hunt
@ranman Semuanya berfungsi, saya tidak pernah menggunakan ini dan belum pernah melihatnya di literatur. "{0}". Format () ... tidak saya kenal. :)
Belial
1
Bagaimana saya harus memilih BUF_SIZE?
Martin Thoma
1
Ini tidak menghasilkan hasil yang sama dengan shasumbinari. Jawaban lain yang tercantum di bawah ini (yang menggunakan memoryview) kompatibel dengan alat hashing lainnya.
tedivm
61

Untuk penghitungan nilai hash file yang benar dan efisien (dengan Python 3):

  • Buka file dalam mode biner (yaitu tambahkan 'b'ke kode file) untuk menghindari pengkodean karakter dan masalah konversi akhir baris.
  • Jangan membaca file lengkap ke dalam memori, karena itu hanya membuang-buang memori. Sebagai gantinya, bacalah secara berurutan blok demi blok dan perbarui hash untuk setiap blok.
  • Hilangkan double buffering, yaitu jangan gunakan buffered IO, karena kita sudah menggunakan ukuran blok yang optimal.
  • Gunakan readinto()untuk menghindari buffer yang berputar.

Contoh:

import hashlib

def sha256sum(filename):
    h  = hashlib.sha256()
    b  = bytearray(128*1024)
    mv = memoryview(b)
    with open(filename, 'rb', buffering=0) as f:
        for n in iter(lambda : f.readinto(mv), 0):
            h.update(mv[:n])
    return h.hexdigest()
maxschlepzig.dll
sumber
2
Bagaimana Anda tahu apa itu ukuran blok yang optimal?
Mitar
1
@Mitar, batas bawah adalah maksimum blok fisik (biasanya 512 byte atau 4KiB dengan disk yang lebih baru) dan ukuran halaman sistem (4KiB pada banyak sistem, pilihan umum lainnya: 8KiB dan 64 KiB). Kemudian pada dasarnya Anda melakukan beberapa pembandingan dan / atau melihat hasil pembandingan yang dipublikasikan dan pekerjaan terkait (misalnya, periksa apa yang digunakan rsync / GNU cp / ... saat ini).
maxschlepzig
Apakah resource.getpagesizeada gunanya di sini, jika kita ingin mencoba mengoptimalkannya secara dinamis? Dan bagaimana dengan mmap?
jpmc26
@ jpmc26, getpagesize () tidak terlalu berguna di sini - nilai yang umum adalah 4 KiB atau 8 KiB, sesuatu dalam kisaran itu, yaitu sesuatu yang jauh lebih kecil dari 128 KiB - 128 KiB umumnya merupakan pilihan yang baik. mmap tidak banyak membantu dalam kasus penggunaan kami karena kami secara berurutan membaca file lengkap dari depan ke belakang. mmap memiliki keuntungan ketika pola akses lebih bersifat random-access, jika halaman diakses lebih dari sekali dan / atau jika mmap menyederhanakan manajemen buffer baca.
maxschlepzig
3
Saya membandingkan solusi (1) @Randall Hunt dan (2) milik Anda (dalam urutan ini, penting karena cache file) dengan file sekitar 116GB dan algoritma sha1sum. Solusi 1 dimodifikasi untuk menggunakan buffer 20 * 4096 (PAGE_SIZE) dan mengatur parameter buffering ke 0. Algoritma solusi 2 saja yang dimodifikasi (sha256 -> sha1). Hasil: (1) 3m37.137s (2) 3m30.003s. Sha1sum asli dalam mode biner: 3m31.395s
bioinfornatics
18

Saya akan mengusulkan secara sederhana:

def get_digest(file_path):
    h = hashlib.sha256()

    with open(file_path, 'rb') as file:
        while True:
            # Reading is buffered, so we can read smaller chunks.
            chunk = file.read(h.block_size)
            if not chunk:
                break
            h.update(chunk)

    return h.hexdigest()

Semua jawaban lain di sini tampaknya terlalu rumit. Python sudah buffering saat membaca (dengan cara yang ideal, atau Anda mengonfigurasi buffering itu jika Anda memiliki lebih banyak informasi tentang penyimpanan yang mendasarinya) dan oleh karena itu lebih baik untuk membaca dalam potongan-potongan yang menurut fungsi hash ideal yang membuatnya lebih cepat atau paling tidak CPU intensif untuk menghitung fungsi hash. Jadi, alih-alih menonaktifkan buffering dan mencoba menirunya sendiri, Anda menggunakan buffering Python dan mengontrol apa yang harus Anda kendalikan: apa yang dianggap ideal oleh konsumen data Anda, ukuran blok hash.

Mitar
sumber
Jawaban sempurna, tetapi alangkah baiknya, jika Anda mendukung pernyataan Anda dengan dokumen terkait: Python3 - open () dan Python2 - open () . Terlepas dari perbedaan antara keduanya, pendekatan Python3 lebih canggih. Namun demikian, saya sangat menghargai perspektif yang berpusat pada konsumen!
Murmel
hash.block_sizedidokumentasikan sebagai 'ukuran blok internal dari algoritma hash'. Hashlib tidak menganggapnya ideal . Tidak ada dalam dokumentasi paket yang menyarankan bahwa update()lebih memilih hash.block_sizeinput berukuran. Itu tidak menggunakan lebih sedikit CPU jika Anda menyebutnya seperti itu. file.read()Panggilan Anda mengarah ke banyak pembuatan objek yang tidak perlu dan salinan yang berlebihan dari buffer file ke objek chunk bytes baru Anda.
maxschlepzig
Hash memperbarui statusnya dalam beberapa bagian block_size. Jika Anda tidak menyediakannya dalam potongan tersebut, mereka harus menyangga dan menunggu data yang cukup untuk muncul, atau membagi data yang diberikan menjadi beberapa potongan secara internal. Jadi, Anda bisa mengatasinya di luar dan kemudian menyederhanakan apa yang terjadi secara internal. Saya menemukan yang ideal ini. Lihat contoh: stackoverflow.com/a/51335622/252025
Mitar
Ini block_sizejauh lebih kecil daripada ukuran baca yang berguna. Selain itu, setiap blok yang berguna dan ukuran baca adalah pangkat dua. Dengan demikian, ukuran pembacaan dapat dibagi oleh ukuran blok untuk semua pembacaan kecuali mungkin pembacaan yang terakhir. Misalnya, ukuran blok sha256 adalah 64 byte. Itu berarti update()dapat langsung memproses input tanpa ada buffering hingga kelipatan block_size. Jadi, hanya jika pembacaan terakhir tidak dapat dibagi oleh ukuran blok, ia harus menyangga hingga 63 byte, sekali. Karenanya, komentar terakhir Anda salah dan tidak mendukung klaim yang Anda buat dalam jawaban Anda.
maxschlepzig
Intinya adalah seseorang tidak harus mengoptimalkan buffering karena sudah dilakukan oleh Python saat membaca. Jadi Anda hanya perlu memutuskan jumlah perulangan yang ingin Anda lakukan saat melakukan hashing pada buffer yang ada.
Mitar
6

Saya telah memprogram modul yang dapat melakukan hash file besar dengan algoritme berbeda.

pip3 install py_essentials

Gunakan modul seperti ini:

from py_essentials import hashing as hs
hash = hs.fileChecksum("path/to/the/file.txt", "sha256")
filil
sumber
Apakah itu lintas platform (Linux + Win)? Apakah ini bekerja dengan Python3? Juga apakah masih dipertahankan?
Basj
5

Berikut adalah Python 3, solusi POSIX (bukan Windows!) Yang digunakan mmapuntuk memetakan objek ke dalam memori.

import hashlib
import mmap

def sha256sum(filename):
    h  = hashlib.sha256()
    with open(filename, 'rb') as f:
        with mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) as mm:
            h.update(mm)
    return h.hexdigest()
Antti Haapala
sumber
Pertanyaan naif ... apa keuntungan menggunakan mmapskenario ini?
Jonathan B.
1
@Jonathan. kebanyakan metode tidak perlu membuat bytesobjek dalam memori, dan memanggil readterlalu banyak atau terlalu sedikit waktu. Ini akan memetakan file langsung ke memori virtual, dan melakukan hash dari sana - sistem operasi dapat memetakan konten file langsung dari cache buffer ke dalam proses membaca. Ini berarti ini bisa lebih cepat dengan faktor signifikan di atas yang satu ini
Antti Haapala
@Jonathan. Saya melakukan tes dan perbedaannya tidak terlalu signifikan dalam kasus ini , kita berbicara tentang ~ 15% melalui metode naif.
Antti Haapala
-2
import hashlib
user = input("Enter ")
h = hashlib.md5(user.encode())
h2 = h.hexdigest()
with open("encrypted.txt","w") as e:
    print(h2,file=e)


with open("encrypted.txt","r") as e:
    p = e.readline().strip()
    print(p)
Ome Mishra
sumber
2
Anda pada dasarnya melakukan echo $USER_INPUT | md5sum > encrypted.txt && cat encrypted.txtyang tidak berhubungan dengan hashing file, terutama yang tidak besar.
Murmel
1
hashing! = mengenkripsi
bugmenot123