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 函数确实返回 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位CRC,而不是CCITT(Kermit)16位CRC。有 1/65536 的可能性是巧合,因为只有一个示例,因此您需要尝试使用更多嗅探数据包。

下面是一个简单的,一次一比特的C例程,它计算CRC(使用mem == NULL调用它返回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生成,它还为表驱动版本生成代码,包括按字节和按字。

最新更新