The hacker’s nightmare cipher
For example, assume you use a 32-bit shared key for encoding and decoding. Work your way through the hex file and identify a spot for potential modification, for example, an immediate value or a branch address. Then based on the key and a counter (just counting through the bytes of the hex file), decide if and how to modify the value. Sometimes less is better, as huge changes can be obvious. Compilers generate code in established ways, so someone with good compiler/assembler knowledge might spot the more obvious introduced bugs.
But the wonderful thing is: could an attacker who successfully found and removed some bugs ever be sure that all introduced bugs were found?
And if you want to make it even harder for them, use a code obfuscator before running your encoding scheme. Then all relations to compiler-generated code vanish.
At Embedded Systems Academy we have used variations of this method for a while now (primarily ARM Thumb-2 code) for custom CAN/CANopen based bootloaders. The resources required are minimal; the added code overhead to an existing bootloader can be below 100 bytes, and the delay for decoding can be close to unmeasurable. Where needed, the security key can also be combined with a serial number, allowing you to provide device-specific encoded hex files.
Today, whenever we start the utility to generate an encoded hex file, we smile, almost feeling pity for the poor soul who attempts solving this by debugging. Ah well, how bad could it be? Maybe you want to give it a try? We could provide you a few examples. After all, we only introduce about 50 or so really subtle and tiny bugs... per kilobyte of code.
Before happily adapting this method, here are some things you should be aware of:
How much of the code remains real plaintext?
As stated above, our current version introduces some 50 changes in some 1000 bytes of code, so 95% remains unchanged. A hacker with access to multiple encodings can find some of the bugs. Here again, an obfuscator can help, ensuring that the differences between file versions are more than subtle.
What happens to strings?
In the version described here, all strings remain unchanged, so if you have secret information in strings, you would need to treat them separately.
What happens if code gets flashed that is not decrypted correctly (for example, using the wrong key)? Will the code be full of bugs?
For any loadable code you should have a higher level of protection (for example, your own bootloader) that only allows the flashed code to execute if it is authentic. This level should perform some non-obvious checksum/hashing test. I say non-obvious so as not to give attackers something to look for when they try to decode an encrypted hex file.
How are the keys exchanged?
This scheme uses a symmetric key (same key used to encode and to decode), and at some point the key needs to get into the embedded device. As with other security solutions, some key management will be required. A simple approach is to make the key part of the bootloader; this way your key management is limited to keeping track of which key is integrated with which bootloader version. For more advanced key management systems including CAN-based key generation, see my book Implementing Scalable CAN Security with CANcrypt.
Is it perfect?
Of course this method isn’t foolproof. One downside is that you must protect your encryption utility. As soon as hackers have access to it, they can analyze its code or try different inputs to learn exactly what it does. Even so, we sure wish all hackers working on files encoded with this method a good night’s sleep!
Olaf Pfeiffer studied technical computer science at the Cooperative University in Karlsruhe. He is one of the founders of the Embedded Systems Academy. Together with his partners, he wrote the books Embedded Networking with CAN and CANopen and Implementing Scalable CAN Security with CANcrypt. He is a regular speaker at the international CAN Conferences and other events. Olaf is chairman of the CiA 447 standardization group that defines how CANopen is used in special purpose vehicles (including police cars, taxis) and for automotive accessories.