একটি ফাইলের MD5 চেকসাম তৈরি করা হচ্ছে


348

পাইথনের ফাইলগুলির তালিকার এমডি 5 চেকসাম উত্পন্ন করার (এবং পরীক্ষা করার) কোনও সহজ উপায় আছে কি? (আমার একটি ছোট প্রোগ্রাম রয়েছে যা আমি কাজ করছি এবং আমি ফাইলগুলির চেকসামগুলি নিশ্চিত করতে চাই)।


3
শুধু ব্যবহার md5sumকরবেন না কেন ?
কেনেটিএম

99
পাইথনে এটি রাখা ক্রস-প্ল্যাটফর্মের সামঞ্জস্যতা পরিচালনা করা আরও সহজ করে তোলে।
আলেকজান্ডার

আপনি যদি "প্রগতি বার * বা অনুরূপ (খুব বড় ফাইলগুলির জন্য) দিয়ে ডি সলিউশন চান তবে এই সমাধানটি বিবেচনা করুন: স্ট্যাকওভারফ্লো
লরেন্ট ল্যাপার্ট

1
@kennytm আপনি প্রদত্ত লিঙ্কটি দ্বিতীয় অনুচ্ছেদে এটি বলে: বর্ণনা করার সময় "অন্তর্নিহিত MD5 অ্যালগরিদম আর নিরাপদ বলে মনে হয় না" md5sum। এজন্য সুরক্ষিত সচেতন প্রোগ্রামারদের আমার মতে এটি ব্যবহার করা উচিত নয়।
ডিবাগ 255

1
@ ডিবাগ 255 ভাল এবং বৈধ পয়েন্ট। md5sumএই এসও প্রশ্নে বর্ণিত কৌশল এবং উভয়ই এড়ানো উচিত - যদি সম্ভব হয় তবে SHA-2 বা SHA-3 ব্যবহার করা ভাল: en.wikedia.org/wiki/Secure_Hash_Algorithms
Per Lundberg

উত্তর:


463

আপনি hashlib.md5 () ব্যবহার করতে পারেন

মনে রাখবেন যে কখনও কখনও আপনি পুরো ফাইলটিকে মেমরিতে ফিট করতে পারবেন না। সেক্ষেত্রে আপনাকে ধারাবাহিকভাবে 4096 বাইটের অংশগুলি পড়তে হবে এবং এগুলি md5পদ্ধতিতে খাওয়াতে হবে :

import hashlib
def md5(fname):
    hash_md5 = hashlib.md5()
    with open(fname, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

দ্রষ্টব্য: ডাইজেস্টের জন্য হেক্স স্ট্রিং প্রতিনিধিত্ব hash_md5.hexdigest()ফিরিয়ে দেবে , যদি আপনার কেবল প্যাকযুক্ত বাইট ব্যবহারের প্রয়োজন হয় , যাতে আপনাকে ফিরে রূপান্তর করতে হবে না।return hash_md5.digest()


297

এমন একটি উপায় রয়েছে যা বেশ স্মৃতিশক্তি অক্ষম

বিক্ষিপ্ত নথি:

import hashlib
def file_as_bytes(file):
    with file:
        return file.read()

print hashlib.md5(file_as_bytes(open(full_path, 'rb'))).hexdigest()

ফাইলগুলির তালিকা:

[(fname, hashlib.md5(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]

যদিও স্মরণ করুন, এমডি 5 ভাঙ্গা হিসাবে পরিচিত এবং কোনও উদ্দেশ্যেই ব্যবহার করা উচিত নয় যেহেতু দুর্বলতা বিশ্লেষণটি সত্যই মুশকিল হতে পারে এবং সুরক্ষার সমস্যাগুলির জন্য আপনার কোড ব্যবহার করা যেতে পারে এমন কোনও সম্ভাব্য ভবিষ্যতের ব্যবহার বিশ্লেষণ করা অসম্ভব। আইএমএইচও, এটি গ্রন্থাগার থেকে সরিয়ে ফেলা উচিত যাতে এটি ব্যবহার করা প্রত্যেককে আপডেট করতে বাধ্য করা হয়। সুতরাং, পরিবর্তে আপনার যা করা উচিত তা এখানে:

[(fname, hashlib.sha256(file_as_bytes(open(fname, 'rb'))).digest()) for fname in fnamelst]

আপনি যদি চান তবে 128 বিট মূল্যের ডাইজেস্ট আপনি করতে পারেন .digest()[:16]

এটি আপনাকে টিপলগুলির একটি তালিকা দেবে, প্রতিটি টিপল এর ফাইলের নাম এবং এর হ্যাশযুক্ত।

আবার আমি আপনার এমডি 5 ব্যবহারের বিষয়ে দৃ strongly়তার সাথে প্রশ্ন করছি। আপনার কমপক্ষে SHA1 ব্যবহার করা উচিত এবং SHA1 এ সন্ধান করা সাম্প্রতিক ত্রুটিগুলি দেওয়া উচিত , সম্ভবত এটিও নয়। কিছু লোক মনে করেন যে আপনি 'ক্রিপ্টোগ্রাফিক' উদ্দেশ্যে এমডি 5 ব্যবহার করছেন না ততক্ষণ আপনি ভাল আছেন। তবে স্টাফের প্রবণতা রয়েছে আপনি প্রারম্ভিকভাবে প্রত্যাশার চেয়ে সুযোগে আরও বিস্তৃত হবেন এবং আপনার নৈমিত্তিক দুর্বলতার বিশ্লেষণ সম্পূর্ণ ত্রুটিযুক্ত প্রমাণিত হতে পারে। গেট থেকে ঠিক সঠিক অ্যালগরিদম ব্যবহার করার অভ্যাসে প্রবেশ করা ভাল। এটি কেবল অক্ষরের একটি গুচ্ছ টাইপ করা সব হয়। এটা খুব কঠিন নয়।

এখানে এমন একটি উপায় যা আরও জটিল, তবে মেমরির দক্ষ :

import hashlib

def hash_bytestr_iter(bytesiter, hasher, ashexstr=False):
    for block in bytesiter:
        hasher.update(block)
    return hasher.hexdigest() if ashexstr else hasher.digest()

def file_as_blockiter(afile, blocksize=65536):
    with afile:
        block = afile.read(blocksize)
        while len(block) > 0:
            yield block
            block = afile.read(blocksize)


[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.md5()))
    for fname in fnamelst]

এবং আবারও, যেহেতু MD5 টি নষ্ট হয়ে গেছে এবং সত্যই আর ব্যবহার করা উচিত নয়:

[(fname, hash_bytestr_iter(file_as_blockiter(open(fname, 'rb')), hashlib.sha256()))
    for fname in fnamelst]

আবার, আপনি যদি [:16]কলটি করতে hash_bytestr_iter(...)চান তবে যদি আপনি কেবল 128 বিট মূল্যের ডাইজেস্ট চান।


66
ফাইলটি দূষিত নয় তা নিশ্চিত করার জন্য আমি কেবল এমডি 5 ব্যবহার করছি। এটি ভেঙে যাওয়ার বিষয়ে আমি তেমন উদ্বিগ্ন নই।
আলেকজান্ডার

87
@ দ্য লাইফলেসঅন: এবং @ সর্বজনীন ভয়ঙ্কর সতর্কতা সত্ত্বেও, এমডি 5 এর এটি পুরোপুরি ভাল ব্যবহার।
রাষ্ট্রপতি জেমস কে পোলক

22
@ গ্রেগস, @ দ্য লাইফলেসঅন - হ্যাঁ, এবং পরবর্তী জিনিস আপনি জানেন যে কেউ আপনার অ্যাপ্লিকেশন সম্পর্কে এই সত্যটি ব্যবহার করার জন্য কোনও ফাইল খুঁজে পেয়েছেন যখন কোনও ফাইল যখন আপনি একেবারেই প্রত্যাশা করছেন না তখন এটি অনাবৃত হিসাবে গ্রহণযোগ্য হতে পারে। না, আমি আমার ভীতিজনক সতর্কতার পাশে দাঁড়িয়েছি। আমি মনে করি MD5 মুছে ফেলা উচিত বা অবচয় সতর্কতা সহ আসা উচিত।
সর্বময়ী

10
আমি সম্ভবত। ডাইজেস্ট () এর পরিবর্তে .hexdigest () ব্যবহার করতাম - মানুষের পক্ষে পড়া সহজ - যা ওপি এর উদ্দেশ্য।
zbstof

21
আমি এই সমাধানটি ব্যবহার করেছি তবে এটি ভুলভাবে দুটি পৃথক পিডিএফ ফাইলের জন্য একই হ্যাশ দিয়েছে। সমাধানটি ছিল বাইনারি মোড নির্দিষ্ট করে ফাইলগুলি খোলার জন্য, যা হ'ল: [(fname, hashlib.md5 (ওপেন (নাম, 'rb' ) .প্রেড ())। ফেক্সেলস্টে নামকরণের জন্য হেক্সডিজাস্ট ())] এটি আরও সম্পর্কিত এমডি 5 এর চেয়ে মুক্ত ক্রিয়াকলাপে তবে আমি ভেবেছিলাম উপরে উল্লিখিত ক্রস-প্ল্যাটফর্মের সামঞ্জস্যতার প্রয়োজনীয়তা প্রদত্ত এটি রিপোর্ট করা কার্যকর হতে পারে (এছাড়াও দেখুন: ডকস.পিথথন.আর / / টিউটোরিয়াল/… )।
ব্লু কোডার

34

আমি পরিষ্কারভাবে মৌলিকভাবে নতুন কিছু যোগ করছি না, তবে আমি মন্তব্য উত্তর দেওয়ার আগে এই উত্তরটি যুক্ত করেছি, এবং কোড অঞ্চলগুলি বিষয়গুলিকে আরও স্পষ্ট করে তোলে - যাইহোক, বিশেষত সর্বজ্ঞতার উত্তর থেকে নিমোর প্রশ্নের উত্তর দেওয়ার জন্য:

আমি চেকসামগুলি সম্পর্কে কিছুটা ভাবছিলাম (ব্লকের আকারগুলি সম্পর্কে বিশেষত পরামর্শের জন্য এখানে এসেছি), এবং আমি পেয়েছি যে এই পদ্ধতিটি আপনার প্রত্যাশার চেয়ে দ্রুত হতে পারে। প্রায় দ্রুত (তবে বেশ সাধারণ) গ্রহণ করা timeit.timeitবা /usr/bin/timeপ্রায় একটি ফাইল চেকসুম করার বিভিন্ন পদ্ধতির প্রতিটি থেকে ফলাফল। 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.300k
11890400

সুতরাং, দেখে মনে হচ্ছে পাইথন এবং / usr / bin / md5sum উভয়ই 11MB ফাইলের জন্য 30 মিমি নিয়ে থাকে। প্রাসঙ্গিক md5sumফাংশন ( md5sum_readউপরের তালিকায়) সর্বশক্তিমানের সাথে বেশ অনুরূপ:

import hashlib
def md5sum(filename, blocksize=65536):
    hash = hashlib.md5()
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            hash.update(block)
    return hash.hexdigest()

মঞ্জুরিপ্রাপ্ত, এটি একক রান থেকে হয় ( mmapকমপক্ষে কয়েক ডজন রান করা হলে এটি সর্বদা দ্রুততর হয়) এবং f.read(blocksize)বাফার শেষ হয়ে যাওয়ার পরে আমার সাধারণত অতিরিক্ত অতিরিক্ত হয়ে যায়, তবে এটি যুক্তিসঙ্গত পুনরাবৃত্তিযোগ্য এবং দেখায় যে md5sumকমান্ড লাইনে রয়েছে অজগর বাস্তবায়নের চেয়ে দ্রুত প্রয়োজন হয় না ...

সম্পাদনা: দীর্ঘ বিলম্বের জন্য দুঃখিত, কিছু সময় এটির দিকে নজর দেওয়া হয়নি, তবে @ এডরান্ডাল এর প্রশ্নের উত্তর দেওয়ার জন্য, আমি একটি অ্যাডলার 32 বাস্তবায়ন লিখব। যাইহোক, আমি এর জন্য মানদণ্ড পরিচালনা করি না। এটি মূলত সিআরসি 32 এর মতোই ছিল: আরকি, আপডেট এবং ডাইজেস্ট কলগুলির পরিবর্তে সমস্ত কিছু zlib.adler32()কল:

import zlib
def adler32sum(filename, blocksize=65536):
    checksum = zlib.adler32("")
    with open(filename, "rb") as f:
        for block in iter(lambda: f.read(blocksize), b""):
            checksum = zlib.adler32(block, checksum)
    return checksum & 0xffffffff

নোট করুন যে এটি অবশ্যই শূন্য স্ট্রিং দিয়ে শুরু করা উচিত, কারণ অ্যাডলারের যোগফলগুলি শূন্য থেকে বনাম যখন তাদের যোগফলের চেয়ে আলাদা হয় তবে ""এটি হয় 1- 0পরিবর্তে সিআরসি শুরু করতে পারে । AND-Ing এটি একটি 32 বিট স্বাক্ষরবিহীন পূর্ণসংখ্যা, যা এটি পাইথন সংস্করণ জুড়ে একই মান নিশ্চিত করে করতে প্রয়োজন হয়।


আপনি কি সম্ভবত SHA1 এর সাথে তুলনা করে কয়েকটি লাইন যুক্ত করতে পারেন, এবং zlib.adler32 সম্ভবত?
এড র্যান্ডাল

1
উপরের md5sum () ফাংশনটি ধরে নিয়েছে যে আপনার কাছে ফাইলটিতে লেখার অ্যাক্সেস রয়েছে। যদি আপনি "আরবি" দিয়ে খোলা () কলটিতে "আর + বি" প্রতিস্থাপন করেন তবে এটি দুর্দান্ত কাজ করবে।
কেভিন লিডা

1
@ এডরানডাল: অ্যাডলার 32 আসলে বিরক্ত করার মতো নয় eg leviathansecurity.com/blog/analysis-of-adler32
MikeW

6

পাইথন 3.8+ এ আপনি করতে পারেন

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

এর hashlib.blake2bপরিবর্তে md5(কেবলমাত্র উপরের স্নিপেটের md5সাথে প্রতিস্থাপন করুন) ব্যবহার করার কথা বিবেচনা করুন blake2b। এটি ক্রিপ্টোগ্রাফিকভাবে সুরক্ষিত এবং MD5 এর চেয়ে দ্রুত


:=অপারেটর একটি "নিয়োগ অপারেটর" (পাইথন 3.8+ নতুন) হয়; এটি আপনাকে বৃহত্তর অভিব্যক্তির ভিতরে মানগুলি নির্ধারণ করতে দেয়; এখানে আরও তথ্য: docs.python.org/3/whatsnew/3.8.html#assignment- এক্সপ্রেশন
বেঞ্জামিন

0
hashlib.md5(pathlib.Path('path/to/file').read_bytes()).hexdigest()

3
ওহে! কেন এটি সমস্যার সমাধান এটি সম্পর্কে আপনার কোডটিতে কিছু ব্যাখ্যা যুক্ত করুন। তদ্ব্যতীত, এই পোস্টটি বেশ পুরানো, সুতরাং আপনার সমাধানটি কেন এমন কিছু যুক্ত করে যা অন্যরা ইতিমধ্যে সম্বোধন করেনি সে সম্পর্কেও আপনাকে কিছু তথ্য যুক্ত করা উচিত।
d_kennetz

1
এটি আর একটি স্মৃতিশক্তির অযোগ্য উপায়
এরিক অ্যারোনস্টি

-2

আমি মনে করি সাব-প্রসেস বা এমডি 5 প্যাকেজের চেয়ে চালান প্যাকেজ এবং এমডি 5সাম বাইনারি নির্ভর করা কিছুটা বেশি সুবিধাজনক

import invoke

def get_file_hash(path):

    return invoke.Context().run("md5sum {}".format(path), hide=True).stdout.split(" ")[0]

এটি অবশ্যই ধরে নিয়েছে যে আপনি চালনা এবং এমডি 5সাম ইনস্টল করেছেন।


3
যদি pathকোনও ব্যবহারকারী সরবরাহিত পথ হয় তবে এটি কোনও ব্যবহারকারীকে আপনার সিস্টেমে নির্বিচারে বাশ কমান্ড কার্যকর করতে দেবে।
বরিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.