Decrypt Locked LPC2101FBD48 Program: The Gate Is Not a Cipher
The first sentence of most enquiries about this part is a vocabulary problem. Somebody has a board with an LPC2101FBD48 on it, the debugger refuses to attach, and the request arrives as a request to decrypt the program. That framing sets an expectation that cannot be met, because there is nothing on this device that encrypts the flash array in the first place.
The instruction memory of an LPC2101 is plain. If you can read it, you read ARM code, immediately, with no post-processing step and no secret. What blocks you is not mathematics but a permission bit — a single control word that the boot loader and the debug logic both consult before they will let a byte leave the array.
Understanding that difference changes what a job on a locked part can realistically deliver, and it changes the order in which you attack the unit.
What the protection actually is
The mechanism is called Code Read Protection, and on every member of this family it is implemented the same way: one 32-bit value stored in the last four bytes of flash sector 0. That location is deliberate. It is inside the first erase block, so it cannot be changed without touching the sector that holds the reset vector, and it is the first thing the boot loader examines after reset.
There is no key register, no decryption engine, no per-device secret fused at test. The value written there is a constant that anybody can look up in the user manual, and its only job is to select one of four access states.
| Word stored at end of sector 0 | State | Debug port | ISP read commands | ISP erase commands |
|---|---|---|---|---|
| any other value | open | full access | allowed | allowed |
| 0x12345678 | CRP1 | blocked | blocked | allowed, sector 0 erase wipes the array |
| 0x87654321 | CRP2 | blocked | blocked | blocked except the Go command |
| 0x43218765 | CRP3 | blocked | blocked | blocked entirely, boot loader stays silent |
Because the constants are public, a locked device would tell you its own state if you could read one word. The difficulty is that the states which block the read also block the read of that word, so the diagnosis usually has to be inferred from behaviour rather than read out directly.
CRP1 is a field-update compromise
CRP1 is the state most products actually ship in, because it is the only one that leaves a legitimate update path open. The debug port is closed, the read and copy and compare commands are refused, but the erase and program commands still work on sectors other than the first. A boot loader sitting in the application can therefore pull a new image over UART or CAN and write it, while an outsider with a debugger and a flash utility gets nothing.
The trap is in the exception. If sector 0 is erased through the boot loader while CRP1 is engaged, the device does not erase eight kilobytes. It erases the entire array. NXP built it that way on purpose: without the guard, an attacker could erase only the vector table, drop in a two-hundred-byte routine that reads the rest of the flash and prints it out, and walk away with the firmware through the front door. Making the first sector special makes that attack cost exactly the same as losing everything.
CRP2 and CRP3 remove the door
CRP2 closes the debug port and reduces the ISP command set to a single verb: Go. The boot loader will still start the application, which is all a finished product needs, but it will not read, will not erase, will not report the part identifier. There is no authorised update path left, so a product shipping in CRP2 is telling you that its firmware is never meant to change.
CRP3 goes further and removes the boot loader from the conversation completely. No commands, no Go, no entry. On a CRP3 part the only interface left is the pins the application itself drives, and whatever those pins happen to expose is the only handle you have.
For recovery work the consequence is blunt. On CRP2 and CRP3 there is nothing to negotiate with. The job stops being a firmware job and becomes a silicon job.
So what does a locked LPC2101 still give you
Quite a lot, none of it the array. The device runs. A device that runs can be observed: current draw at reset over time, bus activity on the external memory interface if the design uses one, the timing of the first output on each port pin, the access pattern to an external serial memory if the board carries one. On a small part like this one, with eight kilobytes of flash and two kilobytes of SRAM, the firmware is compact enough that its behaviour is often a stronger description than its listing would be.
There is also the honest intermediate outcome. If the board carries an external EEPROM or a configuration serial flash, that content is usually unprotected and often holds the calibration and product identity that the customer actually needs, even though it is not the program.
The order that avoids destroying the evidence
Do the passive work first, and do all of it before anything is erased. Photograph the board, identify every memory device, dump anything on an external bus, record boot behaviour, and only then consider touching the protected part. The reason is cumulative: every step that involves erasing sector 0 is irreversible, and it also clears the protection word, so a unit that was unlocked and blank cannot afterwards be told apart from one that never held a program.
Then measure the state. Attempt a debug attach with adaptive clocking enabled and record whether the core answers at all. Attempt an ISP synchronisation with the boot entry pin held at the required level during reset, and record whether the boot loader replies, replies and refuses, or stays silent. Those two results place the part in one of the four rows above with high confidence, without writing anything.
Only after that is it reasonable to discuss invasive options, and only with the customer told plainly what they cost.
What the word decrypt means in this trade
It survives because it is short, and because customers use it to mean any situation in which firmware is inaccessible. It is worth correcting once, in writing, at the start of a job: the array is readable given access, the access is a permission state rather than a cryptographic one, and where that state has been set to its highest level, no amount of computation recovers the flash from outside.
That correction is not pedantry. It decides whether the next two weeks are spent with a scope and a decapping station or with a debugger, and it decides what the customer is told to expect at the end.
Where the small parts fit
The LPC2101FBD48 is the eight-kilobyte member of a family that runs from eight kilobytes to five hundred and twelve, all on the same ARM7TDMI-S core with the same boot loader behaviour and the same protection word. What is learned here transfers upward almost unchanged: the control word sits at the end of the first sector, erasing that sector costs the whole array, and the command set is identical on every density.
The details that change with size are the ones that matter later in a job. The larger members are covered in LPC2114FBD64 code work and in LPC2138FBD64 locked flash recovery, where the array is big enough for partial recovery to be meaningful.
A short checklist before the bench
Confirm the exact ordering code, because the same die ships in more than one package and board access differs even when the silicon does not. Confirm the crystal, because ISP autobaud is derived from it and a board with an unusual clock will not synchronise at the rates written in the manual. Confirm whether the product was ever field-updated, because a shipping update path is strong evidence of CRP1 rather than CRP2. And confirm what the customer actually needs — the whole image, the calibration block, or the protocol spoken on a port. Those three answers lead to different procedures, and only the first one requires the array at all.