Reputation: 756
I am sending multiple messages from an MCU to my computer and I want to use a 32-bit Cyclic Redundancy Check to verify that the messages are correct. From what I've read, it should be possible to append the CRC remainder to the last message and run that through the CRC function. If the message was error free, it should then return zero (am I right?) I have however been unsuccessful in implementing this using the binascii library function binascii.crc32().
Let's for example say I want to check the message internally from the example given in Python docs (I'm using Python 3.5). How would I go ahead checking if the message is error free (which of course it is in this example)?
crc = binascii.crc32(b"hello")
crc = binascii.crc32(b" world", crc)
check_for_error() # <--- ?
Upvotes: 3
Views: 3382
Reputation: 55469
The simple way to do it is to just append the CRC in byte form to the message. Then when you receive the message, you calculate the CRC of all but the last 4 bytes of the message and compare it to appended CRC bytes. Sure, it's a bit more fiddly than what you want to do, but you can apply that strategy to cryptographic hashes like MD5 or the SHA family.
However, to do what you're asking you need to invert the CRC32 by subtracting it from 0xffffffff before converting it to bytes & appending it. The CRC32 is actually an inverse CRC, which prevents a message of all zero bytes from having a zero CRC. On decoding, the message may be valid if the CRC of the data + CRC equals 0xffffffff.
The Python CRC32 docs recommend that you use
crc32(data) & 0xffffffff
rather than
crc32(data)
to ensure that you get the same numeric value across all Python versions and platforms.
Here's a quick Python 3 demo.
import binascii
maxcrc = 0xffffffff
def inverse_crc(data):
crc = binascii.crc32(data) & maxcrc
invcrc = maxcrc - crc
return invcrc.to_bytes(4, 'little')
def check_crc(data):
return binascii.crc32(data) & maxcrc == maxcrc
#Test
data = b"Hello, world"
newdata = data + inverse_crc(data)
print(check_crc(newdata))
newdata = b'0x00' + newdata
print(check_crc(newdata))
output
True
False
Note that you can get false positives: a corrupt message may have a correct CRC. If you need a higher level of protection you should use a cryptographic hash. That's still not perfect, but the odds of a false positive with such large hashes are extremely low. Of course, calculating a MD5 or SHA hash is much slower than calculating a CRC32.
Upvotes: 5