C# 中的 CRC-CCITT Kermit 16

CRC-CCITT Kermit 16 in C#

正在尝试对串行端口协议进行逆向工程。我无法重新创建 crc-16 字节。

根据文档,这是数据包的格式

48 45 4c 4f // HELO
01 00 00 01 // ARG 1
00 00 00 00 // ARG 2
00 00 00 00 // ARG 3
00 00 00 00 // ARG 4
00 00 00 00 // REQUEST BODY
5c b1 00 00 // CRC-16
b7 ba b3 b0  // Bit-wise inversion of HELO command

这是串口监控嗅探出来的写命令

48 45 4c 4f 01 00 00 01 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 5c b1 00 00 b7 ba b3 b0   

我能够很好地重新创建数据包,除了 2 个字节“5c b1”。根据文档,5c b1 字节是数据包上的 crc-ccit16,crc-16 槽中有零。 CRC16 函数执行 return 5C 字节但不执行 b1。

我正在使用下面的代码来计算 crc:

  public class Crc16
{
    static ushort[] table = new ushort[256];

    public ushort ComputeChecksum(params byte[] bytes)
    {
        ushort crc = 0;
        for (int i = 0; i < bytes.Length; ++i)
        {
            byte index = (byte)(crc ^ bytes[i]);
            crc = (ushort)((crc >> 8) ^ table[index]);
        }
        return crc;
    }

    public byte[] ComputeChecksumBytes(params byte[] bytes)
    {
        ushort crc = ComputeChecksum(bytes);
        return BitConverter.GetBytes(crc);
    }

    public Crc16(Crc16Mode mode)
    {
        ushort polynomial = (ushort)mode;
        ushort value;
        ushort temp;
        for (ushort i = 0; i < table.Length; ++i)
        {
            value = 0;
            temp = i;
            for (byte j = 0; j < 8; ++j)
            {
                if (((value ^ temp) & 0x0001) != 0)
                {
                    value = (ushort)((value >> 1) ^ polynomial);
                }
                else {
                    value >>= 1;
                }
                temp >>= 1;
            }
            table[i] = value;
        }
    }
}

       public byte[] getPreCRC16Bytes()
    {
            byte[] x = new byte[28];
            byte[] cmdBytes = Encoding.ASCII.GetBytes(this.cmd.ToString());
            byte[] arg1Bytes = (byte[])this.arg1;
            byte[] arg2Bytes = (byte[])this.arg2;
            byte[] arg3Bytes = (byte[])this.arg3;
            byte[] arg4Bytes = (byte[])this.arg4;
            byte[] bodyLen = { 0x00, 0x00, 0x00, 0x00 };
            byte[] emptyCRC = { 0x00, 0x00, 0x00, 0x00 };
            byte[] checksum = Encoding.ASCII.GetBytes(this.checksum);
            var list = new List<byte>();
            list.AddRange(cmdBytes);
            list.AddRange(arg1Bytes);
            list.AddRange(arg2Bytes);
            list.AddRange(arg3Bytes);
            list.AddRange(arg4Bytes);
            list.AddRange(bodyLen);
            list.AddRange(emptyCRC);
            list.AddRange(checksum);
            var xx = list.ToArray();

        string hex = BitConverter.ToString(cmdBytes).Replace("-", "");

        return list.ToArray();

    }

从那个例子来看,它似乎是 X-25 16-bit CRC,而不是 CCITT (Kermit) 16 位 CRC。这是巧合的概率是 1/65536,因为只有一个例子,所以你需要用更多的嗅探数据包来尝试。

这是一个简单的、一次一位的 C 例程,用于计算 CRC(使用 mem == NULL returns CRC 的初始值调用它):

unsigned crc16x_25_bit(unsigned crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0;
    crc = ~crc;
    crc &= 0xffff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;
    }
    crc ^= 0xffff;
    return crc;
}

该代码由 crcany 生成,它还为 table 驱动版本生成代码,包括字节和字。