As stated, your problem is simple. What you want is to embed in
B_trusted a hash value, which is the result of hashing the concatenation of the "hardware key" and the second stage bootloader code. As long as the contents of
B_trusted are indeed free from alterations, and the hash function is second preimage resistant, then the attacker will not be able to come up with an altered version of the second stage bootloader that
B_trusted will accept to load and run.
No need to fiddle with encryption here; a simple hash suffices. However, this assumes that the two following properties are maintained:
B_trusted cannot be altered by the attacker.
- Each individual device can get its own
B_trusted personalized with the proper hash value.
B_trusted is considered free of alterations because it is in some ROM, then it may be hard to indeed personalize its value for each device; it would have to be at least partly PROM and this may raise costs. An additional problem is that such a scheme precludes the possibility of firmware updates: once
B_trusted is fixated with a hash value, it will load only one specific second-stage bootloader. The attacker cannot make an alternate version, but you neither. Hash functions make no prisoners.
To solve these potential issues, you have to use cryptography, and, in particular, keys. A key is something secret and its value is exactly the measure of how it is unknown to the attacker.
A first solution attempt is to use a MAC. That's what your construction amounts to: a custom, homemade MAC, by encrypting a hash output. In cryptography, "homemade" is a synonym for "probably weak". Instead, use an actual MAC. Since you have access to a hash function, then use HMAC. Compute HMAC over the second stage bootloader code, using the "hardware key" as key for HMAC; the second stage bootloader header contains the MAC value, and
B_trusted checks that it matches what it has recomputed.
This ensures that the second stage bootloader is tied to the hardware, and an altered version will not be loaded, unless it was produced by you, because, using your knowledge of the "hardware key", you can compute the HMAC output for any ulterior bootloader version. However, this works only as long as the "hardware key" is secret. And that's not a given. Indeed, most of the time, such hardware keys are not secret; the attacker can recompute them. They are bound to the hardware and thus cannot be changed by the attacker, but if he knows that "key" then he can recompute MAC values at will.
In fact, I bet that your "hardware key" is not a key in the cryptographic sense; let's call it an "hardware identifier".
To fix that, we need a digital signature. The scheme is the following:
- There is a unique asymmetric key pair (say, RSA) with a public key Kp and a private key Ks.
- The first stage bootloader
B_trusted contains a copy of the public key Kp.
- The second stage bootloader is tied to the hardware and signed: for device with identifier I, a signature is computed (in factory) over the concatenation of I and the code of
B. That signature is added to
B as a header.
B_trusted runs, it obtains I from the hardware, and verifies the signature on
This scheme does everything you want:
B_trusted is the same for every device instance, bit to bit. It can be mass-produced in ROM.
B_trusted contains anything secret, so there is nothing that would be a problem if the attacker reverse-engineered the whole lot.
- You, as the owner of Ks, can generate signatures at will. When you sign a second stage bootloader, you are actually authorizing that specific version to run on the hardware whose identifier you include in the signature input. Firmware updates are now possible.
Technologically, this method implies the following:
- You must add a header to the second-stage bootloader, with a signature value. A strong 2048-bit RSA signature has size 256 bytes. If that size overhead is not tolerable in your situation, you may try to use DSA or ECDSA (a good, strong signature of the same strength will be down to 56 bytes).
B_trusted must do a signature verification. RSA signature verification is efficient; it begins by hashing, then uses the hash value in a mathematical operation which can be completed by an anemic ARM core in less than 100000 clock cycles. I don't know what your system hardware is, but it seems improbable that you could not contrive to use a RSA signature verification (DSA and ECDSA imply higher costs, but maybe usable as well).