Reverse-engineering a checksum - Page 1
Forum section: electronics / general

author: Peabody
author_rank: Super Contributor
timestamp: May 28, 2025, 05:59:11 pm
content: I've been participating in a thread on the Arduino forum that's basically about testing a large number of oddball two-button IR remotes to make sure they are working. All the reception issues have been worked out, but we've had no luck verifying the "checksum" portion of the stream.We have six data samples to work with, consisting of three remotes of this model, each with two buttons. Here are the data streams:Code:HEX----------------------------------Code Viewed As--------------------------Serial Button Code Cksum 17 bits 16 bits 2+15 bits Cksum------ ------ -- --------------- ----- ------- ------- --------- ------24664 1 11 110000001011000 00011 1e058 e058 3 6058 324664 2 00 110000001011000 01011 06058 6058 0 6058 b24869 1 11 110000100100101 10101 1e125 e125 3 6125 1524869 2 00 110000100100101 01100 06125 6125 0 6125 c24870 1 11 110000100100110 01000 1e126 e126 3 6126 824870 2 00 110000100100110 00110 06126 6126 0 6126* 6 *typo fixedThe first two bits identify the button, but they are always either 00 or 11, so we don't know if both bits are significant. The next 15 bits are the serial number of the remote in binary. And the final five bits are the checksum.It's been confirmed that the checksum is not "a linear function over GF(2) of the preceding bits", which I understand to mean it's not a CRC or Hamming code or anything simple like that. But we don't know what else to test for. Of course it could be anything, and there's no guarantee we would ever figure it out. But I thought I would see if anyone here has any ideas on solving this puzzle.

author: amyk
author_rank: Super Contributor
timestamp: May 29, 2025, 02:24:26 am
content: This might be a good start?http://www.righto.com/2017/12/decoding-air-conditioner-controls.html

author: Halcyon
author_rank: Unknown
timestamp: May 29, 2025, 03:01:30 am
content: Are you able to obtain more samples and perhaps throw them at ChatGPT to hopefully give you some more clues? It's able to do some brute forcing.

author: Peabody
author_rank: Super Contributor
timestamp: May 29, 2025, 02:40:15 pm
content: Thanks very much for the responses.I've tried the Shirriff method, but can't see any pattern that works. For all three remotes, changing the button changes only the top two bits of the input. But the effect on the checksum is completely different among the three remotes. And in the case of remotes 24869 and 24870, only the bottom two bits change if the same button is pressed. But I don't see any relationship between how the button affects the checksum for those two remotes. Unfortunately, there's no example where only one bit changes.I don't know if we can get more samples. Originally I thought having so few samples would result in finding multiple solutions, possibly dozens or hundreds, with no way to tell which one, if any, was right. But I can't find even a single solution of any kind for these six samples.It appears that a very small change of two bits completely changes the checksum. Of course CRC does that, but I've tested every possible polynomial of CRC-5, and none of them work. So I wonder if it's a cryptographic hash of some kind. I just never heard of a five-bit hash. I guess it could be the lower five bits of something like MD5 or one of the SHAs.I don't know anything about ChatGPT, and don't subscribe to it. But I would think you would have to specify what algorithm you want it to test, and of course that's what we don't know.

author: thm_w
author_rank: Super Contributor
timestamp: May 29, 2025, 09:48:06 pm
content: Gemini said first two were: ( B1 + B2 + B3<<8 ) mod 32. But then that doesn't match the rest.Is there any chance the source data is wrong? There is a typo in your last line (6126, 6216).Is it possible the device just ignores the checksum?

author: aeg
author_rank: Regular Contributor
timestamp: May 29, 2025, 11:09:56 pm
content: Remote controls have limited computational power. It's very unlikely to be a cryptographic hash.Can you change the serial number in E2PROM to generate more samples?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: May 29, 2025, 11:40:19 pm
content: What are you trying to achieve ?If you can receive any code, the hardware is working - have you seen any units that output an IR code but don't decode properly?If not then do you need to figure out the checksum at all?

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 12:30:55 am
content: Quote from: thm_w on May 29, 2025, 09:48:06 pmThanks for letting me know about the typo. But that's just my error. I'm pretty sure the binary is correct.I don't think the checksum is ignored. These remotes are used as part of an auction system, so getting the serial number right is critical. So I think the checksum confirms that the entire transmission is valid.Are you able to feed all six examples into Gemini?

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 12:40:10 am
content: Quote from: aeg on May 29, 2025, 11:09:56 pmThat was my assumption too about hashes. Some of them are very elaborate. But the remote's manufacturing process has to put its individual serial number in its code, so whatever does that could insert the checksums at the same time. There would only be two of them, one for each button. So the remote itself wouldn't actually have to calculate anything if it's done that way.I don't think it's possible to change the remote's firmware. But I will ask about getting more samples.

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 12:50:20 am
content: Quote from: mikeselectricstuff on May 29, 2025, 11:40:19 pmApparently there have been cases when a remote didn't work. I don't know the details, but they want to test all the remotes just before the auction. If we can't find the checksum solution then the alternative is to display the serial number portion as received, and compare that number to what's written on the body of the remote. But that still doesn't confirm that the checksum is being sent correctly, and that the auction computer will accept the transmission. So having the serial number match is a strong indication that the remote is working. But it would just be nice to confirm that absolutely everything is right.

author: thm_w
author_rank: Super Contributor
timestamp: May 30, 2025, 01:04:14 am
content: Quote from: Peabody on May 30, 2025, 12:30:55 amIt didn't give useful answers once you put more data in, starts referring to conditional changes in the byte order. Maybe another tool exists.Quote from: Peabody on May 30, 2025, 12:40:10 amYeah could just be a preset number.How viable is reverse engineering the code on the auction computer?

author: fzabkar
author_rank: Super Contributor
timestamp: May 30, 2025, 02:25:06 am
content: Can you make your own remote control and produce a stream of bits using any serial number you like plus 32 combinations of checksum bits, and then see which combination is accepted by the receiver?You could then vary the serial by one bit and see what effect it has on the checksum.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: May 30, 2025, 08:35:36 am
content: Quote from: Peabody on May 30, 2025, 12:50:20 amIR remotes typically have a capacitor to provide a high current IR pulse - failure of this, causing reduced range, is probably more likely than sending IR but with incorrect codes, so any testing system should be checking signal strength - this could simply be done by using a comparable distance to the normal usage.

author: aeg
author_rank: Regular Contributor
timestamp: May 30, 2025, 09:42:51 am
content: Photo of remote's PCB?

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 01:38:24 pm
content: Quote from: thm_w on May 30, 2025, 01:04:14 amThe guy doing this is very much a newb. I doubt he would risk messing things up.

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 01:42:16 pm
content: Quote from: fzabkar on May 30, 2025, 02:25:06 amIt would certainly be possible to make the remote, but the system doesn't provide any way to test remotes. So the only way to test them is to enter a bid at an auction, which they can't do. That's basically the reason for the project in the first place.

author: madires
author_rank: Super Contributor
timestamp: May 30, 2025, 02:34:52 pm
content: Are you sure that the bits listed are actually the decoded protocol data? Can you say anything about the modulation, timing, start/stop pulse or bit order?

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 03:09:47 pm
content: Quote from: aeg on May 30, 2025, 09:42:51 amThis is what he's posted of the remote.https://europe1.discourse-cdn.com/arduino/original/4X/5/d/4/5d4d2b3fc93d0705268e4f79758ede130764df47.jpegAnd here are two pictures of the receiver board:https://europe1.discourse-cdn.com/arduino/original/4X/4/6/b/46bfdd7992b9aec6096bbf1ed0650927dfbc3527.jpeghttps://europe1.discourse-cdn.com/arduino/original/4X/5/d/c/5dca6b6fab6abc8150b230e82cc0f692ef1cf893.jpegAs you can see, this is an ancient system. All through-hole, with date codes back into the 90's. And I think I see what must be custom ROM chips. I just don't think he would risk taking them out, nor would I suggest he do that.But the age of the system does make you wonder what they would have done for the checksum back then.

author: Andy Watson
author_rank: Super Contributor
timestamp: May 30, 2025, 04:01:25 pm
content: Quote from: Peabody on May 30, 2025, 03:09:47 pmWhat is the number of the 16-pin chip on that board (IC1)?

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 04:20:26 pm
content: Quote from: madires on May 30, 2025, 02:34:52 pmYes, I'm sure. He's using my code. :-)I wasn't going to get into the transmission details because they are truly oddball. But basically, instead of having a 38KHz carrier which is turned on and off every few hundred microseconds, the data is encoded in variations in the carrier frequency. Each carrier full wave is either short (zero) or long (one). So successive carrier cycles look like this (in microseconds):Code:42 44 43 42 26 26 27 27 27 30 41 28 41 43 29 27 26 25 26 27 44 46 165342 45 41 43 26 28 26 27 27 26 45 28 42 42 28 25 26 27 27 26 45 46 205343 43 43 42 28 25 27 27 26 27 44 29 41 42 29 27 27 27 27 26 41 46 252443 43 43 43 28 25 26 27 27 26 45 28 42 42 28 25 26 27 27 30 41 46 257844 43 42 43 28 25 26 27 27 27 44 28 41 43 28 25 27 26 27 30 41 46 241443 43 43 43 24 28 27 27 26 27 44 28 43 42 27 28 24 26 31 26 41 47 193343 42 43 42 26 30 27 27 27 26 42 28 41 43 28 24 27 27 30 27 41 46 48229442 42 43 43 29 27 26 27 27 27 41 28 41 46 26 26 27 27 27 27 41 46 226042 43 42 44 28 28 26 27 26 27 41 29 41 46 25 28 26 27 27 27 41 46 966The first two bits are the button code, and the next 15 bits are the remote's serial number, followed by the 5-bit checksum.So the entire transmission is sent in what would be the first ON period of the NEC protocol. In fact, a standard TSOP IR receiver module demodulates it as continuous 38KHz carrier.Now it could be argued that since the code is repeated dozens of times on each button press, you don't really need a checksum. So it may be that the checksum is just an anti-competitive feature to prevent anyone else from making the remotes, which are probably expensive. That would be my guess. The entire system seems to be an exercise in obfuscation.

author: tom66
author_rank: Super Contributor
timestamp: May 30, 2025, 04:25:38 pm
content: That's not that unusual, it's known as BFSK (binary frequency shift keying). Common in radio ... not that common in IR, but if you are receiving the signal directly via a photodiode (rather than an IR receiver IC), there's no reason you -couldn't- do it that way, I guess.

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 04:28:13 pm
content: Quote from: Andy Watson on May 30, 2025, 04:01:25 pmI only have the pictures, and I can't quite make it out, except "1092", which could be a date code.

author: bobxyz
author_rank: Contributor
timestamp: May 30, 2025, 06:21:21 pm
content: Is the serial number written on the remotes all in decimal, no hex digits? Does it match the digits in the 15-bit code, or in other words, is it BCD encoded? If so, have you tried converting the 4? digit BCD serial number to hex before checksum analysis?If it helps, I recognize the jumbo processor chip in the last picture. It's a Hitachi 6303 from the late 1980s, and is a 2MHz romless variant of the Motorola 6800. The Hitachi Databook, with example math routines, is available here:https://bitsavers.org/components/hitachi/_dataBooks/1989_U07_HD6301_HD6303_Series_Handbook_1989.pdf

author: Peabody
author_rank: Super Contributor
timestamp: May 30, 2025, 09:17:47 pm
content: Quote from: bobxyz on May 30, 2025, 06:21:21 pmThe serial numbers on the remotes are in decimal, and the numbers match the 15-bit straight binary values in the transmission. It's not BCD. Serial number 24664 is binary 110000001011000. The hex versions of everything are in the table in the first post.

author: tom66
author_rank: Super Contributor
timestamp: May 30, 2025, 11:24:38 pm
content: I did a fairly exhaustive search of possibly polys for various-length CRCs (up to 16 bit polynomial) which might be masked down and shifted to calculate this CRC. I also added all possible rotations into the search, as well as XOR on the input and output and reversal on the input and output. Nothing matched more than 4 out of the 6 inputs (there were many matches for 3/6 which is probably just statistical coincidence), so I am pretty confident it is not a CRC, unless there is something really strange like selecting N bits from the output CRC and shuffling them somehow but there are so many more combinations. Given the simplicity of the processor, I suspect the algorithm is fundamentally quite simple, but may only be something you can determine with many more inputs and something more sophisticated like differential cryptanalysis. At that point I suspect it would be easier to just dump the ROM and reverse engineer it.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: May 30, 2025, 11:31:50 pm
content: Quote from: tom66 on May 30, 2025, 11:24:38 pmDefinitely - if you can find a disassembler it shouldn't be too hard to locate the decoding code & figure out what it does.getting at the transmitter code, though smaller and easier to reverse, might be less helpful as it's possible the sum is precalculated & programmed in.

author: Peabody
author_rank: Super Contributor
timestamp: May 31, 2025, 02:37:01 pm
content: @tom66, thanks for doing the CRC analysis. I had done something similar, with the same result. I also tested whether each bit of the checksum is equal to the XOR of selected bits of the data, with the same pattern working for all six inputs, but that produced nothing as well.

author: amyk
author_rank: Super Contributor
timestamp: June 01, 2025, 03:55:14 am
content: Given the age and application it might not be a CRC, but something more like a Luhn checksum.Of course, if it was a regular CRC just run through a 32-entry substitution table ("s-box" in crypto terminology), that could also explain the apparent lack of patterns in the output.

author: m k
author_rank: Super Contributor
timestamp: June 01, 2025, 10:09:01 am
content: Lookup table for byte+byte is pretty easy.

author: Peabody
author_rank: Super Contributor
timestamp: June 01, 2025, 01:57:09 pm
content: Yes, it could be something arbitrary like an S-box or lookup table. In which case the odds of finding it would be pretty low. And we would need lots more data samples. Well, thanks to everyone for the comments and suggestions.

author: bobxyz
author_rank: Contributor
timestamp: June 01, 2025, 04:08:56 pm
content: Looking at the pictures, I'd guess the base station was designed in the late 1980s or early 1990s. If it was any later, it would use a better processor, such as 68HC11. The PCB is all through-hole, with datecodes in the early 1990s.The remote picture is a much more modern design - reasonably closely packed SMT components, and a QFN-16. Those didn't exist in the early 1990s. Maybe the remote is a compatible replacement design for whatever the original was. It looks like the remote has a big blue crystal/oscillator near the test connector. I'm wondering if there's a MCU on the bottom of the board, and that the QFN is a SMPS chip since it's next to the coil.Assuming the protocol and base station code was from the early 1990s, I'd be looking for a simple checksum, maybe with an extra adder per byte. I'd expect the hardware to pack bits into 8-bit bytes with no gaps. Maybe LSb first (like RS-232) or maybe MSb first to match the human readable serial numbering. The checksum might also be a truncated CRC-16 (CCITT or IBM). CRC and fancier hashes weren't common knowledge in the early 1990s, and there was a field of patents to avoid.The base station picture shows a baud rate crystal 4.9152MHz = 9600 * 16 * 32. This would give a 6303 core clock rate of ~1.2MHz, or really roughly 130 instructions per protocol byte, which doesn't give much for handling/checking checksums. I'd expect the checking to be calculated on-the-fly, vs. using a table.

author: nfmax
author_rank: Super Contributor
timestamp: June 01, 2025, 04:40:50 pm
content: When I needed to do this I had success with RevEng -https://reveng.sourceforge.io/

author: Peabody
author_rank: Super Contributor
timestamp: June 01, 2025, 06:23:44 pm
content: Quote from: bobxyz on June 01, 2025, 04:08:56 pmYes, I assume they continue to make the remotes, and probably had to go to surface mount at some point. I'll ask about an MCU on the bottom, but I thought that was the QFN.QuoteCould you explain "extra adder"?We know it's MSB because that's what produces the remote's serial number. And remember, we're essentially talking about two bytes - 16 bits, or possibly 17.@tom66 and I have both tried every possible CRC polynomial, not just CRC-5, but up to 16, and didn't find anything. So if it's a CRC, the result must be messed with, just to confuse me.I have a theory that I need you guys to validate. It says that any algorithm that consists only of XORs, such as CRC, will always have a solution such that each bit of the checksum can be expressed as the XOR of certain specific bits of the input data, and those bits will work for the same checksum bit in all samples. Has anybody heard of such a thing? I asked ChatGPT, and got confirmation, if it's not halucinating:Code:Q. Is it true that for any CRC, each bit of the final result can be expressed as the exclusive-orof some specific selection of bits of the input, and the same selected bits will produce thatoutput bit for all samples?A. ... Because of this linearity, each bit in the CRC result is a linear combination (i.e. XOR) of a specific subset of the input bits.More precisely: Each output bit of the CRC depends on a fixed pattern of input bits determined by the CRC polynomial and the message length.This means:* For a given CRC polynomial and message size, the bit positions in the input that influence each bit in the output are fixed.* These patterns do not depend on the values of the inputs, only on their positions and the polynomial used.* The transformation is deterministic and reproducible.So I wrote software that tests every possible selection of bits, but found nothing that works for all six samples. That would suggest it's not a CRC, but again, inverting or reversing or otherwise playing with the result still might hide that.

author: Peabody
author_rank: Super Contributor
timestamp: June 01, 2025, 06:30:05 pm
content: Quote from: nfmax on June 01, 2025, 04:40:50 pmIt's hard to tell, but it looks like it's for Linux, which I don't have. In any case, I can't find any evidence that it's a CRC.Edit: No, I see a Win32 binary in the zip file.

author: Peabody
author_rank: Super Contributor
timestamp: June 01, 2025, 10:11:47 pm
content: So let me back up a little on the XOR of specific input bits to get a checksum bit.When I run my program on either 16-bit input (0-15) or 17-bit (0-16), I get the following results:Bits 0, 1, 2 and 4 of the checksum have no solutions, no pattern of XORed input bits that produces the checksum bit.Bit 3 of the checksum has 4096 solutions:Code:15 3 015 3 2 115 4 015 4 2 115 5 3 115 5 3 2 015 5 4 115 5 4 2 015 6 015 6 2 115 6 4 3 015 6 4 3 2 1...15 14 13 12 11 10 9 8 7 5 4 015 14 13 12 11 10 9 8 7 5 4 2 115 14 13 12 11 10 9 8 7 6 115 14 13 12 11 10 9 8 7 6 2 015 14 13 12 11 10 9 8 7 6 4 3 115 14 13 12 11 10 9 8 7 6 4 3 2 015 14 13 12 11 10 9 8 7 6 5 015 14 13 12 11 10 9 8 7 6 5 2 115 14 13 12 11 10 9 8 7 6 5 4 3 015 14 13 12 11 10 9 8 7 6 5 4 3 2 1Note that all solutions include bit 15, which is the button indicator.So I wondered if they had just XORed the checksums with 0b10111. But when I did that, I still get no solutions on those four bits. If I invert bit 3, I still get 4096 solutions, all including input bit 15, but the solutions are otherwise different from the non-inverted round.If I exchange checksum bits, or reflect them, or shift them, I still only get a solution on the bit which used to be bit 3. I think this all stands to reason.So I think this all means that, with the possible exception of checksum bit 3, the checksum is not a linear function of the input, at least not one involving no-carry manipulations like XOR. But regular addition-with-carry, or multiplication, would still be possible. It's still just a seemingly impossible task to find what they've done.

author: nctnico
author_rank: Super Contributor
timestamp: June 01, 2025, 10:22:42 pm
content: I'd go and try to disassemble the code at this point. This has worked the best for me in similar cases. Chances are the creator has dreamed up something completely odd.

author: dietert1
author_rank: Super Contributor
timestamp: June 01, 2025, 10:35:27 pm
content: Don't know whether it has been dismissed before, but one could try error correction codes. If i remember right it works roughly like this: One parity bit for all data bits, another parity with every second data bit inverted, another with every two out of 4 consecutive data bits inverted and so on. Should give 5 parity bits for a number of data bits between 16 and 32. The receiver can locate and correct a single bit transmission error.Regards, Dieter

author: bobxyz
author_rank: Contributor
timestamp: June 02, 2025, 12:57:05 am
content: For simple checksums, you'd like to be able to detect common failures. If it's just a sum, then an all 0's message, for instance from broken/shorted hardware, will pass as good. To prevent this, you can start with a non-zero sum (e.g. 0xa5 or the designer's initials), or add the byte number (1,2,3,...) with each byte. This was more common for variable length messages, and not a fixed ~3 byte message. For the sum itself, the carry could be added back in or dropped. Other options would be to rotate the 8-bit sum by 1 bit after summing in each byte.For the protocol, I'd guess that the original supported 4 different buttons and that it's still 17bits+5bits. As an auction system, you'd like a "bid" and a "pass" button. I don't know what the other 2 would be, but most designers would include a little extra capability (if only to avoid the taunts from other engineers or co-workers of re-inventing the garage door opener).Some PROM programmers from the early 1990s had the capability to insert a few byte serial number that counted up by 1 for each device programmed. They did not have any capability of inserting specific bytes based on the serial number.

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 02:14:16 am
content: Quote from: dietert1 on June 01, 2025, 10:35:27 pmCan you point me to a data sample using this method? I haven't found anything like what you describe.

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 02:48:35 am
content: Quote from: bobxyz on June 02, 2025, 12:57:05 amYeah, but I just haven't found anything like that that works. Consider these two samples, where the inputs differ only by the two LS bits:Code:HEXButton Order --------------------------------------- Code Viewed As----------------Serial Button Code Cksum 17 bits 2+15 bits Cksum------------- ------------------ ----- ------- --------- ------24869 1 11 110000100100101 10101 1e125 3 6125 1524870 1 11 110000100100110 01000 1e126 3 6126 8Yet the checksum more than doubles, and four of the five checksum bits are flipped. I just can't get there.

author: tom66
author_rank: Super Contributor
timestamp: June 02, 2025, 09:16:00 am
content: Out of interest, if you send the 'wrong' checksum to the receiver, does the receiver still respond to the message? Perhaps toggling the odd bit here or there will give you clues. For instance, if it is a form of Hamming code, then toggling any one bit in the checksum should still allow the message to be successfully decoded, since Hamming codes can correct errors in both the message and in themselves.

author: dietert1
author_rank: Super Contributor
timestamp: June 02, 2025, 09:51:37 am
content: A CRC shifter with two XOR inputs can double the number of changed bits. The algorithm could be like thiscrc = initfor each data bitif (data bit) crc ^= 01010rotate left crc in 5 bitsThe last five crc values will be xxxxx (previous value), xyxyx (y = second last data bit change), yxyxx (rotate left), yzyzx (z = last data bit change), zyzxy (rotate left). With two last data bits changed, four CRC bits changed. I did not check anything else.Regards, Dieter

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 01:49:25 pm
content: Quote from: dietert1 on June 02, 2025, 09:51:37 amThanks, but I'm having trouble understanding this. Could you show the steps with a specific sample?Edit: Ok, I think I understand. You rotate the five bits on each input bit, but if that bit is a one, you first XOR with 1010. I'll see if that works.

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 01:56:45 pm
content: Quote from: tom66 on June 02, 2025, 09:16:00 amApparently there's no way to send a test sequence into the receiver, other than in an actual auction, which they can't do. The reason for this project in the first place is because there's no way to just test that a remote is working.

author: tom66
author_rank: Super Contributor
timestamp: June 02, 2025, 02:04:53 pm
content: Quote from: Peabody on June 02, 2025, 01:56:45 pmYou say 'auction'; is this a case of buying equipment sight-unseen otherwise (and use of the remote would allow one to determine if it is functional), or are you talking about something else?

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 02:16:01 pm
content: The remote is used in the bidding process. The posted price is reduced until some bidder presses a button on the remote which was assigned to him. He wins the auction at that price. That's my understanding.

author: dietert1
author_rank: Super Contributor
timestamp: June 02, 2025, 04:17:21 pm
content: Quote from: Peabody on June 02, 2025, 01:49:25 pmI was looking at your own examples:Code:24869 1 11 110000100100101 10101 1e125 3 6125 1524870 1 11 110000100100110 01000 1e126 3 6126 8The pseudocode i showed changes 4 checksum bits from 2 changed data bits and leaves the one checksum bit that doesn't change untouched (x = previous value, same in both examples). Of course, if that is the wanted algorithm, one would rather not shift bitwise but xor groups of 5 data bits and then simulate the second CRC input at the end, something likeCRC = CRC ^ (rotate CRC left twice).Mere obfuscation, yet your two examples served for differential analysis.Regards, Dieter

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 05:26:51 pm
content: But unless I misunderstand, you did not actually calculate the CRC using this method and get 10101 at the end. It's just a way to get the number of changed bits that I got. Right?I continue to wonder about the result I got in post #34 - seeing which checksum bits can be expressed as the XOR of specific input bits. Bit 3 was the only bit that showed such a relationship, and one of the solutions found for that bit was, excluding input bit 0, the parity bit of the entire bit string, and it works for all six samples.15 14 13 12 11 10 9 8 7 6 5 4 3 2 1Of course with so few samples, that may just be coincidence. In any case, it seems bit 3 of the checksum is the only bit that is manipulated exclusively by XORs and ANDs and is not rotated or shifted. The other four are something else. And I don't see why a parity bit would be placed in the bit 3 position, other than more obfuscation.

author: nctnico
author_rank: Super Contributor
timestamp: June 02, 2025, 05:46:37 pm
content: Quote from: Peabody on June 02, 2025, 02:16:01 pmThis whole thing sounds a bit iffy to me. Why can't they test with the auction system itself? It almost sounds like somebody wants to make a device to cheat with the auction process but doesn't have access to the hardware.Since auctions are used for financial transactions, it is likely the checksum is obfustigated on purpose so it also serves the function of authorising the transmitters.

author: dietert1
author_rank: Super Contributor
timestamp: June 02, 2025, 06:06:08 pm
content: Yes, i understand, let's stop here.

author: tooki
author_rank: Super Contributor
timestamp: June 02, 2025, 06:26:58 pm
content: It strains credulity that an auction house:- would insist on relying on an ancient system, instead of investing in a new one every 20-30 years- cannot hold a test auction, where people bid on, i dunno, a cubic meter of unpackaged air from the room, with bidding in 1 cent increments.Besides, if cases are known of them not working reliably, what’s more likely:- that the remote is actually sending incorrect codes?- that multiple remotes were pressed simultaneously, causing them to stomp on the other’s signal?

author: aeg
author_rank: Regular Contributor
timestamp: June 02, 2025, 07:35:05 pm
content: Quote from: Peabody on June 02, 2025, 01:56:45 pmPoint it at a cellphone camera and see if it lights up?

author: Peabody
author_rank: Super Contributor
timestamp: June 02, 2025, 09:45:16 pm
content: The OP on the Arduino forum decided to settle for displaying the serial number and button number in response to a test firing of the remote, thinking that if those were right, the remote was working. It was me and a couple others there who thought it would be cool to get the checksum too. And, you know, there's the challenge of figuring it out. But if some of you aren't comfortable with it, it's probably best to drop it. I've pretty much hit a brick wall anyway. But thanks to those who contributed.

author: fzabkar
author_rank: Super Contributor
timestamp: June 04, 2025, 05:35:04 pm
content: Quote from: Peabody on May 31, 2025, 02:37:01 pmWould either of you mind providing your code for public access? I often have need for such a tool, but I haven't studied the mathematics.

author: tom66
author_rank: Super Contributor
timestamp: June 04, 2025, 05:52:46 pm
content: Well, it's bloody ugly, but if you want...Code:import randomdata_list = [("11110000001011000", "00011"),("00110000001011000", "01011"),("11110000100100101", "10101"),("00110000100100101", "01100"),("11110000100100110", "01000"),("00110000100100110", "00110")]def bit_by_bit_crc(binary_data, generator, initial_crc='0'):padded_data = binary_data + '0' * (len(generator) - 1)remainder = padded_data[:len(generator)]for i in range(len(generator), len(padded_data)):if remainder == '1':remainder = xor(remainder, generator)else:remainder = xor(remainder, '0' * len(generator))remainder = remainder[1:] + padded_dataif remainder == '1':remainder = xor(remainder, generator)else:remainder = xor(remainder, '0' * len(generator))return remainder[1:]def xor(a, b):"""Bitwise XOR of two binary strings of equal length."""return ''.join('0' if i == j else '1' for i, j in zip(a, b))def rotate(strg, n):return strg[n:] + strg[:n]for r_in in range(0, 2):for x_in in range(0, 2):for r_out in range(0, 2):for x_out in range(0, 2):for l in range(5, 16):for p in range(2**l):for n in range(10):for r in range(l):p_str = format(p, '0' + str(l) + 'b')n_match = 0for index, (d, match_c) in enumerate(data_list):if r_in:d = d[::-1]if x_in:d = xor(d, "1" * len(d))cksum = bit_by_bit_crc(d, p_str)if r_out:cksum = cksum[::-1]if x_out:cksum = xor(cksum, "1" * len(d))cksum = rotate(cksum[n:n+5], r)if match_c == cksum:n_match += 1if (n_match >= 3) and (n_match < 5):print(n_match, " matches with poly " + format(p, '0' + str(l) + 'b') + " offset ", n, " rotate ", r)elif (n_match >= 5):print("**** ", n_match, " matches with poly " + format(p, '0' + str(l) + 'b') + " offset ", n, " rotate ", r)ChatGPT helped with the CRC generator, since I was lazy.

author: bobxyz
author_rank: Contributor
timestamp: June 04, 2025, 07:56:56 pm
content: You may find the below resources helpful:wikipedia - CRC and older error correcting codeshttps://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checkshttps://en.wikipedia.org/wiki/Hamming_codehttps://en.wikipedia.org/wiki/Cyclic_codehttps://en.wikipedia.org/wiki/Burst_error-correcting_code#Fire_codeshttps://en.wikipedia.org/wiki/BCH_codehttp://www.ross.net/crc/See "A Painless Guide to CRC Error Detection Algorithms" by Dr. Ross Williams(also see "CRC Resources On The Net" for examples of what was commonly available in 1996)https://sourceforge.net/projects/reveng/"CRC RevEng is a portable, arbitrary-precision CRC calculator and algorithm finder. Itcalculates CRCs using any of the 113 preset algorithms, or a user-specified algorithmto any width. It calculates reversed CRCs to give the bit pattern that produces a desiredforward CRC. CRC RevEng also reverse-engineers any CRC algorithm from sufficient correctlyformatted message-CRC pairs and optional known parameters. It comprises powerful inputinterpretation options. Compliant with Ross Williams' Rocksoft(tm) model of parametrisedCRC algorithms."https://crc-reveng.septs.app/Web based version of above CRC RevEng code - think of it as a DOS window where you can typein and run reveng commands directly.I think that the Rocksoft Reflection property is controlled by the reveng -l -b -L -B flags(little and big endian on input and output).reveng has the ability to search for a known CRC algorithm, or a range of polys, that matchesa group of example messages and CRCs. For instance, a simple search for a 5-bit CRC that matchesthe 6 examples in this thread would be (the -a and -A flags specify binary input/output):reveng -w 5 -a 1 -A 1 -s 1111000000101100000011 0011000000101100001011 1111000010010010110101 0011000010010010101100 1111000010010011001000 0011000010010011000110Unfortunately, the result is:reveng: no models foundI haven't played around with the search capabilities over a polynomial range. This ?might? bebetter documented in the reveng support forum:https://sourceforge.net/projects/reveng/support

author: Peabody
author_rank: Super Contributor
timestamp: June 04, 2025, 09:51:57 pm
content: The other thing I tried was to see if each bit of the checksum can be expressed as the XOR of specific bits of the input, with the same bits working for that checksum bit position on all samples. Below is my Arduino code running on 118 samples of the IR keyboard and mouse of the Windows Media Center Edition (from back in the day), and below that the output. Notice that it finds two solutions for each bit.This doesn't tell you how the checksum is calculated - CRC should have solutions by this method, but other checksum algorithms could as well. So it's kinda like dealing with raw IR instead of protocol/address/command.Code:/*Snoop_XOR.inoThis code tests multiple samples of data and its "checksum" to seeif each bit of the checksum can be represented as the exclusive-Orof specific bits of the data. It tests all possible bit patterns,and reports for each bit of the checksum all patterns which work forall data samples.If the number of samples is small, there may be many patterns that,by chance, appear to work. It may be necessary to input a large numberof samples to get down to one solution per bit. And even then, unlessyou input all possible data samples, there is no guarantee that theone solution is universally valid.Make sure the dataSize and checkSize definitions are correct.*/// PICK or NOT//#define CHECKBITS_INVERTED // checksum may be invertedconst unsigned long sample[] PROGMEM = {{0b0000010000000000, 0b01111}, // data, checksum{0b0000010100000000, 0b00010}, // these are Windows Media Center Edition{0b0000011000000000, 0b00001}, // IR keyboard - 104 keys plus mouse{0b0000100000000000, 0b10001},{0b0000100100000000, 0b11100},{0b0000101000000000, 0b11111},{0b0000101100000000, 0b10010},{0b0000110000000000, 0b11110},{0b0000110100000000, 0b10011},{0b0000111000000000, 0b10000},{0b0000111100000000, 0b11101},{0b0001000000000000, 0b10010},{0b0001000100000000, 0b11111},{0b0001001000000000, 0b11100},{0b0001001100000000, 0b10001},{0b0001010000000000, 0b11101},{0b0001010100000000, 0b10000},{0b0001011000000000, 0b10011},{0b0001011100000000, 0b11110},{0b0001100000000000, 0b00011},{0b0001100100000000, 0b01110},{0b0001101000000000, 0b01101},{0b0001101100000000, 0b00000},{0b0001110000000000, 0b01100},{0b0001110100000000, 0b00001},{0b0001111000000000, 0b00010},{0b0001111100000000, 0b01111},{0b0010000000000000, 0b10011},{0b0010000100000000, 0b11110},{0b0010001000000000, 0b11101},{0b0010001100000000, 0b10000},{0b0010010000000000, 0b11100},{0b0010010100000000, 0b10001},{0b0010011000000000, 0b10010},{0b0010011100000000, 0b11111},{0b0010100000000000, 0b00010},{0b0010100100000000, 0b01111},{0b0010101000000000, 0b01100},{0b0010101100000000, 0b00001},{0b0010110000000000, 0b01101},{0b0010110100000000, 0b00000},{0b0010111000000000, 0b00011},{0b0010111100000000, 0b01110},{0b0011000000000000, 0b00001},{0b0011000100000000, 0b01100},{0b0011001100000000, 0b00010},{0b0011010000000000, 0b01110},{0b0011010100000000, 0b00011},{0b0011011000000000, 0b00000},{0b0011011100000000, 0b01101},{0b0011100000000000, 0b10000},{0b0011100100000000, 0b11101},{0b0011101000000000, 0b11110},{0b0011101100000000, 0b10011},{0b0011110000000000, 0b11111},{0b0011110100000000, 0b10010},{0b0011111000000000, 0b10001},{0b0011111100000000, 0b11100},{0b0100000000000000, 0b10100},{0b0100000100000000, 0b11001},{0b0100001000000000, 0b11010},{0b0100001100000000, 0b10111},{0b0100010000000000, 0b11011},{0b0100010100000000, 0b10110},{0b0100100100000000, 0b01000},{0b0100101000000000, 0b01011},{0b0100101100000000, 0b00110},{0b0100110000000000, 0b01010},{0b0100110100000000, 0b00111},{0b0000000000000001, 0b00011},{0b0000000000000010, 0b00101},{0b0000000000011000, 0b01110},{0b0000000111100100, 0b00110},{0b0000101000010100, 0b10000},{0b0000110000000000, 0b11110},{0b0000111111100000, 0b10000},{0b1111001000000000, 0b01110},{0b1111010111101000, 0b01000},{0b1111011000010100, 0b01110},{0b1111010000000001, 0b01100},{0b0000101000000001, 0b11100},{0b0000000111101101, 0b00010},{0b0000000000010101, 0b01100},{0b1111011000010101, 0b01101},{0b0000101000010101, 0b10011},{0b1111010111101001, 0b01011},{0b0000111111100001, 0b10011},{0b0100111000000000, 0b00100},{0b0100111100000000, 0b01001},{0b0101000000000000, 0b00110},{0b0101000100000000, 0b01011},{0b0101001000000000, 0b01000},{0b0000000000000001, 0b00011},{0b0000000000000010, 0b00101},{0b0000000000000100, 0b00110},{0b0000000000001000, 0b00111},{0b0001111000000010, 0b00111},{0b0001111100000010, 0b01010},{0b0010000000000010, 0b10110},{0b0010000100000010, 0b11011},{0b0010001000000010, 0b11000},{0b0010001100000010, 0b10101},{0b0010010000000010, 0b11001},{0b0010010100000010, 0b10100},{0b0010011000000010, 0b10111},{0b0010011100000010, 0b11010},{0b0010011100000010, 0b11010},{0b0010110100000010, 0b00101},{0b0010111000000010, 0b00110},{0b0011010100000010, 0b00110},{0b0011011000000010, 0b00101},{0b0010111100100000, 0b00100},{0b0011000000100000, 0b01011},{0b0011000100100000, 0b00110},{0b0011001100100000, 0b01000},{0b0011010000100000, 0b00100},{0b0011011000100000, 0b01010},{0b0011100000100000, 0b11010}};const int Samples = sizeof(sample) / sizeof(sample); // number of samplesconst byte dataSize = 16; // number of bits (max = 32)const byte checkSize = 5;unsigned long target; // bit pattern being testedunsigned long checkBit;unsigned long thisSample, andTarget, thisCheck, andCheck;byte dTemp, cTemp;int i, x, z;unsigned long data2n; // number of possible data valuesvoid setup() {if (dataSize == 32) data2n = (long) ~0;else data2n = ((long)1 << dataSize) - 1;delay(3000);Serial.begin (9600);#if defined CHECKBITS_INVERTEDSerial.println("CHECKBITS_INVERTED\n");#endifSerial.print (Samples); Serial.println(" samples");for (z = 0; z < checkSize; z++) { // for each checksum bitSerial.print ("Checksum Bit "); Serial.println(z);target = 1;checkBit = 1 << z;while (target <= data2n) { //for each possible target valuefor (x = 0; x < Samples; x++) { //test all samples until one failsthisSample = pgm_read_dword_near(&sample); // the data part of samplethisCheck = pgm_read_dword_near(&sample); // the checksum partapply(); // XOR the 1 bits that match the targetandCheck = thisCheck & checkBit; // isolate the bit, andcTemp = (andCheck != 0); // move to bit zero#if defined CHECKBITS_INVERTEDif (cTemp == dTemp) break; // if no match,#elseif (cTemp != dTemp) break; // go to the next target value#endifif (x == Samples - 1) {output(); // if we get here, we have a match// target = data2n; // print just the first one}}if (target == data2n) break; // all targets tested, exit while looptarget++; // go to next target}}Serial.println("Complete");}void apply() { // XOR each bit of data that matchesdTemp = 0; // a 1 bit in the targetandTarget = thisSample & target;for (i = 0; i < dataSize; i++) {if (andTarget) {dTemp ^= (andTarget & 1);andTarget >>= 1;}else break;}}void output () {for (i = dataSize - 1; i >= 0; i--) {if (target & (1 << i)) {Serial.print(" ");if (i < 10) Serial.print(" ");Serial.print (i);}}Serial.println();}void loop() {}Code:118 samplesChecksum Bit 015 13 11 10 8 6 4 3 1 015 13 11 10 8 7 4 3 1 0Checksum Bit 113 12 10 9 6 5 3 2 013 12 10 9 7 5 3 2 0Checksum Bit 215 14 10 9 8 6 3 2 115 14 10 9 8 7 3 2 1Checksum Bit 310 9 8 5 410 9 8 7 6 5 4Checksum Bit 415 14 13 12 1115 14 13 12 11 7 6Complete