Lab 3 - Fault Injection Attack
2026-01-12 | Hackster , Labs , Fault Injection , Side Channel , Cryptography
Introduction
Fault injection attacks are a type of side-channel attack that exploit vulnerabilities in the hardware implementation of cryptographic algorithms to introduce errors and extract sensitive information, such as cryptographic keys. These attacks are particularly effective against embedded systems and hardware implementations of cryptographic algorithms.
In this lab, you will learn about fault injection attacks and how they can be used to compromise the security of a cryptographic implementation of AES-128.
Goals:
- Understand the basics of fault injection attacks on cryptographic hardware
- Use three different bitstreams to emulate fault injection attacks in Rounds 8, 9, and 10 of AES-128
- Using the clean and faulty ciphertexts, perform a differential fault analysis attack to recover the AES key under each scenario.
Getting Started
- Do a
git pullto get the latest version of the lab materials. - Open up the
examples/spi_aes/project - Load the example bitstream onto the fpga with
make run_fpga, this contains a bitstream with a known AES key (0x2b7e151628aed2a6abf7976676151301). - You can now encrypt values by using the SPI interface from the AppMicro. You did this in Lab 0. The MicroPython script for doing so is provided,
spi_aes.py, in this folder. Try it out now, following the Lab0 instructions.
Preparing for the Fault Injection Attacks:
- When you are ready to proceed, you first need to install the
phoenixAESlibrary to break the AES key for round 8. You can install it by first creating a Python virtual environment, and then runningpip install phoenixAESwithin that environment.
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install phoenixAES
- Then, download from Moodle the Lab 3 bitstreams zip file and find the
(your zID)_lab3_r8.bin,(your zID)_lab3_r9.bin, and(your zID)_lab3_r10.binbitstreams. These are three different versions of the AES implementation, each with a controllable fault injected at a different stage of the AES algorithm. The faults are designed to cause errors in the ciphertext output, which you can use to perform a differential fault analysis attack to recover the AES key.-
You can run these bitstreams by unzipping the downloaded zip in the
diy/directory of the repository, and after opening a shell in the extracted directory using the following commands:- Round 8 fault injection:
$ ZID=(your ZID) make run_fpga_round8- Round 9 fault injection:
$ ZID=(your ZID) make run_fpga_round9- Round 10 fault injection:
$ ZID=(your ZID) make run_fpga_round10
-
- By default, these bitstreams act the same way as the original bitstream for
spi_aes. However, if you hold down the “ICE” button on the board (SW7) during the encryption process, you will trigger the fault injection and cause an error in the ciphertext output. You can use this behavior to perform a differential fault analysis attack to recover the AES key. - Experiment with this now. Deploy the round 8 scenario bitstream by using the Makescript, and then run the
spi_aes.pyAppMicro script to encrypt some plaintexts. Save the ciphertexts. Then, hold down the “ICE” button and repeat the process with the same plaintexts. You should see that the ciphertexts are different from what you get when you don’t hold down the button, indicating that the fault injection is working.
Round 8:
- To perform a Round 8 attack you need one clean ciphertext and two faulty ciphertexts. You can use the
spi_aes.pyAppMicro script to do this or make your own script (recommended). Collect the clean ciphertext by running the script without holding down the “ICE” button, and then collect two faulty ciphertexts by running the script while holding down the “ICE” button. Make sure to use the same plaintext for all three encryptions. - Now, following the material in the
phoenixAESdocumentation, and using your PC (not the AppMicro), provide the ciphertexts to the library to perform the attack and recover the AES key. - Note that
phoenixAESrecovers the last round key, which is not the same as the original AES key. You will need to conduct your own research to work out how to derive the original AES key from the last round key thatphoenixAESrecovers.
Hint: Though undocumented, you can set the result of phoenixAES.crack_file() to a variable, i.e. last_round_key = phoenixAES.crack_file("faults.txt"). This will give you the last round key as a variable that you can then process to derive the original AES key.
Round 9:
- To perform a Round 9 attack, you need a clean ciphertext and many faulty ciphertexts. You can adapt your script from earlier. Collect the clean ciphertext by running the script without holding down the “ICE” button, and then collect many faulty ciphertexts by running the script while holding down the “ICE” button. Make sure to use the same plaintext for all encryptions.
- Now, following the material in the
phoenixAESdocumentation, provide the ciphertexts to the library to perform the attack and recover the AES key. - Again, you will need to derive the original AES key from the last round key that
phoenixAESrecovers.
Round 10:
- To perform a Round 10 attack, you need multiple clean ciphertexts and multiple faulty ciphertexts. You can adapt your script from earlier to do this. Collect multiple clean and faulty ciphertexts. You’ll need to use a few different plaintexts for the encryptions in this scenario, so make sure to vary the plaintexts you use while collecting the clean and faulty ciphertexts.
Note: This bitstream has a fixed-fault in each byte of the state, but the exact byte which is faulted changes with each encryption. As a hint, try collecting 16 faulty ciphertexts and one clean ciphertext for each plaintext, and then analyze the differences between the clean and faulty ciphertexts to identify which byte of the state is being faulted in each case. This will help you to perform the attack and recover the AES key.
phoenixAESdoes not support Round 10 attacks, so you will need to implement the attack yourself. You can use the material from the lecture slides for Week 5 to guide you through the process of performing a Round 10 attack. The principle is quite straightforward:- Apply two plaintexts
PT1, PT2to the AES encryption, getting ciphertextsC1, C2. - Apply the fault injections to get faulty ciphertexts
C*1', C*2'. - For each byte
(C1[j], C*1[j])and(C2[j], C*2[j]), construct the simultaneous equations:d1(k) = InvS(C1[j] ⊕ k) ⊕ InvS(C1*[j] ⊕ k)d2(k) = InvS(C2[j] ⊕ k) ⊕ InvS(C2*[j] ⊕ k)
- Given that the same byte index of the state is faulted the same way each time, you can then solve for the key byte
kby finding the value ofkthat satisfies the equationd1(k) = d2(k). - If more than one
ksatisfies the equation, you can use additional pairs of clean and faulty ciphertexts to further narrow down the possibilities until you recover the correct key byte.
- Apply two plaintexts
Challenge Task: Dynamic Round 10 Stuck-At Fault
- As a challenge task, we include a fourth
(your zID)_lab3_r10_dynamic_stuck.binbitstream.- In this fault injection scenario, the fault is a dynamic stuck-at-1 fault, meaning that the fault causes an individual, inconsistent bit in the state to be stuck at 1.
- In other words, rather than the fault operation being an “exclusive-or” operation, it is instead a simple “or” operation.
- This means that faulty ciphertexts may not always differ from the clean ciphertext, as the fault may not always cause a change in the output.
- Further, rather than the same bit being faulted each time, the bit that is faulted changes with each encryption cycle.
- Download it using:
$ ZID=(your ZID) make run_fpga_round10_dynamic_stuck
- To perform an attack on this scenario, you will need to collect a large number of clean and faulty ciphertexts, and analyze the differences between them to identify patterns that can help you to recover the AES key. This is a much more challenging attack than the previous ones, as the fault is less predictable and may not always cause a change in the output. You will need to do your own research to come up with a clever way to analyze the data you collect to identify the key.
- This challenge is worth 1% of the grade for this lab, which may not reflect the amount of effort required to complete it.
Deliverables and Weightings:
This lab is worth 10% of your final grade for this course.
- Submit to Moodle a single zip file containing at least the following files and directories:
fault_injection_attack/:- This directory contains the attack on your provided AES IP, with at least the following files:
(your zID)_lab3_r8.bin,(your zID)_lab3_r9.bin,(your zID)_lab3_r10.bin, and optionally(your zID)_lab3_r10_dynamic_stuck.bin:- These are the unique AES IP files we provided you with. Provide a copy of them back to us.
round8/:- This directory contains the data for the Round 8 attack. It should include at least the following files:
r8.micropython.py:- This is the MicroPython script you used to collect the clean and faulty ciphertexts for the Round 8 attack. It should be immediately runnable on the AppMicro, and provide the output in an obvious format (i.e. copy and paste to the capture data file).
r8faults.txt:- This is your collected data for the Round 8 attack, containing the clean and faulty ciphertexts you collected. This should be in the format accepted by the
phoenixAESlibrary for performing the attack.
- This is your collected data for the Round 8 attack, containing the clean and faulty ciphertexts you collected. This should be in the format accepted by the
r8attack.py:- This program should use the
phoenixAESlibrary to perform the Round 8 attack using the data inr8faults.txt, and output the recovered key in hexadecimal format.
- This program should use the
r8key.txt:- This file should contain the hexadecimal value of the key you recovered from the Round 8 attack.
- This directory contains the data for the Round 8 attack. It should include at least the following files:
round9/:- This directory contains the data for the Round 9 attack. It should include at least the following files:
r9.micropython.py:- This is the MicroPython script you used to collect the clean and faulty ciphertexts for the Round 9 attack. It should be immediately runnable on the AppMicro, and provide the output in an obvious format (i.e. copy and paste to the capture data file).
r9faults.txt:- This is your collected data for the Round 9 attack, containing the clean and faulty ciphertexts you collected. This should be in the format accepted by the
phoenixAESlibrary for performing the attack.
- This is your collected data for the Round 9 attack, containing the clean and faulty ciphertexts you collected. This should be in the format accepted by the
r9attack.py:- This program should use the
phoenixAESlibrary to perform the Round 9 attack using the data inr9faults.txt, and output the recovered key in hexadecimal format.
- This program should use the
r9key.txt:- This file should contain the hexadecimal value of the key you recovered from the Round 9 attack.
- This directory contains the data for the Round 9 attack. It should include at least the following files:
round10/:- This directory contains the data for the Round 10 attack. It should include at least the following files:
r10.micropython.py:- This is the MicroPython script you used to collect the clean and faulty ciphertexts for the Round 10 attack. It should be immediately runnable on the AppMicro, and provide the output in an obvious format (i.e. copy and paste to the capture data file).
README.md:- This file should contain a brief explanation of how you performed the Round 10 attack, including any challenges you faced and how you overcame them. It should also include a description of the format of your collected data for the Round 10 attack, and how you structured it to perform the attack, and any special instructions for running your Round 10 attack program.
r10faults.txtORr10faults.csvORr10faults.jsonOR similar:- This is your collected data for the Round 10 attack, containing the clean and faulty ciphertexts you collected. This should be in a format that allows us to understand how you are structuring the captured data for the attack. Explain your format in the
README.mdfile.
- This is your collected data for the Round 10 attack, containing the clean and faulty ciphertexts you collected. This should be in a format that allows us to understand how you are structuring the captured data for the attack. Explain your format in the
r10attack.py:- This program should implement the Round 10 attack using your collected data and output the recovered key in hexadecimal format.
r10key.txt:- This file should contain the hexadecimal value of the key you recovered from the Round 10 attack.
- This directory contains the data for the Round 10 attack. It should include at least the following files:
challenge_dynamic_round10/:- You may choose to omit this directory if you did not attempt the challenge.
- This directory contains the data for the dynamic round 10 stuck-at fault attack challenge. It should include at least the following files:
r10_dynamic_stuck.micropython.py:- This is the MicroPython script you used to collect the clean and faulty ciphertexts for the dynamic round 10 stuck-at fault attack challenge. It should be immediately runnable on the AppMicro, and provide the output in an obvious format (i.e. copy and paste to the capture data file).
README.md:- This file should contain a brief explanation of how you performed the attack on the dynamic round 10 stuck-at fault scenario, including any challenges you faced and how you overcame them. It should also include a description of the format of your collected data for this attack, and how you structured it to perform the attack, and any special instructions for running your attack program for this scenario.
r10_dynamic_stuck_faults.txtORr10_dynamic_stuck_faults.csvORr10_dynamic_stuck_faults.jsonOR similar:- This is your collected data for the dynamic round 10 stuck-at fault attack challenge, containing the clean and faulty ciphertexts you collected. This should be in a format that allows us to understand how you are structuring the captured data for the attack. Explain your format in the
README.mdfile.
- This is your collected data for the dynamic round 10 stuck-at fault attack challenge, containing the clean and faulty ciphertexts you collected. This should be in a format that allows us to understand how you are structuring the captured data for the attack. Explain your format in the
r10_dynamic_stuck_attack.py:- This program should implement the attack on the dynamic round 10 stuck-at fault scenario using your collected data and output the recovered key in hexadecimal format.
r10_dynamic_stuck_key.txt:- This file should contain the hexadecimal value of the key you recovered from the attack on the dynamic round 10 stuck-at fault scenario.
- This directory contains the attack on your provided AES IP, with at least the following files:
Resources
- The
phoenixAESlibrary documentation: https://phoenixaes.readthedocs.io/en/latest/ - The lecture slides for Week 5, which cover the theory and implementation of fault injection attacks on AES, including the Round 10 attack. You can find these slides on the course website under the “Lectures” section for Week 5.
Grading Rubric
Fault Injection Attack (10%)
- Criterion:
- (2%) Round 8 attack implementation and key recovery
- Fail (0%) No attempt, or completely incoherent implementation of the attack.
- Genuine Attempt (1%) Attempted fault injection attack but did not recover any bytes of the key (e.g. collected correct data, but failed to analyze it correctly).
- Pass (2%) Correct implementation of the attack and successful recovery of the AES key.
- (2%) Round 9 attack implementation and key recovery
- Fail (0%) No attempt, or completely incoherent implementation of the attack.
- Genuine Attempt (1%) Attempted fault injection attack but did not recover any bytes of the key (e.g. collected correct data, but failed to analyze it correctly).
- Pass (2%) Correct implementation of the attack and successful recovery of the AES key.
- (5%) Round 10 attack implementation and key recovery
- Fail (0%) No attempt, or completely incoherent implementation of the attack.
- Genuine Attempt (1-2%) Attempted fault injection attack but did not recover any bytes of the key (e.g. collected correct data, but failed to analyze it correctly).
- Partial Success (3-4%) Attempted fault injection attack and recovered at least some of the key.
- Pass (5%) Correct implementation of fault injection attack and successful recovery of the AES key.
- (1%) Challenge: Dynamic Round 10 Stuck-At Fault
- Fail (0%) No attempt, or completely incoherent implementation of the attack.
- Pass (1%) Recovered the AES key from the dynamic round 10 stuck-at fault scenario.
- (2%) Round 8 attack implementation and key recovery