为什么Python计算的"hashlib.sha1"与文件的"git hash-object"不同?

Ikk*_*kke 45 python git hash

我正在尝试计算文件的SHA-1值.

我编造了这个脚本:

def hashfile(filepath):
    sha1 = hashlib.sha1()
    f = open(filepath, 'rb')
    try:
        sha1.update(f.read())
    finally:
        f.close()
    return sha1.hexdigest()
Run Code Online (Sandbox Code Playgroud)

对于特定文件,我得到这个哈希值:
8c3e109ff260f7b11087974ef7bcdbdc69a0a3b9
但是当我用git hash_object计算值时,我得到这个值: d339346ca154f6ed9e92205c3c5c38112e761eb7

他们怎么不一样?我做错了什么,或者我可以忽略它的区别?

Bri*_*ndy 51

git计算这样的哈希:

sha1("blob " + filesize + "\0" + data)
Run Code Online (Sandbox Code Playgroud)

参考

  • 应该提到git这样做是为了避免长度扩展攻击. (13认同)
  • 完全实施这个建议可以在问题中找到[分配混帐SHA1的不混帐(http://stackoverflow.com/a/552725/42473). (3认同)

Ben*_*Ben 32

作为参考,这是一个更简洁的版本:

def sha1OfFile(filepath):
    import hashlib
    with open(filepath, 'rb') as f:
        return hashlib.sha1(f.read()).hexdigest()
Run Code Online (Sandbox Code Playgroud)

第二个想法:虽然我从来没有见过它,但我认为有可能f.read()返回少于完整文件或数千兆字节文件,因为f.read()内存不足.对于每个人的启发,让我们考虑如何解决这个问题:第一个解决方法是:

def sha1OfFile(filepath):
    import hashlib
    sha = hashlib.sha1()
    with open(filepath, 'rb') as f:
        for line in f:
            sha.update(line)
        return sha.hexdigest()
Run Code Online (Sandbox Code Playgroud)

但是,根本无法保证'\n'文件中出现,因此for循环将为我们提供结束文件块的事实'\n'可能会给我们带来与原来相同的问题.遗憾的是,我没有看到任何类似的Pythonic方法来尽可能大地迭代文件块,我认为这意味着我们遇到了一个while True: ... break循环并且块大小的幻数:

def sha1OfFile(filepath):
    import hashlib
    sha = hashlib.sha1()
    with open(filepath, 'rb') as f:
        while True:
            block = f.read(2**10) # Magic number: one-megabyte blocks.
            if not block: break
            sha.update(block)
        return sha.hexdigest()
Run Code Online (Sandbox Code Playgroud)

当然,谁能说我们可以存储一兆字节的字符串.我们可能会,但如果我们在一台小型嵌入式计算机上呢?

我希望我能想到一种更清洁的方式,保证不会在大量文件上耗尽内存,并且没有神奇的数字,并且性能与原始简单的Pythonic解决方案一样好.