Генерация контрольной суммы MD5 файла

есть ли простой способ генерации (и проверки) контрольных сумм MD5 списка файлов в Python? (У меня есть небольшая программа, Я работаю, и я хотел бы подтвердить, контрольные суммы файлов).

3 ответов


вы можете использовать hashlib.md5()

обратите внимание, что иногда вы не сможете поместить весь файл в память. В этом случае вам придется последовательно читать куски 4096 байт и передавать их функции Md5:

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

есть способ, который довольно памяти неэффективное.

один файл:

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]

но, MD5, как известно, сломан и (IMHO) должен прийти со страшными предупреждениями об осуждении и удален из библиотеки, так что вот как вы должны это сделать:

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

если вы хотите только 128 бит дайджеста, вы можете сделать .digest()[:16].

это даст вам список кортежей, каждый кортеж, содержащий имя файла и его хэш.

снова я сильно сомневаюсь в вашем использовании MD5. Вы должны хотя бы использовать SHA1. Некоторые люди думают, что пока вы не используете MD5 для 'шифрования' ты в порядке. Но материал имеет тенденцию в конечном итоге быть более широким по охвату, чем вы изначально ожидаете, и ваш случайный анализ уязвимости может оказаться полностью ошибочным. Лучше всего просто привыкнуть использовать правильный алгоритм выхода из ворот. Это просто набирать другую кучу письма-это все. Это не так уж сложно.

вот способ, который является более сложным, но эффективная память:

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 бит дайджеста.


я явно не добавляю ничего принципиально нового, но добавил этот ответ, прежде чем я был до статуса комментирования: -), плюс регионы кода делают вещи более ясными-во всяком случае, в частности, чтобы ответить на вопрос @Nemo из ответа Omnifarious:

я немного думал о контрольных суммах (пришел сюда в поисках предложений по размерам блоков, в частности) и обнаружил, что этот метод может быть быстрее, чем вы ожидали. Принимая самый быстрый (но довольно типичный) timeit.timeit или /usr/bin/time результат каждого из нескольких методов контрольной суммы файла ок. 11МБ:

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

Итак, похоже, что Python и / usr/bin / md5sum занимают около 30 мс для файла 11 Мб. Соответствующий