Расчет Ethernet CRC32 - программное против алгоритмического результата

Я пытаюсь вычислить последовательность проверки кадра (FCS) пакета Ethernet побайтно. Полином равен 0x104C11DB7. Я следовал алгоритму XOR-SHIFT, показанному здесь http://en.wikipedia.org/wiki/Cyclic_redundancy_check или здесь http://www.woodmann.com/fravia/crctut1.htm

Предположим, что информация, которая должна иметь CRC, составляет всего один байт. Допустим, это 0x03.

  1. step: pad с 32 битами вправо

    0x0300000000

  2. выровняйте многочлен и данные в левой части с их первым битом, который не равен нулю, и xor их

    0x300000000 xor 0x209823B6E = 0x109823b6e

  3. возьмите остаток, выровняйте и снова xor

    0x109823b6e xor 0x104C11DB7 = 0x0d4326d9

Поскольку битов больше не осталось, CRC32 0x03 должен быть 0x0d4326d9

К сожалению, все программные реализации говорят мне, что я ошибаюсь, но что я сделал не так или что они делают по-другому?

Python говорит мне:

 "0x%08x" % binascii.crc32(chr(0x03))
 0x4b0bbe37

Онлайн-инструмент здесь http://www.lammertbies.nl/comm/info/crc-calculation.html#intr дает тот же результат. В чем разница между моим ручным расчетом и алгоритмом, который использует упомянутое программное обеспечение?

ОБНОВЛЕНИЕ:

Оказывается, уже был подобный вопрос при переполнении стека:

Здесь вы найдете ответ Проблемы с Python CRC-32

Хотя это не очень понятно. Если вам нужно более формальное описание того, как это делается для кадров Ethernet, вы можете посмотреть Стандартный документ Ethernet 802.3 Часть 3 - Глава 3.2.9 Поле последовательности проверки кадра

Продолжим пример сверху:

  1. Измените битовый порядок вашего сообщения. Это представляет, как они будут поступать в приемник по крупицам.

    0x03, следовательно, 0xC0

  2. Дополните первые 32 бита вашего сообщения. Обратите внимание, что мы снова заполняем один байт 32-битным.

    0xC000000000 xor 0xFFFFFFFF = 0x3FFFFFFF00

  3. Выполните Xor и метод сдвига снова сверху. Примерно через 6 шагов вы получите:

    0x13822f2d

  4. Затем дополняется приведенная выше битовая последовательность.

    0x13822f2d xor 0xFFFFFFFF = 0xec7dd0d2

  5. Помните, что на первом шаге мы изменили порядок следования битов, чтобы получить представление в сети Ethernet. Теперь нам нужно отменить этот шаг, и мы, наконец, выполнили наш квест.

    0x4b0bbe37

Тот, кто придумал этот способ, должен быть ...

Часто вы действительно хотите знать, что полученное вами сообщение является правильным. Для этого вы берете полученное сообщение, включая FCS, и выполняете те же шаги с 1 по 5, что и выше. В результате должен получиться то, что они называют остатком. Это постоянная величина для данного многочлена. В данном случае это 0xC704DD7B.

Как упоминает mcdowella, вам нужно поиграть со своими битами, пока вы не добьетесь нужного результата, в зависимости от того, какое приложение вы используете.


person sebs    schedule 15.02.2012    source источник
comment
Откуда 0x209823B6E?   -  person grieve    schedule 15.02.2012
comment
Также вы установили свой начальный остаток на 0xFFFFFFFF   -  person grieve    schedule 15.02.2012
comment
0x209823B6E - это сдвинутая версия полинома, чтобы выровнять его с данными   -  person sebs    schedule 16.02.2012
comment
@sebs, как сдвинули?   -  person cp.engr    schedule 24.01.2017
comment
@ cp.engr сдвинуто на один бит влево. (0x104C11DB7 << 1)   -  person sebs    schedule 27.11.2018
comment
Остаток зависит от аппаратной реализации. Если следовать стандарту, байты должны быть буферизованы, чтобы вычислить стандартную CRC смещения влево. Вместо этого CRC со сдвигом вправо может использоваться для вычисления CRC на лету. Аппаратная реализация может использовать регистр LFSR, смещающий вправо или влево, для вычисления CRC, поэтому остаток может быть инвертирован, что приведет к 0xDEBB20E3 (сдвиг вправо) или 0xC704DD7B (сдвиг влево).   -  person rcgldr    schedule 31.01.2020
comment
Проблема усугубляется тем, что сначала данные передаются lsb (бит 0), а FCS сначала передается msb (бит 31).   -  person rcgldr    schedule 31.01.2020


Ответы (4)


Этот фрагмент записывает правильный CRC для Ethernet.

Python 3

# write payload
for byte in data:
    f.write(f'{byte:02X}\n')
# write FCS
crc = zlib.crc32(data) & 0xFFFF_FFFF
for i in range(4):
    byte = (crc >> (8*i)) & 0xFF
    f.write(f'{byte:02X}\n')

Python 2

# write payload
for byte in data:
    f.write('%02X\n' % ord(byte))
# write FCS
crc = zlib.crc32(data) & 0xFFFFFFFF
for i in range(4):
    byte = (crc >> (8*i)) & 0xFF
    f.write('%02X\n' % byte)

Сэкономил бы мне время, если бы нашел это здесь.

person maxy    schedule 18.11.2013
comment
Это сэкономило мне часы борьбы. Спасибо Спасибо. - person dinkelk; 06.11.2019

Как правило, требуется немного проб и ошибок, чтобы привести вычисления CRC в соответствие, потому что вы никогда не прочитаете, что именно нужно делать. Иногда вам нужно перевернуть входные байты или полином, иногда вам нужно начать с ненулевого значения и так далее.

Один из способов обойти это - посмотреть на исходный код программы, исправивший все, например http://sourceforge.net/projects/crcmod/files/ (по крайней мере, он утверждает, что соответствует, и поставляется с модульным тестом для этого).

Другой - поиграться с реализацией. Например, если я использую калькулятор по адресу http://www.lammertbies.nl/comm/info/crc-calculation.html#intr Я вижу, что если указать 00000000, CRC будет равен 0x2144DF1C, но если дать ему FFFFFFFF, получится FFFFFFFF - так что это не совсем то полиномиальное деление, которое вы описываете, для которого 0 будет иметь контрольную сумму 0

Беглый взгляд на исходный код и эти результаты, я думаю, вам нужно начать с CRC 0xFFFFFFFF, но я могу ошибаться, и вы можете в конечном итоге отладить свой код вместе с реализацией, используя соответствующие printfs, чтобы узнать, где первые различаются и исправляют различия одно за другим.

person mcdowella    schedule 15.02.2012

В Интернете есть ряд мест, где вы прочитаете, что порядок битов должен быть изменен на обратный перед вычислением FCS, но спецификация 802.3 не входит в их число. Цитата из версии спецификации 2008 года:

3.2.9 Frame Check Sequence (FCS) field

A cyclic redundancy check (CRC) is used by the transmit and receive algorithms to
generate a CRC value for the FCS field. The FCS field contains a 4-octet (32-bit)
CRC value. This value is computed as a function of the contents of the protected
fields of the MAC frame: the Destination Address, Source Address, Length/ Type 
field, MAC Client Data, and Pad (that is, all fields except FCS). The encoding is
defined by the following generating polynomial.

  G(x) = x32 + x26 + x23 + x22 + x16 + x12 + x11 
             + x10 + x8 + x7 + x5 + x4 + x2 + x + 1

Mathematically, the CRC value corresponding to a given MAC frame is defined by 
the following procedure:

a) The first 32 bits of the frame are complemented.
b) The n bits of the protected fields are then considered to be the coefficients
   of a polynomial M(x) of degree n – 1. (The first bit of the Destination Address
   field corresponds to the x(n–1) term and the last bit of the MAC Client Data 
   field (or Pad field if present) corresponds to the x0 term.)
c) M(x) is multiplied by x32 and divided by G(x), producing a remainder R(x) of
   degree ≤ 31.
d) The coefficients of R(x) are considered to be a 32-bit sequence.
e) The bit sequence is complemented and the result is the CRC.

The 32 bits of the CRC value are placed in the FCS field so that the x31 term is
the left-most bit of the first octet, and the x0 term is the right most bit of the
last octet. (The bits of the CRC are thus transmitted in the order x31, x30,..., 
x1, x0.) See Hammond, et al. [B37].

Конечно, остальные биты в кадре передаются в обратном порядке, но это не включает FCS. Опять же из спецификации:

3.3 Order of bit transmission

Each octet of the MAC frame, with the exception of the FCS, is transmitted least
significant bit first.
person Daniel Wisehart    schedule 10.08.2013
comment
Это просто неявно, что первый бит и последний бит относятся к порядку передачи - они не говорят старший или младший бит по этой причине :) - person hobbs; 06.03.2015
comment
Стандарт описывает CRC32 BZIP2, который представляет собой CRC со сдвигом влево, затем сначала передают данные lsb, но сначала msb FCS (бит 31). Альтернативой является использование CRC32 со сдвигом вправо, что приводит к CRC, то есть обращению битов FCS, после чего данные и CRC могут быть отправлены первым младшим битом, что приведет к идентичной передаче. В стандарте также упоминается, что получатель должен сравнить вычисленную FCS с полученной FCS, но альтернативой является генерация CRC для данных + FCS, что приводит к фиксированному ненулевому значению, которое зависит от реализации. - person rcgldr; 31.01.2020

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

содержит все данные для Ethernet и множество важных деталей, например, существует (как минимум) 2 соглашения о кодировании полинома в 32-битное значение, сначала наибольший член или сначала наименьший член.

person Dima Tisnek    schedule 15.02.2012