1

我需要帮助来验证 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 个消息比特视为 k-1 次多项式 M(x) 的系数,将第零个消息八位字节的 MSB 与 x^k-1 相关联,将最后一个消息八位字节的 LSB 与 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 字段中,CRC 的第 0 个八位字节的 MSB 对应于 x^31,CRC 的第三个八位字节的 LSB 对应于 x^0。

在上面的引用中,我已经^展示了权力,因为引用时格式并没有保持不变。我不确定会发生什么,但这有帮助吗?

4

3 回答 3

5

我有一个从互联网上找到的 C++ 转换而来的类,它使用 long 来计算 CRC32。它遵守标准,是 PKZIP、WinZip 和以太网使用的一种。要对其进行测试,请使用 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;
       }
 }
于 2013-04-25T11:18:03.603 回答
4
  1. 阅读有关 CRC 的 Ross Williams 教程,以更好地了解 CRC、定义特定 CRC 的内容及其实现。

  2. reveng网站有一个很好的已知 CRC 目录,以及每个测试字符串的 CRC(九个字节:ASCII/UTF-8 中的“123456789”)。请注意,这里定义了22 种不同的 16 位 CRC

同一站点上的 reveng 软件可用于对多项式、初始化、后处理和位反转进行逆向工程,给出了几个示例,如 16 位 CRC。(因此得名“reveng”。)我运行了你的数据并得到:

./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)

如“(none)”所示,16 位 CRC 不是 reveng 上列出的 22 个中的任何一个,尽管它与其中几个相似,仅在初始化方面有所不同。

您提供的附加信息适用于 32 位 CRC,即 reveng 目录中的 CRC-32 或 CRC-32/BZIP,具体取决于位是否反转。

于 2013-04-22T20:48:53.270 回答
2

CRC 计算有很多参数:多项式、初始值、最终 XOR ......有关详细信息,请参阅Wikipedia。您的 CRC 似乎不适合您使用的网站上的那些,但您可以尝试从您的文档中找到正确的参数并使用不同的计算器,例如这个(虽然我担心它不支持 HEX 输入) .

要记住的一件事是,CRC-16 通常是根据应该进行校验和的数据加上两个零字节来计算的,例如,您可能正在寻找一个CRC16函数 where CRC16(BD001325E032091B94C40000) == 12AC。以这种方式计算校验和,附加校验和的数据的 CRC 将计算为 0,这使得检查更容易,例如CRC16(BD001325E032091B94C412AC) == 0000

于 2013-04-22T08:55:50.750 回答