STM32H725: When the External Memory Is Ciphertext
A board with an external QSPI device next to the microcontroller looks like a board whose firmware is partly outside the chip. Read the QSPI device, add it to the internal image, and the job looks complete. On this line of the family, that assumption can be wrong in a way that produces no error message at all: the external device holds ciphertext, the part decrypts it as it fetches, and a byte-perfect copy of the external device is a byte-perfect copy of something that will never disassemble.
The mechanism
The family includes variants with a decryption engine sitting between the external memory interface and the core. Code fetched from the external device passes through it and arrives in the core as instructions; what sits in the device is the encrypted form.
| layer | what it holds | what a reader sees |
|---|---|---|
| external QSPI device | encrypted bytes | high entropy, no strings, no vector table |
| decryption engine | key material and region configuration | register writes during start-up |
| core executing from external memory | plaintext instructions | ordinary code, not visible in any dump |
Nothing about the arrangement is hidden. The configuration registers are documented, the key slots are documented, and the start-up sequence that sets them up is ordinary code. What is hidden is the plaintext, and it is hidden by arithmetic rather than by a lock bit.
How to tell, from the image alone
The configuration of the decryption engine is visible even in an image that does not include the external device. Four signals, in rough order of reliability:
| signal | where it appears | what it means |
|---|---|---|
| writes to the decryption engine’s region registers | start-up code, before any external fetch | external memory is treated as encrypted |
| key slot loading | start-up code or a secure loader | an encrypted region exists and has a key |
| external memory interface configured but no plausible code at its base | the external device dump | the base is ciphertext, not a vector table |
| a jump or call into the external address range immediately after configuration | start-up path | execution continues outside the chip |
The third row is the one that reaches a bench as a puzzle. The dump is not empty, not all-ones, not obviously damaged. It is simply noise, and the natural conclusion — that the device was read incorrectly — is wrong.
Key material and where it lives
A decryption key has to come from somewhere, and on this family the options are limited and all of them matter to a recovery.
| location | readable through the debug port | survives an erase | appears in a flash dump |
|---|---|---|---|
| key registers loaded by software | no | not applicable | no, but the loading code does |
| one-time programmable area | no | yes | no |
| derived from the device unique identifier | no | yes, per device | the derivation code does |
The third row has a consequence that is easy to miss. Where the key is derived from the unique identifier, the ciphertext is bound to that specific device. Copying the external device and the internal image to another part of the same ordering code produces a board that boots to a decryption engine configured with the wrong key — which presents as a hard fault in the first external fetch, not as a message about keys.
What this does to a recovery scope
The honest scope statement is narrower than customers expect: the internal flash can be delivered as plaintext, and the external device can be delivered as the bytes it contains. Whether those bytes can be turned into source-equivalent code depends on whether the key is recoverable, and on this family it usually is not, because it is either one-time programmable or derived from an identifier that cannot be changed.
| customer expectation | what is actually deliverable |
|---|---|
| the whole program, as source-equivalent code | internal flash yes; external region only if the key is known |
| a byte-perfect copy of both devices | yes, and this is often the useful deliverable |
| the ability to rebuild a working board | yes, if both devices are copied to the same part type |
| the ability to port the application to a different board | only for the part of it that lives in internal flash |
The last row is where a project can quietly fail. A customer who intends to port the application, and who receives an image that is functionally complete on the original hardware, discovers the boundary only when the port does not work.
Where the operating conditions enter
This line is fed by a switched-mode regulator with a linear regulator alongside it, which changes the external component count and the start-up timing relative to the linear-only members of the family. That is a board-level fact rather than an image fact, but it decides whether a delivered image can be validated at all: a return that cannot be powered up on a matching board cannot be verified before shipping.
A second reading of the same generation, from the clock and voltage-mode angle rather than the external memory angle, is at STM32H723 heximal extraction. The two-core arrangement that splits a program across two processors is covered in STM32H745 code recovery, and the display pipeline that consumes the largest structured block of SRAM in STM32H747 heximal recovery. For the read-out restrictions that decide whether any of this is reachable, STM32F303VE flash recovery covers the protection side on a smaller member of the family.
FAQ
If the external device is encrypted, is the internal flash encrypted too? Not necessarily. The engine is configured per region, and the common arrangement protects the external device while leaving internal flash plaintext.
Can the ciphertext be decrypted offline? Only with the key. Without it, the ciphertext is not a weaker version of the program; it is a different object.
Does a byte-perfect copy of both devices produce a working board? On the same part type, usually yes. On a different part, only if the key is not bound to the device identifier.
Conclusion
The decryption engine changes what “extraction” means on this part. Internal flash and external device are two different objects with two different answers, and the difference is visible in the start-up code before any of it is read. Saying so at the quotation stage is cheaper than discovering it at the porting stage.