在Python中无需解压缩即可计算zip内容的CRC32,MD5和SHA1

par*_*adf 6 python hash crc32 md5 sha1

我需要计算zip文件内容的CRC32,MD5和SHA1而不解压缩它们.

到目前为止,我发现了如何为zip文件本身计算这些,例如:

CRC32:

import zlib


zip_name = "test.zip"


def Crc32Hasher(file_path):

    buf_size = 65536
    crc32 = 0

    with open(file_path, 'rb') as f:
        while True:
            data = f.read(buf_size)
            if not data:
                break
            crc32 = zlib.crc32(data, crc32)

    return format(crc32 & 0xFFFFFFFF, '08x')


print(Crc32Hasher(zip_name))
Run Code Online (Sandbox Code Playgroud)

SHA1 :( MD5同样)

import hashlib


zip_name = "test.zip"


def Sha1Hasher(file_path):

    buf_size = 65536
    sha1 = hashlib.sha1()

    with open(file_path, 'rb') as f:
        while True:
            data = f.read(buf_size)
            if not data:
                break
            sha1.update(data)

    return format(sha1.hexdigest())


print(Sha1Hasher(zip_name))
Run Code Online (Sandbox Code Playgroud)

对于zip文件的内容,我可以直接从zip读取CRC32,无需计算如下:

阅读zip内容的CRC32:

import zipfile

zip_name = "test.zip"

if zip_name.lower().endswith(('.zip')):
    z = zipfile.ZipFile(zip_name, "r")

for info in z.infolist():

    print(info.filename,
          format(info.CRC & 0xFFFFFFFF, '08x'))
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何计算zip文件内容的SHA1(或MD5)而不先解压缩它们.这有可能吗?

Mar*_*rat 6

这不可能。之所以可以得到CRC,是因为在创建归档文件时已为您仔细地对其进行了预先计算(用于完整性检查)。任何其他校验和/哈希都必须从头算起,并且至少需要流式传输归档内容,即解压缩。

UPD:可能的实现

libarchive:额外的依赖项,支持多种存档格式

import libarchive.public as libarchive
with libarchive.file_reader(fname) as archive:
    for entry in archive:
        md5 = hashlib.md5()
        for block in entry.get_blocks():
            md5.update(block)
        print(str(entry), md5.hexdigest())
Run Code Online (Sandbox Code Playgroud)

本机zipfile:无依赖项,仅压缩

import zipfile

archive = zipfile.ZipFile(fname)
blocksize = 1024**2  #1M chunks
for fname in archive.namelist():
    entry = archive.open(fname)
    md5 = hashlib.md5()
    while True:
        block = entry.read(blocksize)
        if not block:
            break
        md5.update(block)
    print(fname, md5.hexdigest())
Run Code Online (Sandbox Code Playgroud)