Проверки CRC-16 и CRC-32

Мне нужна помощь в проверке значений CRC-16 (также нужна помощь со значениями CRC-32). Я попытался сесть и понять, как работает CRC, но у меня ничего не получается.

Моя первая проблема связана с попыткой использовать онлайн-калькулятор для вычисления сообщения "BD001325E032091B94C412AC" в CRC16 = 12AC. В документации указано, что последние два октета являются значением CRC16, поэтому я ввожу "BD001325E032091B94C4" на сайт http://www.lammertbies.nl/comm/info/crc-calculation.html и получите в результате 5A90 вместо 12AC.

Кто-нибудь знает, почему эти значения разные и где я могу найти код для вычисления значений CRC16 и CRC32 (я планирую позже узнать, как это сделать, но время не позволяет прямо сейчас)?

Еще несколько сообщений:

16000040FFFFFFFF00015FCB  
3C00003144010405E57022C7  
BA00001144010101B970F0ED  
3900010101390401B3049FF1  
09900C800000000000008CF3  
8590000000000000000035F7  
00900259025902590259EBC9  
0200002B00080191014BF5A2  
BB0000BEE0014401B970E51E  
3D000322D0320A2510A263A0  
2C0001440000D60000D65E54

--Редактировать--

Я добавил больше информации. Документация, на которую я ссылался, - TIA-102.BAAA-A (из стандарта TIA). В документации указано следующее (попытка максимально избежать нарушения авторских прав):

Последний блок в пакете содержит несколько октетов пользовательской информации и / или октетов заполнения, за которыми следует 4-октетная проверка четности CRC. Это называется CRC пакета.

CRC пакета - это 4-октетная проверка циклическим избыточным кодом, закодированная по всем октетам данных, включенным в промежуточные блоки, и октетам пользовательской информации последнего блока. Конкретный расчет выглядит следующим образом.

Пусть k будет общим количеством пользовательской информации и битов заполнения, по которым должен вычисляться CRC пакета. Считайте k битов сообщения коэффициентами полинома M (x) степени k – 1, связывая старший бит нулевого октета сообщения с x ^ k – 1 и младший бит последнего октета сообщения с x ^ 0. Определите порождающий полином GM (x) и полином обращения IM (x).

GM(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1

IM(x) = x^31 + x^30 + x^29 + ... + x^2 + x +1

Полином пакета CRC, FM (x), затем вычисляется по следующей формуле.

FM (x) = (x ^ 32 M (x) mod GM (x)) + IM (x) по модулю 2, т.е. в GF (2)

Коэффициенты FM (x) помещаются в поле CRC с MSB нулевого октета CRC, соответствующего x ^ 31, и LSB третьего октета CRC, соответствующего x ^ 0.

В приведенной выше цитате я поставил ^, чтобы показать полномочия, поскольку форматирование не оставалось прежним при цитировании. Я не уверен, что к чему, но помогает ли это?


person Gabriel Graves    schedule 22.04.2013    source источник
comment
Откуда у вас значение 12AC?   -  person Matthew Watson    schedule 22.04.2013
comment
Последние два байта BD001325E032091B94C412AC. Если вы посмотрите на блок примеров, окажется, что последние два байта всегда являются контрольной суммой.   -  person egrunin    schedule 22.04.2013
comment
Могут быть разные значения CRC-16, которые полностью зависят от используемого полинома.   -  person ken2k    schedule 22.04.2013
comment
Габриэль: Документация = какая документация?   -  person egrunin    schedule 22.04.2013
comment
Вы правы в том, что я не определяю, какая документация. Я отредактировал свой вопрос, чтобы показать более подробную информацию.   -  person Gabriel Graves    schedule 22.04.2013


Ответы (3)


  1. Прочтите руководство Росс Уильямс по CRC, чтобы лучше понять CRC, что определяет конкретный CRC, и их реализации.

  2. На сайте reveng есть отличный каталог известных CRC, и для каждой CRC тестовой строки (девять байтов : "123456789" в ASCII / UTF-8). Обратите внимание, что там определены 22 различных 16-битных CRC.

Программное обеспечение Reveng на том же сайте может быть использовано для обратного проектирования полинома, инициализации, постобработки и реверсирования битов на нескольких примерах, как и для 16-битной CRC. (Отсюда и название "месть".) Я просмотрел ваши данные и получил:

./reveng -w 16 -s 16000040FFFFFFFF00015FCB 3C00003144010405E57022C7 BA00001144010101B970F0ED 3900010101390401B3049FF1 09900C800000000000008CF3 8590000000000000000035F7 00900259025902590259EBC9 0200002B00080191014BF5A2 BB0000BEE0014401B970E51E 3D000322D0320A2510A263A0 2C0001440000D60000D65E54

width=16  poly=0x1021  init=0xc921  refin=false  refout=false  xorout=0x0000  check=0x2fcf  name=(none)

Как обозначено «(нет)», этот 16-битный CRC не является ни одним из 22, перечисленных в reng, хотя он похож на некоторые из них, отличаясь только инициализацией.

Дополнительная информация, которую вы предоставили, относится к 32-битной CRC, CRC-32 или CRC-32 / BZIP в каталоге reng, в зависимости от того, поменяны ли биты на противоположные или нет.

person Mark Adler    schedule 22.04.2013
comment
Я собираюсь отметить это как ответ на данный момент, поскольку у меня нет много времени, чтобы посвятить изучению CRC, и похоже, что мне нужно над чем поработать для тех, которые я получаю. Спасибо за ссылки и информацию. Я когда-нибудь вернусь к ним и попытаюсь разобраться в них. - person Gabriel Graves; 23.04.2013
comment
@ygoe Исправлено. Спасибо. - person Mark Adler; 31.12.2019

У меня есть класс, который я преобразовал из C ++, который я нашел в Интернете, он использует long для вычисления CRC32. Он соответствует стандарту и используется PKZIP, WinZip и Ethernet. Чтобы проверить это, используйте Winzip и сожмите файл, затем вычислите тот же файл с этим классом, он должен вернуть тот же CRC. Мне подходит.

public class CRC32
{
    private int[] iTable;

    public CRC32() {
       this.iTable = new int[256];
       Init();
    }

    /**
     * Initialize the iTable aplying the polynomial used by PKZIP, WINZIP and Ethernet.
     */
    private void Init()
    {
       // 0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet.
       int iPolynomial = 0x04C11DB7;

       // 256 values representing ASCII character codes.
       for (int iAscii = 0; iAscii <= 0xFF; iAscii++)
       {
          this.iTable[iAscii] = this.Reflect(iAscii, (byte) 8) << 24;

          for (int i = 0; i <= 7; i++)
          {
             if ((this.iTable[iAscii] & 0x80000000L) == 0) this.iTable[iAscii] = (this.iTable[iAscii] << 1) ^ 0;
             else this.iTable[iAscii] = (this.iTable[iAscii] << 1) ^ iPolynomial;
          }
          this.iTable[iAscii] = this.Reflect(this.iTable[iAscii], (byte) 32);
       }
    }

    /**
     * Reflection is a requirement for the official CRC-32 standard. Note that you can create CRC without it,
     * but it won't conform to the standard.
     *
     * @param iReflect
     *           value to apply the reflection
     * @param iValue
     * @return the calculated value
     */
    private int Reflect(int iReflect, int iValue)
    {
       int iReturned = 0;
       // Swap bit 0 for bit 7, bit 1 For bit 6, etc....
       for (int i = 1; i < (iValue + 1); i++)
       {
          if ((iReflect & 1) != 0)
          {
             iReturned |= (1 << (iValue - i));
          }
          iReflect >>= 1;
       }
       return iReturned;
    }

    /**
     * PartialCRC caculates the CRC32 by looping through each byte in sData
     *
     * @param lCRC
     *           the variable to hold the CRC. It must have been initialize.
     *           <p>
     *           See fullCRC for an example
     *           </p>
     * @param sData
     *           array of byte to calculate the CRC
     * @param iDataLength
     *           the length of the data
     * @return the new caculated CRC
     */
    public long CalculateCRC(long lCRC, byte[] sData, int iDataLength)
    {
       for (int i = 0; i < iDataLength; i++)
       {
          lCRC = (lCRC >> 8) ^ (long) (this.iTable[(int) (lCRC & 0xFF) ^ (int) (sData[i] & 0xff)] & 0xffffffffL);
       }
       return lCRC;
    }

    /**
     * Caculates the CRC32 for the given Data
     *
     * @param sData
     *           the data to calculate the CRC
     * @param iDataLength
     *           then length of the data
     * @return the calculated CRC32
     */
    public long FullCRC(byte[] sData, int iDataLength)
    {
       long lCRC = 0xffffffffL;
       lCRC = this.CalculateCRC(lCRC, sData, iDataLength);
       return (lCRC /*& 0xffffffffL)*/^ 0xffffffffL);
    }

    /**
     * Calculates the CRC32 of a file
     *
     * @param sFileName
     *           The complete file path
     * @param context
     *           The context to open the files.
     * @return the calculated CRC32 or -1 if an error occurs (file not found).
     */
    long FileCRC(String sFileName, Context context)
    {
          long iOutCRC = 0xffffffffL; // Initilaize the CRC.

          int iBytesRead = 0;
          int buffSize = 32 * 1024;
          FileInputStream isFile = null;
          try
          {
             byte[] data = new byte[buffSize]; // buffer de 32Kb
             isFile = context.openFileInput(sFileName);
             try
             {
                while ((iBytesRead = isFile.read(data, 0, buffSize)) > 0)
                {
                   iOutCRC = this.CalculateCRC(iOutCRC, data, iBytesRead);
                }
                return (iOutCRC ^ 0xffffffffL); // Finalize the CRC.
             }
             catch (Exception e)
             {
                // Error reading file
             }
             finally
             {
                isFile.close();
             }
          }
          catch (Exception e)
          {
             // file not found
          }
          return -1l;
       }
 }
person ja_mesa    schedule 25.04.2013

Для вычислений CRC существует довольно много параметров: полином, начальное значение, окончательное XOR ... см. Википедия для подробностей. Кажется, ваша CRC не соответствует тем, которые вы использовали на сайте, но вы можете попытаться найти правильные параметры в своей документации и использовать другой калькулятор, например этот (хотя, боюсь, он не поддерживает ввод HEX).

Следует иметь в виду, что CRC-16 обычно вычисляется по данным, которые предполагается вычислить с помощью контрольной суммы плюс два нулевых байта, например вы, вероятно, ищете функцию CRC16, где CRC16(BD001325E032091B94C40000) == 12AC. Если контрольные суммы рассчитаны таким образом, CRC данных с добавленной контрольной суммой будет работать до 0, что упрощает проверку, например CRC16(BD001325E032091B94C412AC) == 0000

person Medo42    schedule 22.04.2013
comment
Я обновил свой исходный вопрос, включив в него дополнительную информацию. - person Gabriel Graves; 22.04.2013