当前位置:  开发笔记 > 编程语言 > 正文

生成文件的MD5校验和

如何解决《生成文件的MD5校验和》经验,为你挑选了3个好方法。

有没有简单的方法来生成(和检查)Python中文件列表的MD5校验和?(我有一个小程序,我正在研究,我想确认文件的校验和).



1> quantumSoup..:

你可以使用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()

注意: 如果您只需要使用压缩字节,hash_md5.hexdigest()则将返回摘要的十六进制字符串表示形式return hash_md5.digest(),因此您无需转换回来.


@MartinThoma--这是在7.5年前写的,乘以32左右.

2> Omnifarious..:

有一种方式是非常低效的内存.

单个文件:

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已知故障,不应该用于任何目的,因为漏洞分析可能非常棘手,并且分析任何可能的未来使用,您的代码可能会被用于安全问题是不可能的.恕我直言,它应该是从图书馆中删除的,所以每个使用它的人都被迫更新.所以,这是你应该做的事情:

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

如果你只想要128位的摘要,你可以做到.digest()[:16].

这将为您提供元组列表,每个元组包含其文件名及其哈希值.

我再次强烈质疑你对MD5的使用.您应该至少使用SHA1,并且考虑到在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]

同样,如果你只需要128位的摘要,你可以[:16]在调用之后hash_bytestr_iter(...).


@TheLifelessOne:尽管有@Omnifarious可怕的警告,但这完全可以很好地利用MD5.
我只使用MD5来确认文件没有损坏.我不是那么担心它被打破了.
我使用了这个解决方案,但它没有正确地为两个不同的pdf文件提供相同的哈希值.解决方案是通过指定二进制模式来打开文件,即:[(fname,hashlib.md5(open(fname,**'rb'**).read()).hexdingest())for fname in fnamelst]这与open函数比md5更相关,但我认为根据上面提到的跨平台兼容性要求报告它可能是有用的(另请参阅:http://docs.python.org/2/tutorial/inputoutput. HTML#读取与写入文件).
@GregS,@ TheLifelessOne - 是的,接下来你知道有人找到了一种方法来使用这个关于你的应用程序的事实,当文件不是你期望的文件时,它会被接受为未损坏的文件.不,我支持我可怕的警告.我认为应删除MD5或附带弃用警告.
我可能会使用.hexdigest()而不是.digest() - 人类更容易阅读 - 这是OP的目的.
@Omnifarious说"从Python库中删除MD5"或甚至只是说"向Python库添加弃用警告"就像是说"不应该使用Python,如果现有的东西需要MD5,请使用其他东西".当然,解释文档中的安全隐患,但删除甚至只是弃用是疯狂的建议.
@hyde:必须要做些什么才能让人们停止使用这种愚蠢的算法.即使在我证明它创建了安全漏洞(不可否认的是相当模糊的漏洞)并且SHA在OpenSSL(我们正在使用的库)中实现更快的实现之后,我仍然有使用它的工作.这太疯狂了.
提醒:MD5的已知弱点是碰撞攻击,而**不是*[preimage攻击](http://en.wikipedia.org/wiki/Preimage_attack),因此它适用于某些加密应用程序而不适用于其他加密应用程序.如果您不知道差异,则不应该使用它,但不要完全丢弃它.见http://www.vpnc.org/hash.html.
在那些列表推导中_not close_打开文件是否可以?
整个人生都围绕着“我认为在这种情况下我可以摆脱它”-或更客观地说,“风险管理”适用于*所有*密码系统,包括MD5和SHA1。阅读有关[MD5前映像攻击]的最新技术(https://crypto.stackexchange.com/questions/41860/pre-image-attack-on-md5-hash/41865)。我不会在家里的所有窗户上都放酒吧,并且在进行花园式完整性检查时不使用恶意对手(例如,将文件从一台PC复制到另一台PC)时,我会使用MD5。
我不会继续讨论,您只是在思想上拒绝MD5。
对于在同一个文件句柄上多次使用`def hashfile`函数的人,记得在读完每个文件时重置`afile`指针.例如.`afile.seek(0)`
是的,我想问同样的事情.这里不是关闭()吗?
不。抱歉。不好比喻。

3> 小智..:

我显然没有添加任何根本新的东西,但在我评论状态之前添加了这个答案,加上代码区域使事情变得更清楚 - 无论如何,专门回答来自Omnifarious的答案的@ Nemo的问题:

我碰巧考虑了一些校验和(来这里寻找有关块大小的建议,特别是),并且发现这种方法可能比你预期的要快.采用最快(但非常典型)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

因此,看起来Python和/ usr/bin/md5sum对于11MB文件大约需要30ms.相关md5sum功能(md5sum_read在上面的清单中)与Omnifarious非常相似:

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在命令行上显示不一定比Python实现更快......

编辑:很抱歉长时间的延迟,有一段时间没有看过这个,但回答@ EdRandall的问题,我会写下Adler32的实现.但是,我没有为它运行基准测试.它与CRC32基本相同:不是init,update和digest调用,一切都是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- CRC可以从而开始0.AND需要使用-ing使其成为32位无符号整数,这可确保它在Python版本中返回相同的值.

推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有