//----------------------------------------------------------------------------- // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- // CRC16 //----------------------------------------------------------------------------- #include "crc16.h" static uint16_t crc_table[256]; static bool crc_table_init = false; static CrcType_t crc_type = CRC_NONE; void init_table(CrcType_t ct) { // same crc algo, and initialised already if (ct == crc_type && crc_table_init) return; // not the same crc algo. reset table. if (ct != crc_type) reset_table(); crc_type = ct; switch (ct) { case CRC_14443_A: case CRC_14443_B: case CRC_15693: case CRC_ICLASS: generate_table(CRC16_POLY_CCITT, true); break; case CRC_FELICA: generate_table(CRC16_POLY_CCITT, false); break; case CRC_LEGIC: generate_table(CRC16_POLY_LEGIC, true); break; case CRC_CCITT: generate_table(CRC16_POLY_CCITT, false); break; case CRC_KERMIT: generate_table(CRC16_POLY_CCITT, true); break; default: crc_table_init = false; crc_type = CRC_NONE; break; } } void generate_table(uint16_t polynomial, bool refin) { uint16_t i, j, crc, c; for (i = 0; i < 256; i++) { crc = 0; if (refin) c = reflect8(i) << 8; else c = i << 8; for (j = 0; j < 8; j++) { if ((crc ^ c) & 0x8000) crc = (crc << 1) ^ polynomial; else crc = crc << 1; c = c << 1; } if (refin) crc = reflect16(crc); crc_table[i] = crc; } crc_table_init = true; } void reset_table(void) { memset(crc_table, 0, sizeof(crc_table)); crc_table_init = false; crc_type = CRC_NONE; } // table lookup LUT solution uint16_t crc16_fast(uint8_t const *d, size_t n, uint16_t initval, bool refin, bool refout) { // fast lookup table algorithm without augmented zero bytes, e.g. used in pkzip. // only usable with polynom orders of 8, 16, 24 or 32. if (n == 0) return (~initval); uint16_t crc = initval; if (refin) crc = reflect16(crc); if (!refin) while (n--) crc = (crc << 8) ^ crc_table[((crc >> 8) ^ *d++) & 0xFF ]; else while (n--) crc = (crc >> 8) ^ crc_table[(crc & 0xFF) ^ *d++]; if (refout ^ refin) crc = reflect16(crc); return crc; } // bit looped solution TODO REMOVED uint16_t update_crc16_ex(uint16_t crc, uint8_t c, uint16_t polynomial) { uint16_t i, v, tmp = 0; v = (crc ^ c) & 0xff; for (i = 0; i < 8; i++) { if ((tmp ^ v) & 1) tmp = (tmp >> 1) ^ polynomial; else tmp >>= 1; v >>= 1; } return ((crc >> 8) ^ tmp) & 0xffff; } uint16_t update_crc16(uint16_t crc, uint8_t c) { return update_crc16_ex(crc, c, CRC16_POLY_CCITT); } // two ways. msb or lsb loop. uint16_t crc16(uint8_t const *d, size_t length, uint16_t remainder, uint16_t polynomial, bool refin, bool refout) { if (length == 0) return (~remainder); uint8_t c; for (uint32_t i = 0; i < length; ++i) { c = d[i]; if (refin) c = reflect8(c); // xor in at msb remainder ^= (c << 8); // 8 iteration loop for (uint8_t j = 8; j; --j) { if (remainder & 0x8000) { remainder = (remainder << 1) ^ polynomial; } else { remainder <<= 1; } } } if (refout) remainder = reflect16(remainder); return remainder; } void compute_crc(CrcType_t ct, const uint8_t *d, size_t n, uint8_t *first, uint8_t *second) { // can't calc a crc on less than 1 byte if (n == 0) return; init_table(ct); uint16_t crc = 0; switch (ct) { case CRC_14443_A: crc = crc16_a(d, n); break; case CRC_14443_B: case CRC_15693: crc = crc16_x25(d, n); break; case CRC_ICLASS: crc = crc16_iclass(d, n); break; case CRC_FELICA: crc = crc16_xmodem(d, n); break; //case CRC_LEGIC: case CRC_CCITT: crc = crc16_ccitt(d, n); break; case CRC_KERMIT: crc = crc16_kermit(d, n); break; default: break; } *first = (crc & 0xFF); *second = ((crc >> 8) & 0xFF); } uint16_t crc(CrcType_t ct, const uint8_t *d, size_t n) { // can't calc a crc on less than 3 byte. (1byte + 2 crc bytes) if (n < 3) return 0; init_table(ct); switch (ct) { case CRC_14443_A: return crc16_a(d, n); case CRC_14443_B: case CRC_15693: return crc16_x25(d, n); case CRC_ICLASS: return crc16_iclass(d, n); case CRC_FELICA: return crc16_xmodem(d, n); //case CRC_LEGIC: case CRC_CCITT: return crc16_ccitt(d, n); case CRC_KERMIT: return crc16_kermit(d, n); default: break; } return 0; } // check CRC // ct crc type // d buffer with data // n length (including crc) // // This function uses the message + crc bytes in order to compare the "residue" afterwards. // crc16 algos like CRC-A become 0x000 // while CRC-15693 become 0x0F47 // If calculated with crc bytes, the residue should be 0xF0B8 bool check_crc(CrcType_t ct, const uint8_t *d, size_t n) { // can't calc a crc on less than 3 byte. (1byte + 2 crc bytes) if (n < 3) return false; init_table(ct); switch (ct) { case CRC_14443_A: return (crc16_a(d, n) == 0); case CRC_14443_B: return (crc16_x25(d, n) == X25_CRC_CHECK); case CRC_15693: return (crc16_x25(d, n) == X25_CRC_CHECK); case CRC_ICLASS: return (crc16_iclass(d, n) == 0); case CRC_FELICA: return (crc16_xmodem(d, n) == 0); //case CRC_LEGIC: case CRC_CCITT: return (crc16_ccitt(d, n) == 0); default: break; } return false; } // poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 residue=0x0000 name="CRC-16/CCITT-FALSE" uint16_t crc16_ccitt(uint8_t const *d, size_t n) { return crc16_fast(d, n, 0xffff, false, false); } // FDX-B ISO11784/85) uses KERMIT // poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 name="KERMIT" uint16_t crc16_kermit(uint8_t const *d, size_t n) { return crc16_fast(d, n, 0x0000, true, true); } // FeliCa uses XMODEM // poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 name="XMODEM" uint16_t crc16_xmodem(uint8_t const *d, size_t n) { return crc16_fast(d, n, 0x0000, false, false); } // Following standards uses X-25 // ISO 15693, // ISO 14443 CRC-B // ISO/IEC 13239 (formerly ISO/IEC 3309) // poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff name="X-25" uint16_t crc16_x25(uint8_t const *d, size_t n) { uint16_t crc = crc16_fast(d, n, 0xffff, true, true); crc = ~crc; return crc; } // CRC-A (14443-3) // poly=0x1021 init=0xc6c6 refin=true refout=true xorout=0x0000 name="CRC-A" uint16_t crc16_a(uint8_t const *d, size_t n) { return crc16_fast(d, n, 0xC6C6, true, true); } // iClass crc // initvalue 0x4807 reflected 0xE012 // poly 0x1021 reflected 0x8408 // poly=0x1021 init=0x4807 refin=true refout=true xorout=0x0BC3 check=0xF0B8 name="CRC-16/ICLASS" uint16_t crc16_iclass(uint8_t const *d, size_t n) { return crc16_fast(d, n, 0x4807, true, true); } // This CRC-16 is used in Legic Advant systems. // poly=0xB400, init=depends refin=true refout=true xorout=0x0000 check= name="CRC-16/LEGIC" uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc) { uint16_t initial = uidcrc << 8 | uidcrc; return crc16_fast(d, n, initial, true, true); }