Apakah ada cara sederhana untuk menghasilkan (dan memeriksa) checksum MD5 dari daftar file dengan Python? (Saya punya program kecil yang sedang saya kerjakan, dan saya ingin mengkonfirmasi checksum dari file).
Menyimpannya dalam Python membuatnya lebih mudah untuk mengelola kompatibilitas lintas platform.
Alexander
Jika Anda menginginkan solusi dengan "progress bar * atau yang serupa (untuk file yang sangat besar), pertimbangkan solusi ini: stackoverflow.com/questions/1131220/…
Laurent LAPORTE
1
@kennytm Tautan yang Anda berikan mengatakan ini di paragraf kedua: "Algoritma MD5 yang mendasarinya tidak lagi dianggap aman" saat menjelaskan md5sum. Itulah mengapa programmer yang sadar akan keamanan sebaiknya tidak menggunakannya menurut saya.
Debug255
1
@ Debug255 Poin bagus dan valid. Baik md5sumdan teknik yang dijelaskan dalam pertanyaan SO ini harus dihindari - lebih baik menggunakan SHA-2 atau SHA-3, jika mungkin: en.wikipedia.org/wiki/Secure_Hash_Algorithms
Perhatikan bahwa terkadang Anda tidak dapat memasukkan seluruh file ke dalam memori. Dalam hal ini, Anda harus membaca potongan 4096 byte secara berurutan dan mengumpankannya ke md5metode:
Catatan:hash_md5.hexdigest() akan mengembalikan representasi string hex untuk digest, jika Anda hanya perlu menggunakan byte yang dikemas return hash_md5.digest(), sehingga Anda tidak perlu mengkonversi kembali.
[(fname, hashlib.md5(file_as_bytes(open(fname,'rb'))).digest())for fname in fnamelst]
Ingat, MD5 diketahui rusak dan tidak boleh digunakan untuk tujuan apa pun karena analisis kerentanan bisa sangat rumit, dan menganalisis kemungkinan penggunaan di masa depan yang mungkin dilakukan oleh kode Anda untuk masalah keamanan tidak mungkin. IMHO, itu harus dihapus dari perpustakaan sehingga semua orang yang menggunakannya terpaksa memperbarui. Jadi, inilah yang harus Anda lakukan sebagai gantinya:
[(fname, hashlib.sha256(file_as_bytes(open(fname,'rb'))).digest())for fname in fnamelst]
Jika Anda hanya ingin mencerna 128 bit, Anda bisa melakukannya .digest()[:16].
Ini akan memberi Anda daftar tupel, masing-masing tupel berisi nama file dan hash-nya.
Sekali lagi saya sangat mempertanyakan penggunaan MD5 Anda. Anda harus setidaknya menggunakan SHA1, dan diberi kekurangan baru-baru ini ditemukan di SHA1 , bahkan mungkin tidak. Beberapa orang berpikir bahwa selama Anda tidak menggunakan MD5 untuk tujuan 'kriptografi', Anda baik-baik saja. Tetapi hal-hal memiliki kecenderungan untuk menjadi lebih luas dalam ruang lingkup daripada yang Anda harapkan, dan analisis kerentanan kasual Anda mungkin terbukti benar-benar cacat. Yang terbaik adalah membiasakan diri menggunakan algoritma yang tepat di luar gerbang. Itu hanya mengetik banyak huruf yang berbeda. Tidak sesulit itu.
Berikut ini cara yang lebih kompleks, tetapi hemat memori :
Saya hanya menggunakan MD5 untuk mengkonfirmasi file tidak rusak. Saya tidak begitu khawatir tentang itu rusak.
Alexander
87
@TheLifelessOne: Dan meskipun peringatan menakutkan @Omnifarious, itu adalah penggunaan MD5 yang sangat baik.
Presiden James K. Polk
22
@Regs, @TheLifelessOne - Ya, dan selanjutnya Anda tahu seseorang menemukan cara untuk menggunakan fakta ini tentang aplikasi Anda untuk menyebabkan file diterima sebagai tidak rusak ketika itu bukan file yang Anda harapkan sama sekali. Tidak, saya mendukung peringatan menakutkan saya. Saya pikir MD5 harus dihapus atau datang dengan peringatan penghentian.
Mahakuasa
10
Saya mungkin akan menggunakan .hexdigest () daripada .digest () - lebih mudah bagi manusia untuk membaca - yang merupakan tujuan OP.
zbstof
21
Saya menggunakan solusi ini tetapi tidak benar memberikan hash yang sama untuk dua file pdf yang berbeda. Solusinya adalah membuka file dengan menetapkan mode biner, yaitu: [(fname, hashlib.md5 (buka (fname, 'rb' ) .read ()). Hexdigest ()). Hexdigest ()) untuk fname di fnamelst] Ini lebih terkait untuk fungsi terbuka daripada md5 tapi saya pikir mungkin berguna untuk melaporkannya mengingat persyaratan untuk kompatibilitas lintas-platform yang dinyatakan di atas (lihat juga: docs.python.org/2/tutorial/… ).
BlueCoder
34
Saya jelas tidak menambahkan sesuatu yang pada dasarnya baru, tetapi menambahkan jawaban ini sebelum saya mengomentari status, ditambah wilayah kode membuat segalanya lebih jelas - lagi pula, khususnya untuk menjawab pertanyaan @ Nemo dari jawaban Omnifarious:
Saya kebetulan berpikir tentang checksum sedikit (datang ke sini mencari saran tentang ukuran blok, khususnya), dan telah menemukan bahwa metode ini mungkin lebih cepat daripada yang Anda harapkan. Mengambil yang tercepat (tetapi sangat khas) timeit.timeitatau /usr/bin/timehasil dari masing-masing dari beberapa metode checksumming file kira-kira. 11MB:
$ ./sum_methods.py
crc32_mmap(filename)0.0241742134094
crc32_read(filename)0.0219960212708
subprocess.check_output(['cksum', filename])0.0553209781647
md5sum_mmap(filename)0.0286180973053
md5sum_read(filename)0.0311000347137
subprocess.check_output(['md5sum', filename])0.0332629680634
$ time md5sum /tmp/test.data.300k
d3fe3d5d4c2460b5daacc30c6efbc77f /tmp/test.data.300k
real 0m0.043s
user 0m0.032s
sys 0m0.010s
$ stat -c '%s'/tmp/test.data.300k11890400
Jadi, sepertinya Python dan / usr / bin / md5sum membutuhkan sekitar 30ms untuk file 11MB. Fungsi yang relevan md5sum( md5sum_readdalam daftar di atas) sangat mirip dengan Omnifarious:
Memang, ini dari sekali jalan ( mmapyang selalu smidge lebih cepat ketika setidaknya beberapa selusin dibuat), dan milikku biasanya mendapat tambahan f.read(blocksize)setelah buffer habis, tapi itu cukup berulang dan menunjukkan bahwa md5sumpada baris perintah belum tentu lebih cepat dari implementasi Python ...
EDIT: Maaf atas keterlambatan yang lama, belum melihat ini dalam beberapa waktu, tetapi untuk menjawab pertanyaan @ EdRandall, saya akan menuliskan implementasi Adler32. Namun, saya belum menjalankan tolok ukur untuk itu. Pada dasarnya sama dengan CRC32: alih-alih init, memperbarui, dan mencerna panggilan, semuanya adalah zlib.adler32()panggilan:
Perhatikan bahwa ini harus dimulai dengan string kosong, karena jumlah Adler memang berbeda ketika mulai dari nol dibandingkan jumlah mereka "", yaitu 1- CRC dapat memulai dengan 0sebagai gantinya. The AND-ing diperlukan untuk membuat 32-bit unsigned integer, yang menjamin ia mengembalikan nilai yang sama di versi Python.
Bisakah Anda menambahkan beberapa baris membandingkan SHA1, dan juga zlib.adler32 mungkin?
Ed Randall
1
Fungsi md5sum () di atas mengasumsikan Anda memiliki akses tulis ke file. Jika Anda mengganti "r + b" di panggilan terbuka () dengan "rb" itu akan berfungsi dengan baik.
import hashlib
with open("your_filename.txt","rb")as f:
file_hash = hashlib.md5()while chunk := f.read(8192):
file_hash.update(chunk)print(file_hash.digest())print(file_hash.hexdigest())# to get a printable str instead of bytes
Pertimbangkan untuk menggunakan hashlib.blake2balih-alih md5(ganti saja md5dengan blake2bcuplikan di atas). Ini aman secara kriptografis dan lebih cepat dari MD5.
Hai! Harap tambahkan beberapa penjelasan ke kode Anda mengapa ini merupakan solusi untuk masalah ini. Selain itu, postingan ini sudah cukup tua, jadi Anda juga harus menambahkan beberapa informasi tentang mengapa solusi Anda menambahkan sesuatu yang belum ditangani orang lain.
d_kennetz
1
Ini cara memori lain yang tidak efisien
Erik Aronesty
-2
Saya pikir mengandalkan paket invoke dan md5sum binary sedikit lebih nyaman daripada paket subprocess atau md5
md5sum
?md5sum
. Itulah mengapa programmer yang sadar akan keamanan sebaiknya tidak menggunakannya menurut saya.md5sum
dan teknik yang dijelaskan dalam pertanyaan SO ini harus dihindari - lebih baik menggunakan SHA-2 atau SHA-3, jika mungkin: en.wikipedia.org/wiki/Secure_Hash_AlgorithmsJawaban:
Anda dapat menggunakan hashlib.md5 ()
Perhatikan bahwa terkadang Anda tidak dapat memasukkan seluruh file ke dalam memori. Dalam hal ini, Anda harus membaca potongan 4096 byte secara berurutan dan mengumpankannya ke
md5
metode:Catatan:
hash_md5.hexdigest()
akan mengembalikan representasi string hex untuk digest, jika Anda hanya perlu menggunakan byte yang dikemasreturn hash_md5.digest()
, sehingga Anda tidak perlu mengkonversi kembali.sumber
Ada cara yang cukup tidak efisien memori .
satu file:
daftar file:
Ingat, MD5 diketahui rusak dan tidak boleh digunakan untuk tujuan apa pun karena analisis kerentanan bisa sangat rumit, dan menganalisis kemungkinan penggunaan di masa depan yang mungkin dilakukan oleh kode Anda untuk masalah keamanan tidak mungkin. IMHO, itu harus dihapus dari perpustakaan sehingga semua orang yang menggunakannya terpaksa memperbarui. Jadi, inilah yang harus Anda lakukan sebagai gantinya:
Jika Anda hanya ingin mencerna 128 bit, Anda bisa melakukannya
.digest()[:16]
.Ini akan memberi Anda daftar tupel, masing-masing tupel berisi nama file dan hash-nya.
Sekali lagi saya sangat mempertanyakan penggunaan MD5 Anda. Anda harus setidaknya menggunakan SHA1, dan diberi kekurangan baru-baru ini ditemukan di SHA1 , bahkan mungkin tidak. Beberapa orang berpikir bahwa selama Anda tidak menggunakan MD5 untuk tujuan 'kriptografi', Anda baik-baik saja. Tetapi hal-hal memiliki kecenderungan untuk menjadi lebih luas dalam ruang lingkup daripada yang Anda harapkan, dan analisis kerentanan kasual Anda mungkin terbukti benar-benar cacat. Yang terbaik adalah membiasakan diri menggunakan algoritma yang tepat di luar gerbang. Itu hanya mengetik banyak huruf yang berbeda. Tidak sesulit itu.
Berikut ini cara yang lebih kompleks, tetapi hemat memori :
Dan, sekali lagi, karena MD5 rusak dan seharusnya tidak pernah benar-benar digunakan lagi:
Sekali lagi, Anda dapat melakukan
[:16]
panggilan setelah kehash_bytestr_iter(...)
jika Anda hanya ingin mencerna 128 bit.sumber
Saya jelas tidak menambahkan sesuatu yang pada dasarnya baru, tetapi menambahkan jawaban ini sebelum saya mengomentari status, ditambah wilayah kode membuat segalanya lebih jelas - lagi pula, khususnya untuk menjawab pertanyaan @ Nemo dari jawaban Omnifarious:
Saya kebetulan berpikir tentang checksum sedikit (datang ke sini mencari saran tentang ukuran blok, khususnya), dan telah menemukan bahwa metode ini mungkin lebih cepat daripada yang Anda harapkan. Mengambil yang tercepat (tetapi sangat khas)
timeit.timeit
atau/usr/bin/time
hasil dari masing-masing dari beberapa metode checksumming file kira-kira. 11MB:Jadi, sepertinya Python dan / usr / bin / md5sum membutuhkan sekitar 30ms untuk file 11MB. Fungsi yang relevan
md5sum
(md5sum_read
dalam daftar di atas) sangat mirip dengan Omnifarious:Memang, ini dari sekali jalan (
mmap
yang selalu smidge lebih cepat ketika setidaknya beberapa selusin dibuat), dan milikku biasanya mendapat tambahanf.read(blocksize)
setelah buffer habis, tapi itu cukup berulang dan menunjukkan bahwamd5sum
pada baris perintah belum tentu lebih cepat dari implementasi Python ...EDIT: Maaf atas keterlambatan yang lama, belum melihat ini dalam beberapa waktu, tetapi untuk menjawab pertanyaan @ EdRandall, saya akan menuliskan implementasi Adler32. Namun, saya belum menjalankan tolok ukur untuk itu. Pada dasarnya sama dengan CRC32: alih-alih init, memperbarui, dan mencerna panggilan, semuanya adalah
zlib.adler32()
panggilan:Perhatikan bahwa ini harus dimulai dengan string kosong, karena jumlah Adler memang berbeda ketika mulai dari nol dibandingkan jumlah mereka
""
, yaitu1
- CRC dapat memulai dengan0
sebagai gantinya. TheAND
-ing diperlukan untuk membuat 32-bit unsigned integer, yang menjamin ia mengembalikan nilai yang sama di versi Python.sumber
Dengan Python 3.8+ Anda bisa melakukannya
Pertimbangkan untuk menggunakan
hashlib.blake2b
alih-alihmd5
(ganti sajamd5
denganblake2b
cuplikan di atas). Ini aman secara kriptografis dan lebih cepat dari MD5.sumber
:=
Operator adalah "tugas operator" (baru ke Python 3.8+); ini memungkinkan Anda untuk menetapkan nilai di dalam ekspresi yang lebih besar; info lebih lanjut di sini: docs.python.org/3/whatsnew/3.8.html#assignment-expressionssumber
Saya pikir mengandalkan paket invoke dan md5sum binary sedikit lebih nyaman daripada paket subprocess atau md5
Ini tentu saja mengasumsikan Anda telah memohon dan md5sum diinstal.
sumber
path
adalah jalur yang disediakan pengguna, ini akan memungkinkan setiap pengguna menjalankan perintah bash sewenang-wenang di sistem Anda.