5
votes

I'm trying to evaluate appropriate checksum based on CRC-16 algorithm using crcmod Python module and 2.7 version of Python interpreter. The checksum parameters are:

  • CRC order: 16
  • CRC polynomial: 0x8005
  • Inital value: 0xFFFF
  • Final value: 0x0000
  • Direct: True

Code:

crc16 = crcmod.mkCrcFun(0x18005, rev=False, initCrc=0xFFFF, xorOut=0x0000)
print hex(crc16(str(int(0x5A0001))))

and for the input 0x5A0001 it prints 0x7E16 while I should get something like 0xCE0A.

I checked on http://www.lokker.net/Java/crc/CRCcalculation2.htm and the computed value is 0xACE which is correct (with respect to the order).

4
Looks like you have 0x18005 as your polynomial in the python code, but you listed 0x8005 in your checksum parameters above. - djhoese
No, 0x18005 is correct for crcmod. That package determines the number of bits in the CRC from the complete polynomial. It is common to provide a CRC polynomial without the high term, e.g. 0x8005 and separately specify that it is a 16-bit CRC. - Mark Adler
First off, you created c16 and then tried to use crc16. Did you mean c16? Second, what exactly do you think you are computing the CRC of? You do know that str(int(0x5A0001)) returns the string of ASCII digits 5898241, yes? What did you input into the web CRC calculator? - Mark Adler
Yes, it was a typo. The input into the calcuator was %5A%00%01 with appropriate parameters. - Qrlet
Consider also binascii.crc_hqx(data, 0): docs here - hoc_age

4 Answers

5
votes

crcmod is working fine. You are not giving it the three bytes you think you are giving it. Your str(int(0x5A0001)) is providing seven bytes, which are the ASCII characters 5898241 — the conversion of 0x5a0001 to decimal.

To feed it the bytes 0x5a 0x00 0x01, you would instead (as one approach):

print hex(crc16("5a0001".decode("hex")))

That prints 0xace.

3
votes

Here is a python implementation of CRC-16/CCITT-FALSE

def crc16(data : bytearray, offset , length):
    if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data):
        return 0
    crc = 0xFFFF
    for i in range(0, length):
        crc ^= data[offset + i] << 8
        for j in range(0,8):
            if (crc & 0x8000) > 0:
                crc =(crc << 1) ^ 0x1021
            else:
                crc = crc << 1
    return crc & 0xFFFF
  • data : bytearray of the data you want to calculate CRC for
  • offset : from which offset you want to start calculating CRC
  • length : to which offset you want to calculate CRC
0
votes
def crc16(data : bytearray, offset, length):
    if data is None or offset < 0 or offset > len(data) - 1 and offset + length > len(data):
        return 0
    print("uzunluk=", len(data))
    print(data)

    crc = 0xFFFF
    for i in range(length):
        crc ^= data[offset + i]
        for j in range(8):
            print(crc)
            if ((crc & 0x1) == 1):
                print("bb1=", crc)
                crc = int((crc / 2)) ^ 40961
                print("bb2=", crc)
            else:
                crc = int(crc / 2)
    return crc & 0xFFFF
0
votes

A working single function example for CRC-16-ANSI, CRC-16-IBM based on pycrc code.

It is easy to modify but input or output reflection capability is not included:

def crc16(data: bytes):
    xor_in = 0x0000  # initial value
    xor_out = 0x0000  # final XOR value
    poly = 0x8005  # generator polinom (normal form)

    reg = xor_in
    for octet in data:
        # reflect in
        for i in range(8):
            topbit = reg & 0x8000
            if octet & (0x80 >> i):
                topbit ^= 0x8000
            reg <<= 1
            if topbit:
                reg ^= poly
        reg &= 0xFFFF
        # reflect out
    return reg ^ xor_out