# Reverse engineering serial communication CRC algorithm

I'm working on reverse engineering the serial communication protocol of an obsolete electronic control system, but I'm having trouble figuring out the CRC algorithm and polynomial.

I have reverse engineered another similar system made by the same company in the past. On that previous one I was able to dump the `8051` micro-controller program from the `EPROM` and disassemble it. Here is my working code in C, with the original `8051` disassembly in the comments:

``````unsigned char CalculateChecksum(void) {
unsigned char r1 = 0;               // MOV R1,#0
unsigned char r2, r3, c, a;

for (r2=1; r2<4; r2++) {    // MOV R2,#07
a = out_buffer[r2];     // MOV A,@R0

r3 = a;                 // XCH A,R1
a = r1;
r1 = r3;

c = 0;                  // CLR C

if (a & 0x80) {
c = 1;              // FAKE CARRY
}
a = a << 1;             // RLC A
if (c == 1) {           // JNC 0x03E8
a = a ^ 0x19;       // XRL A,#19
}
a = a ^ r1;             // XRL A,R1 (0x03E8)
r1 = a;                 // MOV R1,A
printf("%d: 0x%x ", r2, a);
}

return a;
}
``````

The problem is that this function does not work on this newer system. I've tried all 255 possible polynomials, so it is unclear wether the algorithms are shared (perhaps with some modifications?) between the different systems, however I believe there is a relation between algorithms.

Here is a capture of some of the transmitted message from one unit:

``````7E 00 12 03 00 50 FB 01 60
7E 00 12 03 00 50 FB 01 60
7E 00 12 03 00 50 FB 01 60
7E 00 12 03 00 50 FB 01 60
7E 00 12 03 00 51 FB 01 61
7E 00 12 03 00 51 FB 01 61
7E 00 12 03 00 51 FB 01 61
7E 00 12 03 00 51 FF 01 65
7E 00 12 03 00 51 03 00 69
7E 00 12 03 00 51 09 00 6F
``````

0x7E appears to be a preamble, followed by 7 bytes of data, then the checksum byte. Can anyone figure it out?

This question seems simpler than you might expect.

Since as OP noted, the code is irrelevant to validation mechanism used in the discussed system, I shall ignore it. It is indeed irrelevant as will be shown below.

as the first byte in each message indeed looks like a preamble, we'll ignore it. Our goal is to recover the function which, when applied to the given 1-8th bytes (i.e. all bytes except the first and last), provides the last byte.

Lets take the first message provided by OP:

``````00 12 03 00 50 FB 01 60
``````

Thus, we need to find `f` such that

``````f(00 12 03 00 50 FB 01) = 60
``````

The following 3 messages are identical. This is good, it uncovers the fact the validation byte is deterministic with regards to the message bytes, but otherwise useless.

We'll skip to the fifth message and compare it to the first:

``````f(00 12 03 00 50 FB 01) = 60
f(00 12 03 00 51 FB 01) = 61
``````

This is nice, we know that a single bit incremental change in the 5th byte of the message causes the exact same change on the output. Adding one to the fifth byte increments the output by one as well.

The same happens for the last two messages:

``````f(00 12 03 00 51 03 00) = 69
f(00 12 03 00 51 09 00) = 6F

9-3 = 6 = 6F-69
``````

Only this time with a different byte and a bigger increment.

We might be willing to assume this relationship is preserved for all bytes and all increments, and we'll be correct.

If it wasn't clear until now, the answer is quite in front of us: The last byte is the sum of all message bytes, modulo 257.

In python, given `m = ['00', '12', '03', '00', '51', '09', '00']`, the following code will provide the correct value of `0x6F`:

``````hex(sum(map(lambda x: int(x, 16), m))%257)
``````

This behaves properly for all provided inputs.

• Thanks for helping! I tried your Python code, and it works correctly for the data in your example, but if you use m = ['00', '12', '03', '00', '50', 'FB', '01'] the result is 0x61, where it should be 0x60. Am I doing something wrong here? Sep 29, 2016 at 14:19
• It actually works perfectly with all of the inputs using mod 257 instead of mod 256. Thanks for the help, I don't know if I would have ever figured that out. Sep 29, 2016 at 15:35