10

我正在尝试计算/验证压缩 bzip2 档案的 CRC32 校验和。

.magic:16                       = 'BZ' signature/magic number
.version:8                      = 'h' for Bzip2 ('H'uffman coding)
.hundred_k_blocksize:8          = '1'..'9' block-size 100 kB-900 kB

.compressed_magic:48            = 0x314159265359 (BCD (pi))
.crc:32                         = checksum for this block
...
... 
.eos_magic:48                   = 0x177245385090 (BCD sqrt(pi))
.crc:32                         = checksum for whole stream
.padding:0..7                   = align to whole byte

http://en.wikipedia.org/wiki/Bzip2

所以我知道 CRC 校验和在 bz2 文件中的位置,但我将如何验证它们。我应该binascii.crc32()获得哪些 CRC?我已经尝试逐字节计算各种块的 CRC,但没有设法得到匹配。

谢谢你。我将研究 bzip2 源代码和bz2Python 库代码,可能会找到一些东西,尤其是在decompress()方法中。

更新1:

据我所知,块头由以下标签标识。但是微小的 bz2 文件不包含 ENDMARK 文件。(感谢adw,我们发现应该寻找 ENDMARK 的位移位值,因为压缩数据没有填充到字节。)

#define BLOCK_HEADER_HI  0x00003141UL
#define BLOCK_HEADER_LO  0x59265359UL

#define BLOCK_ENDMARK_HI 0x00001772UL
#define BLOCK_ENDMARK_LO 0x45385090UL

这是从bzlib2recover.c源头开始的,块似乎总是从第 80 位开始,就在 CRC 校验和之前,应该从 CRC 计算中省略,因为不能将自己的 CRC CRC 为相同的 CRC(你明白我的意思) .

searching for block boundaries ...
block 1 runs from 80 to 1182

查看计算这个的代码。

更新 2:

bzlib2recover.c没有CRC计算功能,它只是从损坏的文件中复制CRC。但是,我确实设法在 Python 中复制了块计算器功能,以标记bz2压缩文件中每个块的开始和结束位。回到正轨,我发现它compress.c指的是bzlib_private.h.

#define BZ_INITIALISE_CRC(crcVar) crcVar = 0xffffffffL;
#define BZ_FINALISE_CRC(crcVar) crcVar = ~(crcVar);
#define BZ_UPDATE_CRC(crcVar,cha)              \
{                                              \
   crcVar = (crcVar << 8) ^                    \
            BZ2_crc32Table[(crcVar >> 24) ^    \
                           ((UChar)cha)];      \
}

这些定义也被访问bzlib.cs->blockCRC在 中初始化和更新,在 中bzlib.c完成compress.c。有超过 2000 行 C 代码,这需要一些时间来查看并弄清楚哪些内容可以输入,哪些内容不可以。我也将C标签添加到问题中。

顺便说一下,这里是 bzip2 的 C 源代码http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz

更新 3:

原来bzlib2块 CRC32 是使用以下算法计算的:

dataIn是要编码的数据。

crcVar = 0xffffffff # Init
    for cha in list(dataIn):
        crcVar = crcVar & 0xffffffff # Unsigned
        crcVar = ((crcVar << 8) ^ (BZ2_crc32Table[(crcVar >> 24) ^ (ord(cha))]))

    return hex(~crcVar & 0xffffffff)[2:-1].upper()

其中 BZ2_crc32Table 定义在crctable.c

对于dataIn = "justatest"返回的 CRC 7948C8CB,使用该数据压缩文本文件后,bz2 文件中的 crc:32 校验和79 48 c8 cb是匹配的。

结论:

bzlib2 CRC32 是(引用crctable.c

由 Rob Warnock 在 comp.compression FAQ 的第 51 节中模糊地派生出来...

...因此,据我了解,不能使用标准 CRC32 校验和计算器预先计算/验证,而是需要bz2lib实现(第 155-172 行bzlib_private.h)。

4

2 回答 2

3

以下是 使用的 CRC 算法bzip2,用 Python 编写:

crcVar = 0xffffffff # Init
    for cha in list(dataIn):
        crcVar = crcVar & 0xffffffff # Unsigned
        crcVar = ((crcVar << 8) ^ (BZ2_crc32Table[(crcVar >> 24) ^ (ord(cha))]))

    return hex(~crcVar & 0xffffffff)[2:-1].upper()

(C 代码定义可以在第 155-172 行找到bzlib_private.h

BZ2_crc32Table数组/列表可以在crctable.cbzip2代码中找到。此 CRC 校验和算法引用:“.. 模糊地源自 Rob Warnock 的代码,在 comp.compression FAQ 的第 51 节......”crctable.c

校验和是在未压缩的数据上计算的。

源代码可以在这里下载:http: //www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz

于 2010-12-21T06:18:19.190 回答
0

要添加到现有答案,在流的末尾有一个最终校验和(之后的那个eos_magic)它用作所有单个 Huffman 块校验和的校验和。它被初始化为零。每次您完成对现有 Huffman 块校验和的验证时,它都会更新。要更新它,请执行以下操作:

crc: u32 = # latest validated Huffman block CRC
ccrc: u32 = # current combined checksum

ccrc = (ccrc << 1) | (ccrc >> 31);
ccrc ^= crc;

ccrc最后,根据您从压缩文件中读取的 32 位无符号值验证 的值。

于 2021-01-15T07:42:27.200 回答