Вычислить / проверить bz2 (bzip2) CRC32 в Python

Я пытаюсь вычислить / проверить контрольные суммы CRC32 для сжатых архивов bzip2.

.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 и bz2 Код библиотеки Python, чтобы найти что-то, особенно в 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.c также, s->blockCRC инициализируется и обновляется в bzlib.c и завершено в compress.c, Существует более 2000 строк кода на C, которые займут некоторое время, чтобы просмотреть и выяснить, что входит, а что нет. Я добавляю C отметьте к вопросу также.

Кстати, вот источники C для bzip2 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, сжав текстовый файл с этими данными, контрольная сумма crc:32 внутри файла bz2 79 48 c8 cb который совпадает.

Заключение:

bzlib2 CRC32 есть (цитирую crctable.c)

Неопределенно полученный из кода Роба Уорнока, в Разделе 51 часто задаваемых вопросов о comp.compression...

... таким образом, насколько я понимаю, не может быть предварительно рассчитан / проверен с использованием стандартных калькуляторов контрольной суммы CRC32, а скорее требует bz2lib реализация (строки 155-172 в bzlib_private.h).

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.c от bzip2 исходный код. Этот алгоритм контрольной суммы CRC цитируется следующим образом: "... смутно получен из кода Роба Уорнока в Разделе 51 FAQ по comp.compression..." (crctable.c)

Контрольные суммы рассчитываются по несжатым данным.

Источники можно скачать здесь: http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz

Проверьте библиотеку python fastcrc, в которой реализована реализация bzip2 crc32.

https://fastcrc.readthedocs.io/en/latest/#fastcrc.crc32.bzip2

Чтобы добавить к существующему ответу, в конце потока есть окончательная контрольная сумма (тот, что после ) Он функционирует как контрольная сумма для всех контрольных сумм отдельных блоков Хаффмана. Он инициализируется нулем. Он обновляется каждый раз, когда вы заканчиваете проверку существующей контрольной суммы блока Хаффмана. Чтобы обновить его, сделайте следующее:

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

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

В конце подтвердите значение против 32-битного значения без знака, которое вы читаете из сжатого файла.

Другие вопросы по тегам