Keys in a Flash
Glitching AES keys from an Arduino / ATmega with a camera flash
Computer security is hard. Even with decades of research and countless collective hours of work, it still amazes and amuses me whenever a published exploit ends up being simple, elegant, and requires almost no effort to pull off.
I had an idea: to put together the most absurd and simple exploit demonstration I could think of. Specifically, to demonstrate just how quickly, cheaply, and easily, with minimal effort and no discipline what-so-ever, we can induce faults into computers… and leak secret keys.
To that end, I’ll show how to glitch the AES secret keys out of an ATmega1284p (Arduino family) using only a hand-held camera flash.
Background
You can skip this if you already know what DFA is… Spoiler alert: I’m doing DFA.
Fault injection attacks on computer systems have been around for a long time. An attacker can induce a fault into (or glitch) a computer system to invoke erroneous behavior. Typically this is done to bypass some sort of protection mechanism, read out protected memory, or even cause mathematical errors in such a way that cryptographic secrets are inadvertently revealed.
In general, faults violate the fundamental assumptions we commonly make about how computers operate.
With that in mind, there is an interesting family of attacks against cryptographic algorithms called differential fault analysis. If an attacker can corrupt (fault) an AES encryption operation in just the right way, and enough times, it is possible to compare corrupted and correct ciphertext outputs to figure out the original secret key. No inputs needed, just the outputs.
Now, sophisticated fault attacks are carried out with expensive equipment and with a variety of techniques. These attacks may use high-voltage transient EM pulses, precise temperature controlled environments, arbitrary waveforms injected into clock and power lines, frekin’ lasers, whatever — all orchestrated with perfectly synchronized and aligned attacks to the nanosecond, with active feedback mechanisms, machine learning, search space optimization, you name it. The possibilities are theoretically limitless, if you have enough time and money.
But, what if we’re impatient, broke, and only have a camera on hand?
The Setup
No sophisticated equipment is involved, only common items.
Hardware:
- ATmega1284p (MoteinoMEGA)
- Nikon camera with a built-in tube flash
- A USB cable
- An old computer
Microcontroller software:
- Reference Rijndael implementation in C (AES, implemented with T-tables)
- Custom AVR C++ library for low-level I/O (or use Arduino stuff)
Laptop software:
- phoenixAES python library for differential fault analysis (this will figure out the round key for me)
- Custom AES python code to reverse out the AES key schedule (round key to secret key) and act as glue code
- Serial and terminal utilities
The Target
The hardware: An ATmega1284p (MoteinoMEGA). Why the Moteino? It was sitting on my desk… and the other Arduino’s were in the drawer a whole 2 feet away, in a box.
The software: A while
loop that repeatedly encrypts a constant plaintext (with a constant key) and outputs the result over the serial line.
The hardware/software combo is intended to simulate a dedicated cryptographic processor, commonly used in various embedded systems (e.g. ATAES132 with AES-ECB). Typically, these co-processors hold a secret key and perform encryption or decryption when requested. The only deviation we make to this use-case is removing the need to supply new plaintext every iteration, and limiting the printed results to errors. This reduces noise and speeds up the attack process a bit, but does not fundamentally enable the attack; it just changes the probabilities (remember, I’m impatient):
int main() {
// Boiler-plate embedded device setup, variable init
// (... there's a secret key here ...) // First line is the expected value (correct ciphertext)
printf("AES glitch target test.\n");
utils::print_hex(expected, 16);
putchar('\n'); int nrounds = rijndaelSetupEncrypt(rk, key, KEYBITS); while(1) {
rijndaelEncrypt(rk, nrounds, plaintext, ciphertext); if (memcmp(ciphertext, expected, 16) != 0) {
utils::print_hex(ciphertext, 16);
putchar('\n');
}
}
}
Reducing the I/O increases the probability that we are glitching an actual crypto operation and not a buffer copy or slow serial operation.
The Weapon
Camera flash? Yes, a camera flash. No, not a cell-phone camera flash that lights up an LED for a brief moment, but a xenon tube flash.
Tube flashes are powerful. They release high-voltage and high-current impulses of electromagnetic energy. An impulse is chaotic. It is every single frequency, stacked up on top of one another, and released as a single, instantaneous blow to the aether. It is loud, abrupt, and it disperses energy everywhere.
A tube flash is the perfect weapon inducing faults: Random, dispassionate, fair to data and instructions alike.
Nikon cameras have a special modeling flash mode that fires off the flash in extremely rapid succession to simulate continuous illumination. It is as an extremely fast and powerful EM source that can induce faults in rapid succession.
It’s like an EM minigun.
The Attack
The camera flash and Moteino are positioned by hand next to each other, and the flash is triggered manually. Unlike sophisticated attacks, we:
- Have no automated triggering
- Have no timing synchronization
- Are extremely sloppy and non-methodical with physical positioning
This can’t possibly be effective, can it?
Well…
Almost every line is a corrupted AES ciphertext… caused by a camera flash.
The faults observed get messy. The system gets stuck, reboots, dumps its own memory, anything. Luckily, the faults induced seem to have a high probability of only impacting the data bus. This is just what we want for DFA.
The fault attacks produce a slurry of corrupted ciphertexts. We don’t really care how badly they are corrupted, just that there is a random distribution of corruption.
Eventually, by chance, it will corrupt the AES operation just right and enough times that it ends up being useful. Just need to keep rolling the dice.
Turns out, it doesn’t even take that long…
The Analysis
We have a mess of corrupted cipher texts. Now what do we do? Let’s create a very short python script to feed the cipher texts to the phoenixAES DFA analysis tool.
Aaannnddd…
In about 10 seconds, we have created enough corrupted ciphertexts to recover the final AES round key and derive the original, (not-so-)secret, AES key.
The Discussion
This type of demonstration may be no surprise to those who are familiar with this family of attacks. There are numerous examples out there, most of which are far more impressive than this.
The purpose here is to show how low the bar really goes and demonstrate what is possible under the simplest of assumptions. And to make something anyone can try themselves.
A Fake Q&A
You might have questions. I might have answers. See below.
How does differential fault analysis actually work?
See the seminal paper (against RSA). Sometimes called the Bellcore attack.
Also see the paper on the round-9 attack on AES (used by phoenixAES).
Wait, you just got a bunch of random output. How is that useful to DFA?
The DFA round-9 attack relies on corrupted ciphertexts that match a specific pattern of corruption: 4 bytes in final ciphertext that differ from the correct value with specific spacing.
The DFA code just ignores inputs that don’t match this pattern.
How is the chip actually getting faulted?
I don’t really know! Maybe through external pins like power, ground, or clock? Maybe direct coupling to the internals of the die?
After some additional experimentation, I found that it’s not (primarily) the visible light spectrum. The faults still work just as well when the board is covered with cardboard.
Visible light is just one small product of a tube flash. There’s a lot of other EM energy at other frequencies.
What types of things we can do to protect against these attacks?
This question has a large body of research behind it, and there are a lot of good ideas out there with varying efficacy. An off-the-cuff list from lowest effectiveness to highest:
- Detect faults: Use hardware or software sensors to try and detect fault attacks. This may not end up being effective over the lifetime of a device as new attacks evolve. False-positive detection is also an issue. Maybe better than nothing?
- Use redundancy: Perform redundant operations or use redundant hardware (like radiation-hardened systems). It’s much more difficult to fault multiple systems or successive operations in the same way, especially if there is software and/or hardware diversity.
- Don’t be an oracle: This is specific to crypto systems, but using other modes or disallowing this type of interaction can also limit exposure. If there was a random IV with a better encryption mode, it would make this attack impossible (I think?). However, other attacks are still possible.
- Limit key usage: Use key derivation techniques to generate fresh keys for each operation. Hash chains or key trees are two approaches. This can be extremely effective, if the use case and cryptographic infrastructure can support it. You can’t perform differential analysis on a single use of a key (assuming related-key attacks don’t apply).
Note: The list isn’t exhaustive, and its correctness is arguable.
This seems a bit contrived. Could this attack really be used against a real device?
Yes, it is contrived, but also fun. I like fun things.
For real devices: If one has direct access to the interface for a dedicated cryptographic processor (not multi-purpose processor), this this attack might just work.
The “contrived” software takes care of a few things that increases the success rate:
- A way to instrument a target
- A way to repeatedly exercise the target operation
- A way to easily collect outputs
Against a real target that does not have any protection mechanisms, the only difference in the outcome is time.
That’s not impressive. That was really simple. Anyone can do it.
Yes, that’s the point. Also, that wasn’t a question.
You pwned your own software. Good job.
OK, no more questions.
If you have never seen a fault attack carried out before, I hope this was somewhat enlightening. And if you actually have seen this type of attack before, I hope it was at least amusing.