CRC循环冗余校验【实现篇】

admin 2023年3月25日01:04:16评论171 views字数 12436阅读41分27秒阅读模式

CRC循环冗余校验【实现篇】

CRC循环冗余校验【实现篇】

在之前的文章当中,我简单介绍了一下有关于CRC的原理,这次呢,我们从开发的角度来看一下CRC的具体实现,因为CRC的种类实在是太多了,如果咱们一个一个实现,那就太费劲了,所以直接来看通用的实现方法。

参数

对于如何确定一个CRC校验,可以通过如下的参数来确定,

  • 「多项式(Poly)」: 它是一个二进制数,表示用于生成CRC码的多项式,多项式长度取决于数据位的位数。
  • **初始值(Initial Value)**: 一个二进制数,表示在计算CRC码之前,应该在数据字节流的开头添加的字节,通常情况是全0或者全1。
  • **终止值(Final Xor Value)**:一个二进制数,表示在计算CRC码之后,应该对CRC码进行执行异或操作的字节,通常情况是全0或者全1。
  • **反转输入(Reflect Input)**:对输入的字节是否进行反转。
  • 「反转输出(Reflect Input)」: 对输出的字节是否进行反转。

有关于第一个参数的含义,可以参考下我之前写过的文章,https://mp.weixin.qq.com/s/VwT__b-1cjaLcK0o7D-Vjw。

代码实现

再次相应读者们的选择,这次还是用C++来写,比较容易写出来一个比较通用的代码,当然我这代码就仅仅支持到crc64的任意多项式,再多其实也有,目前就先不支持了,实际上用的也不多。

#include <iostream>
#include <vector>
#include <iomanip>

template<typename T>
reverse_bits(T value, int num_bits) 
{
  T result = 0;
  for (int i = 0; i < num_bits; i++) {
    result = (result << 1) | (value & 1);
    value >>= 1;
  }
  return result;
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshift-count-overflow"
template<typename T>
std::vector<uint8_tcalculate_crc(const std::vector<uint8_t> &data,
                                   T polynomial,
                                   T initial_value,
                                   bool reflect_input,
                                   bool reflect_output,
                                   T final_xor_value)
 
{
  std::vector<uint8_t> crc_bytes;
  T crc = initial_value;
  int num_bits = sizeof(T) * 8;
  T top_bit = (T) 1 << (num_bits - 1);

  for (uint8_t b : data) {
    if (reflect_input) {
      b = reverse_bits(b, 8);
      crc ^= ((T) b << (num_bits - 8));
      for (int i = 0; i < 8; i++) {
        T msb = crc & top_bit;
        crc <<= 1;
        if (msb != 0) {
          crc ^= polynomial;
        }
      }
    } else {
      crc ^= ((T) b << (num_bits - 8));
      for (int i = 0; i < 8; i++) {
        T msb = crc & top_bit;
        crc <<= 1;
        if (msb != 0) {
          crc ^= polynomial;
        }
      }
    }
  }

  if (reflect_output) {
    for (int i = 0; i < num_bits / 8; i++) {
      if (reflect_input) {
        crc_bytes.push_back(static_cast<uint8_t>(reverse_bits((crc >> (8 * i)) & 0xff8)));
      } else {
        crc_bytes.push_back((crc >> (8 * i)) & 0xff);
      }
    }
  } else {
    for (int i = (num_bits - 8); i >= 0; i -= 8) {
      crc_bytes.push_back((crc >> i) & 0xff);
    }
  }

  for (unsigned char &crc_byte : crc_bytes) {
    crc_byte ^= (final_xor_value & 0xff);
    final_xor_value >>= 8;
  }

  return crc_bytes;
}
#pragma clang diagnostic pop

std::vector<uint8_tcrc8(const std::vector<uint8_t> &data,
                          uint8_t polynomial,
                          uint8_t initial_value,
                          bool reflect_input,
                          bool reflect_output,
                          uint8_t final_xor_value)
 
{
  return calculate_crc<uint8_t>(data, polynomial, initial_value, reflect_input, reflect_output, final_xor_value);
}

std::vector<uint8_tcrc16(const std::vector<uint8_t> &data,
                           uint16_t polynomial,
                           uint16_t initial_value,
                           bool reflect_input,
                           bool reflect_output,
                           uint16_t final_xor_value)
 
{
  return calculate_crc<uint16_t>(data, polynomial, initial_value, reflect_input, reflect_output, final_xor_value);
}

std::vector<uint8_tcrc32(const std::vector<uint8_t> &data,
                           uint32_t polynomial,
                           uint32_t initial_value,
                           bool reflect_input,
                           bool reflect_output,
                           uint32_t final_xor_value)
 
{
  return calculate_crc<uint32_t>(data, polynomial, initial_value, reflect_input, reflect_output, final_xor_value);
}

std::vector<uint8_tcrc64(const std::vector<uint8_t> &data,
                           uint64_t polynomial,
                           uint64_t initial_value,
                           bool reflect_input,
                           bool reflect_output,
                           uint64_t final_xor_value)
 
{
  return calculate_crc<uint64_t>(data, polynomial, initial_value, reflect_input, reflect_output, final_xor_value);
}

void print_vector_as_hex_string(const std::string &tag, const std::vector<uint8_t> &vec) {
  std::cout << tag << ":";
  for (const uint8_t &value : vec) {
    std::cout << std::hex << std::setw(2) << std::setfill('0') << (int) value << " ";
  }
  std::cout << std::endl;
}

int main() {

  std::vector<uint8_t> data = {0x010x020x030x040x05};

  print_vector_as_hex_string("CRC16:(CRC-16/ARC)", crc16(data, 0x80050x0000truetrue0x0000));
  print_vector_as_hex_string("CRC8:(CRC-8/DARC)", crc8(data, 0x390x00truetrue0x00));

  return 0;
}


我们具体使用一个例子来看一下这个代码,首先我们选取CRC8这个来作为例子来看一下,至于为啥选他,看着他简单而已,那下面我们先根据上面我们选取的参数,来看一下CRC8

  • 「多项式(Poly)」:  0x07
  • **初始值(Initial Value)**: 0x00
  • **终止值(Final Xor Value)**:0x00
  • **反转输入(Reflect Input)**:false
  • 「反转输出(Reflect Input)」: false

假设我们的输入是0x02,为啥不选0x01,因为1是一个常量,乘了和没乘是一样的,所以我们换一个数字。

对应输入的多项式为 ,对应生成多项式为,然后我们可以得到`r=8`,然后计算下,我们可以得到:

也就是最终得到CRC8的校验值0x0E,然后我们运行下我们写的程序看一下。

int main() {

  std::vector<uint8_t> data = {0x02};
  print_vector_as_hex_string("CRC8:(CRC-8)", crc8(data, 0x070x00falsefalse0x00));
  return 0;
}

发现输出结果和我们写的程序是一样的,至于这个值,我这是怎么算出来的,读者可以自己尝试一下手动计算,我这里当然是选择科技与狠活了,如果大家对于这个我怎么算的感兴趣,我可以单独写一篇有关怎么计算多项式的文章,咳咳,不要吐槽我水文章哈。

好了,到这里有关于通用版本的CRC计算方案,到这里就给大家讲完了,然后呢,这里我找了下有关于CRC计算的常见多项式,和一些参数,以下资料来自互联网。

常见CRC方案

里面内容来自于参考资料2,我只是个搬运工。

name alias width poly init refin refout xorout check residue
CRC-3/GSM - 3 0x3 0x0 false false 0x7 0x4 0x2
CRC-3/ROHC - 3 0x3 0x7 true true 0x0 0x6 0x0
CRC-4/G-704 CRC-4/ITU 4 0x3 0x0 true true 0x0 0x7 0x0
CRC-4/INTERLAKEN - 4 0x3 0xf false false 0xf 0xb 0x2
CRC-5/EPC-C1G2 CRC-5/EPC 5 0x09 0x09 false false 0x00 0x00 0x00
CRC-5/G-704 CRC-5/ITU 5 0x15 0x00 true true 0x00 0x07 0x00
CRC-6/CDMA2000-A - 6 0x27 0x3f false false 0x00 0x0d 0x00
CRC-6/CDMA2000-B - 6 0x07 0x3f false false 0x00 0x3b 0x00
CRC-6/DARC - 6 0x19 0x00 true true 0x00 0x26 0x00
CRC-6/G-704 CRC-6/ITU 6 0x03 0x00 true true 0x00 0x06 0x00
CRC-6/GSM - 6 0x2f 0x00 false false 0x3f 0x13 0x3a
CRC-7/MMC CRC-7 7 0x09 0x00 false false 0x00 0x75 0x00
CRC-7/ROHC - 7 0x4f 0x7f true true 0x00 0x53 0x00
CRC-7/UMTS - 7 0x45 0x00 false false 0x00 0x61 0x00
CRC-8/AUTOSAR - 8 0x2f 0xff false false 0xff 0xdf 0x42
CRC-8/CDMA2000 - 8 0x9b 0xff false false 0x00 0xda 0x00
CRC-8/DARC - 8 0x39 0x00 true true 0x00 0x15 0x00
CRC-8/DVB-S2 - 8 0xd5 0x00 false false 0x00 0xbc 0x00
CRC-8/GSM-A - 8 0x1d 0x00 false false 0x00 0x37 0x00
CRC-8/GSM-B - 8 0x49 0x00 false false 0xff 0x94 0x53
CRC-8/HITAG - 8 0x1d 0xff false false 0x00 0xb4 0x00
CRC-8/I-432-1 CRC-8/ITU 8 0x07 0x00 false false 0x55 0xa1 0xac
CRC-8/I-CODE - 8 0x1d 0xfd false false 0x00 0x7e 0x00
CRC-8/LTE - 8 0x9b 0x00 false false 0x00 0xea 0x00
CRC-8/MAXIM-DOW CRC-8/MAXIM, DOW-CRC 8 0x31 0x00 true true 0x00 0xa1 0x00
CRC-8/MIFARE-MAD - 8 0x1d 0xc7 false false 0x00 0x99 0x00
CRC-8/NRSC-5 - 8 0x31 0xff false false 0x00 0xf7 0x00
CRC-8/OPENSAFETY - 8 0x2f 0x00 false false 0x00 0x3e 0x00
CRC-8/ROHC - 8 0x07 0xff true true 0x00 0xd0 0x00
CRC-8/SAE-J1850 - 8 0x1d 0xff false false 0xff 0x4b 0xc4
CRC-8/SMBUS CRC-8 8 0x07 0x00 false false 0x00 0xf4 0x00
CRC-8/TECH-3250 CRC-8/AES, CRC-8/EBU 8 0x1d 0xff true true 0x00 0x97 0x00
CRC-10/ATM CRC-10, CRC-10/I-610 10 0x233 0x000 false false 0x000 0x199 0x000
CRC-10/CDMA2000 - 10 0x3d9 0x3ff false false 0x000 0x233 0x000
CRC-10/GSM - 10 0x175 0x000 false false 0x3ff 0x12a 0x0c6
CRC-11/FLEXRAY CRC-11 11 0x385 0x01a false false 0x000 0x5a3 0x000
CRC-11/UMTS - 11 0x307 0x000 false false 0x000 0x061 0x000
CRC-12/CDMA2000 - 12 0xf13 0xfff false false 0x000 0xd4d 0x000
CRC-12/DECT X-CRC-12 12 0x80f 0x000 false false 0x000 0xf5b 0x000
CRC-12/GSM - 12 0xd31 0x000 false false 0xfff 0xb34 0x178
CRC-12/UMTS CRC-12/3GPP 12 0x80f 0x000 false true 0x000 0xdaf 0x000
CRC-13/BBC - 13 0x1cf5 0x0000 false false 0x0000 0x04fa 0x0000
CRC-14/DARC - 14 0x0805 0x0000 true true 0x0000 0x082d 0x0000
CRC-14/GSM - 14 0x202d 0x0000 false false 0x3fff 0x30ae 0x031e
CRC-15/CAN CRC-15 15 0x4599 0x0000 false false 0x0000 0x059e 0x0000
CRC-15/MPT1327 - 15 0x6815 0x0000 false false 0x0001 0x2566 0x6815
CRC-16/ARC ARC, CRC-16, CRC-16/LHA, CRC-IBM 16 0x8005 0x0000 true true 0x0000 0xbb3d 0x0000
CRC-16/CDMA2000 - 16 0xc867 0xffff false false 0x0000 0x4c06 0x0000
CRC-16/DDS-110 - 16 0x8005 0x800d false false 0x0000 0x9ecf 0x0000
CRC-16/DECT-R R-CRC-16 16 0x0589 0x0000 false false 0x0001 0x007e 0x0589
CRC-16/DECT-X X-CRC-16 16 0x0589 0x0000 false false 0x0000 0x007f 0x0000
CRC-16/DNP - 16 0x3d65 0x0000 true true 0xffff 0xea82 0x66c5
CRC-16/EN-13757 - 16 0x3d65 0x0000 false false 0xffff 0xc2b7 0xa366
CRC-16/GENIBUS CRC-16/DARC, CRC-16/EPC, CRC-16/EPC-C1G2, CRC-16/I-CODE 16 0x1021 0xffff false false 0xffff 0xd64e 0x1d0f
CRC-16/GSM - 16 0x1021 0x0000 false false 0xffff 0xce3c 0x1d0f
CRC-16/IBM-3740 CRC-16/AUTOSAR, CRC-16/CCITT-FALSE 16 0x1021 0xffff false false 0x0000 0x29b1 0x0000
CRC-16/IBM-SDLC CRC-16/ISO-HDLC, CRC-16/ISO-IEC-14443-3-B, CRC-16/X-25, CRC-B, X-25 16 0x1021 0xffff true true 0xffff 0x906e 0xf0b8
CRC-16/ISO-IEC-14443-3-A CRC-A 16 0x1021 0xc6c6 true true 0x0000 0xbf05 0x0000
CRC-16/KERMIT CRC-16/BLUETOOTH, CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/V-41-LSB, CRC-CCITT, KERMIT 16 0x1021 0x0000 true true 0x0000 0x2189 0x0000
CRC-16/M17 - 16 0x5935 0xffff false false 0x0000 0x772b 0x0000
CRC-16/MAXIM-DOW CRC-16/MAXIM 16 0x8005 0x0000 true true 0xffff 0x44c2 0xb001
CRC-16/MCRF4XX - 16 0x1021 0xffff true true 0x0000 0x6f91 0x0000
CRC-16/MODBUS MODBUS 16 0x8005 0xffff true true 0x0000 0x4b37 0x0000
CRC-16/NRSC-5 - 16 0x080b 0xffff true true 0x0000 0xa066 0x0000
CRC-16/OPENSAFETY-A - 16 0x5935 0x0000 false false 0x0000 0x5d38 0x0000
CRC-16/OPENSAFETY-B - 16 0x755b 0x0000 false false 0x0000 0x20fe 0x0000
CRC-16/PROFIBUS CRC-16/IEC-61158-2 16 0x1dcf 0xffff false false 0xffff 0xa819 0xe394
CRC-16/SPI-FUJITSU CRC-16/AUG-CCITT 16 0x1021 0x1d0f false false 0x0000 0xe5cc 0x0000
CRC-16/T10-DIF - 16 0x8bb7 0x0000 false false 0x0000 0xd0db 0x0000
CRC-16/TELEDISK - 16 0xa097 0x0000 false false 0x0000 0x0fb3 0x0000
CRC-16/TMS37157 - 16 0x1021 0x89ec true true 0x0000 0x26b1 0x0000
CRC-16/UMTS CRC-16/BUYPASS, CRC-16/VERIFONE 16 0x8005 0x0000 false false 0x0000 0xfee8 0x0000
CRC-16/XMODEM CRC-16/ACORN, CRC-16/LTE, CRC-16/V-41-MSB, XMODEM, ZMODEM 16 0x1021 0x0000 false false 0x0000 0x31c3 0x0000
CRC-17/CAN-FD - 17 0x1685b 0x00000 false false 0x00000 0x04f03 0x00000
CRC-21/CAN-FD - 21 0x102899 0x000000 false false 0x000000 0x0ed841 0x000000
CRC-24/BLE - 24 0x00065b 0x555555 true true 0x000000 0xc25a56 0x000000
CRC-24/FLEXRAY-A - 24 0x5d6dcb 0xfedcba false false 0x000000 0x7979bd 0x000000
CRC-24/FLEXRAY-B - 24 0x5d6dcb 0xabcdef false false 0x000000 0x1f23b8 0x000000
CRC-24/INTERLAKEN - 24 0x328b63 0xffffff false false 0xffffff 0xb4f3e6 0x144e63
CRC-24/LTE-A - 24 0x864cfb 0x000000 false false 0x000000 0xcde703 0x000000
CRC-24/LTE-B - 24 0x800063 0x000000 false false 0x000000 0x23ef52 0x000000
CRC-24/OPENPGP CRC-24 24 0x864cfb 0xb704ce false false 0x000000 0x21cf02 0x000000
CRC-24/OS-9 - 24 0x800063 0xffffff false false 0xffffff 0x200fa5 0x800fe3
CRC-30/CDMA - 30 0x2030b9c7 0x3fffffff false false 0x3fffffff 0x04c34abf 0x34efa55a
CRC-31/PHILIPS - 31 0x04c11db7 0x7fffffff false false 0x7fffffff 0x0ce9e46c 0x4eaf26f1
CRC-32/AIXM CRC-32Q 32 0x814141ab 0x00000000 false false 0x00000000 0x3010bf7f 0x00000000
CRC-32/AUTOSAR - 32 0xf4acfb13 0xffffffff true true 0xffffffff 0x1697d06a 0x904cddbf
CRC-32/BASE91-D CRC-32D 32 0xa833982b 0xffffffff true true 0xffffffff 0x87315576 0x45270551
CRC-32/BZIP2 CRC-32/AAL5, CRC-32/DECT-B, B-CRC-32 32 0x04c11db7 0xffffffff false false 0xffffffff 0xfc891918 0xc704dd7b
CRC-32/CD-ROM-EDC - 32 0x8001801b 0x00000000 true true 0x00000000 0x6ec2edc4 0x00000000
CRC-32/CKSUM CKSUM, CRC-32/POSIX 32 0x04c11db7 0x00000000 false false 0xffffffff 0x765e7680 0xc704dd7b
CRC-32/ISCSI CRC-32/BASE91-C, CRC-32/CASTAGNOLI, CRC-32/INTERLAKEN, CRC-32C 32 0x1edc6f41 0xffffffff true true 0xffffffff 0xe3069283 0xb798b438
CRC-32/ISO-HDLC CRC-32, CRC-32/ADCCP, CRC-32/V-42, CRC-32/XZ, PKZIP 32 0x04c11db7 0xffffffff true true 0xffffffff 0xcbf43926 0xdebb20e3
CRC-32/JAMCRC JAMCRC 32 0x04c11db7 0xffffffff true true 0x00000000 0x340bc6d9 0x00000000
CRC-32/MEF - 32 0x741b8cd7 0xffffffff true true 0x00000000 0xd2c22f51 0x00000000
CRC-32/MPEG-2 - 32 0x04c11db7 0xffffffff false false 0x00000000 0x0376e6e7 0x00000000
CRC-32/XFER XFER 32 0x000000af 0x00000000 false false 0x00000000 0xbd0be338 0x00000000
CRC-40/GSM - 40 0x0004820009 0x0000000000 false false 0xffffffffff 0xd4164fc646 0xc4ff8071ff
CRC-64/ECMA-182 CRC-64 64 0x42f0e1eba9ea3693 0x0000000000000000 false false 0x0000000000000000 0x6c40df5f0b497347 0x0000000000000000
CRC-64/GO-ISO - 64 0x000000000000001b 0xffffffffffffffff true true 0xffffffffffffffff 0xb90956c775a41001 0x5300000000000000
CRC-64/MS - 64 0x259c84cba6426349 0xffffffffffffffff true true 0x0000000000000000 0x75d4b74f024eceea 0x0000000000000000
CRC-64/REDIS - 64 0xad93d23594c935a9 0x0000000000000000 true true 0x0000000000000000 0xe9c6d914c4b8d9ca 0x0000000000000000
CRC-64/WE - 64 0x42f0e1eba9ea3693 0xffffffffffffffff false false 0xffffffffffffffff 0x62ec59e3f1a4f00a 0xfcacbebd5931a992
CRC-64/XZ CRC-64/GO-ECMA 64 0x42f0e1eba9ea3693 0xffffffffffffffff true true 0xffffffffffffffff 0x995dc9bbdf1939fa 0x49958c9abd7d353f
CRC-82/DARC - 82 0x0308c0111011401440411 0x000000000000000000000 true true 0x000000000000000000000 0x09ea83f625023801fd612 0x000000000000000000000

参考资料

  • https://zlib.net/crc_v3.txt
  • https://reveng.sourceforge.io/crc-catalogue/
  • https://crccalc.com/


原文始发于微信公众号(Coder小Q):CRC循环冗余校验【实现篇】

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月25日01:04:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CRC循环冗余校验【实现篇】https://cn-sec.com/archives/1627522.html

发表评论

匿名网友 填写信息