Embedding a Checksum in an Image File

The address here could have a symbol, and then declared "extern" in the C code - it would not have to be a known numerical address. But if the image is checked or started from another program (such as a boot program), you need an absolute address somewhere to chain this all together.

Or for my preferences, the CRC "DIGEST" would be put at the end of the image, rather than near the start. Then the "from, to" range would cover the entire image except for the final CRC. But I'd have a similar directive for the length of the image at a specific area near the start.

Reply to
David Brown
Loading thread data ...

All projects I am involved with have a custom bootloader. If there is a problem with the reset vector, then the program will fail immediately. The CRC is right after the initial vector table. The bootloader application contains a copy of the vector table.

THe first thing the bootloader does is to check the CRC from right after the CRC. Then it compares the vector table with the copy.

The header is only for the application.

The last bootloader I wrote download using Y-Modem which has CRC checking. Since it had more RAM than internal flash, the whole application was downloaded to RAM first, and then when everything is OK, the flash can be programmed. Finally, the header is analyzed and the flash contents checked. There is absolutely no need to have the CRC at the end since the CRC result is stored in a known location.

/Ulf

Reply to
Ulf Samuelsson

With the timestamp located in the header, you can simply compare the non-header area. Make with __DATE__ or __TIME__ will tell you when that module is compiled, not when the program is generated. That is why TIMESTAMP is best generated in the linker.

/Ulf

Reply to
Ulf Samuelsson

The header is declared as a struct.

I really do not see a benefit of splitting the meta information about the image to two separate locations.

The bootloader uses the struct for all checks. It is a much simpler implementation once the tools support it.

You might find it easier to write a tool which adds the CRC at the end, but that is a different issue.

Occam's Razor!

/Ulf

Reply to
Ulf Samuelsson

Whatever, I did not put a lot of thought into that, and certainly did not check it. The important thing is that you can declare labels in the linker and use them in the code through extern declarations. /Ulf

Reply to
Ulf Samuelsson

app_size = .; LONG(to-from);

should work using the GNU linker. /Ulf

Reply to
Ulf Samuelsson

There are different needs for different projects - and more than one way to handle them. I find adding a CRC at the end of the image works best for me, but I have no problem appreciating that other people have different solutions.

Reply to
David Brown

Will that work when placed earlier in the link than the definition of "to" ? I had assumed - perhaps completely incorrectly - that the linker would have to have established the value of "to" before its use in such an expression.

Reply to
David Brown

Yes, the GNU linker creates a list of statements with a known size updating the location counter for each statement.

The expressions are evaluated in a later stage so you can add a DIGEST statement and compute the SIZE by "LONG(to-from);" before "to" and "from" are declared.

/Ulf

Reply to
Ulf Samuelsson

I'd be curious to know WHY it works best for you. /Ulf

Reply to
Ulf Samuelsson

I regularly do not have a bootloader - I am not free to put a CRC at the start of the image. And if the bootloader itself needs to be updatable, it is again impossible to have the CRC (or any other metadata) at the start of the image. I want most of the metadata to be at a fixed location as close to the start as reasonably practical (such as after the vector table, or other microcontroller-specific information that might be used for flash security, early chip setup, etc.). If I am to have one single checksum for the image, which is what I prefer, then it has to be at the end of the image. For example, there might be :

0x00000000 : vectors 0x00000400 : external flash configuration block 0x00000600 : program info metadata 0x00001000 : main program : CRC

There is no way to have the metadata or CRC at the start of the image, so the CRC goes at the end.

It would be possible to have two CRCs - one that covers the vectors, configuration information, and metadata and is placed second last in the metadata block. A second CRC placed last in the metadata block would cover the main program - everything after the CRCs. That would let me have a single metadata block and no CRC at the end of the image. However, it would mean splitting the check in two, rather than one check for the whole image. I don't see that as a benefit.

When making images that are started from a bootloader, I certainly /could/ put the CRC at the start. But I see no particular reason to do so - it makes a lot more sense to keep a similar format.

(Bootloaders don't often have to check their own CRC - after all, even if the CRC fails there is usually little you can do about it, except charge on and hope for the best. But if the bootloader is updatable in system, then you want a CRC during the download procedure to check that you have got a good download copy before updating the flash.)

Reply to
David Brown

It makes sense to use an 8-bit CRC on small telegrams, 16-bit CRC on bigger things, 32-bit CRC on flash images, and 64-bit CRC when you want to use the CRC as an identifying hash (and malicious tampering is non-existent). There can also be benefits of particular choices of CRC for particular use-cases, in terms of detection of certain error patterns for certain lengths of data.

What I don't see any point in is using variations, such as different initial values. I've already said why I think pathological cases such as all zero data are normally irrelevant - but I can accept that there may be occasions when they could happen, and thus a /single/ non-zero initial value would be useful.

If the CRC does not match, you reject the packet or data. End of story. You don't know or care /why/ - because you cannot be sure of any reason.

If you are transmitting some data then both sides need to agree on the CRC algorithm (size, polynomial, initial value, etc.), and on whether a check is "CRC of everything gives 0" or "CRC of everything except the pre-calculated CRC equals the transmitted pre-calculated CRC".

Well, yes. Obviously.

If you are making incorrect assumptions here, someone is doing a pretty poor job at designing, describing or implementing the communications system. It is just like getting the baud rate wrong on a UART link.

A CRC failure doesn't tell you that the telegram type is wrong. It tells you that the data is corrupted.

If there can be different protocols, or telegram types, or whatever, then identify them. Stop playing silly buggers with abuse of different concepts that have different roles in the communication system.

It is called an "initial value" - it is not "salt". It doesn't matter if you want to pick different initial values for your CRC, or why you want to do that. You are still not talking about salt.

If you insist on using your own terminology, you will be left talking to yourself.

No. They are different things.

Look, I /do/ understand what you are doing, and I appreciate that you think it is a good idea. To me, it is an unpleasant mix of orthogonal concepts that needlessly complicates things. Just because something is /possible/, does not mean it is a good idea.

I've snipped the ramblings that have nothing to do with the question I asked. I assume you don't want to answer me.

I've looked. You did not mention "OCL" anywhere before giving the URL to the wikipedia page. You only mentioned it /afterwards/ - without any context that suggests what you meant. (Here's a hint for you - if you want to refer to a wikipedia page, put a link to the /relevant/ page.)

Presumably "RMI" and "OCL" have particular meanings that are relevant for projects you work on, and are so familiar to you that they are part of your language. No one else knows or cares what they are, and they are irrelevant in this thread. So let's leave them there.

Woah, you /really/ don't understand this stuff, do you? Here's a clue - ask yourself what is being signed, and what is doing the checking.

Perhaps also ask yourself if /all/ the people involved in security for Linux or BSD - all the companies such as Red Hat, IBM, Intel, etc., - ask if /all/ of them have got it wrong, and only /you/ realise that digital signatures on open source software is useless? /Very/ occasionally, there is a lone genius that understands something while all the other experts are wrong - but in most cases, the loner is the one that is wrong.

Reply to
David Brown

For the Bootloader, I keep the CRC right after the vectors. I keep a copy of the vectors right after the CRC, and compare the two vector tables. This is to always know the location of the CRC.

You want more metadata like entry point and length, as well as text information about the image. Putting things in a header means that location is fixed. There are a number of checks in my bootloader to ensure that the information in the header makes sense.

In functional safety applications you regularily check the flash contents and refuse to boot if there is a mismatch.

/Ulf

Reply to
Ulf Samuelsson

Flash images larger than X kB may need a 64-bit CRC. I don't remember exactly when to start considering it, but something between 64kB-256kB is probably correct.

It is all to do with Hamming Distance, and this is also affected by the polynome. /Ulf

Reply to
Ulf Samuelsson

"Need" is too strong a word here. A CRC will guarantee detection of certain kinds of error (such as a single bit error), regardless of the length of the data. Some kinds of error are limited by length. If you plot a graph with guaranteed Hamming distance on the vertical scale and length of data on the horizontal scale, each CRC will drop off in steps. For the same CRC size, some will hold a high Hamming distance for longer and then drop off sharply, others will hold a lower Hamming distance for very large data. And in general, a bigger CRC will be better here.

But Hamming distance is not everything. It is important in situations where there is an approximately independent risk of corruption for each bit individually - such as during radio transmission. Programming images into flash has a completely different error risk pattern. A little Hamming is nice to guarantee that any single cell failure in the flash will be be found, but the more realistic flash problems involve large scale effects - failure to erase a block fully, or software flaws. For this kind of thing, pretty much any valid CRC polynomial works the same - a 32-bit polynomial gives you a 1 in 2 ^ 32 chance of the error going undetected. Yes, a 1 in 2 ^ 64 chance is better, but it's rarely something to get excited about.

Note that if you are sending the image to a board via a potentially flawed mechanism, you'll want appropriate checks during the transfers. Ethernet, Wifi, Bluetooth, USB - they will all have suitable checksums for each packet. And for some of those, Hamming distance and particular choice of polynomial /is/ an important consideration.

Reply to
David Brown

Fair enough - that is an entirely reasonable alternative. I have a knee-jerk reaction against duplication as a check, having cut my teeth on microcontrollers where 16 KB devices were "big", but of course a duplication of the vector table is not going to be a noticeable waste on a more modern device.

It does, however, mean extra steps in checking, compared to a simpler CRC run over the entire image.

I do have all that kind of thing too. It's only the CRC itself that is put at the end, and it is easily found since the length of the image is in the metadata. (We are talking about one pointer access more than having it at a fixed address - it's not hard to find it!).

Yes, that is a possibility.

I've worked on safety-certified systems which required things like regular checks of flash while running (not just at bootup). A lot of the so-called "safety requirements" were directly detrimental. I believe many of these kinds of requirements were made by people who understood the "Swiss cheese" model of risks and safety, but not the more realistic "Hot cheese" model. And they seem more concerned about box-ticking and legal arse-covering than actual risk reduction.

Reply to
David Brown

Programming a flash memory can flip bits in parts of the flash memory which is not programmed. Bit errors can also be introduced by radiation. Some applications require better security than others. Functional Safety may require CRC size based on code size. /Ulf

Reply to
Ulf Samuelsson

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.