Espressif ESP32: Breaking HW AES with Power Analysis

Friday, Feb 24, 2023


Side Channel Analysis (SCA) attacks are commonly used for extracting the secret key of cryptographic engines found in modern devices. They exploit side channels, such as Timing, Power and Electromagnetic (EM) leaks, to obtain information about the secret key used by the cryptography algorithm. Even though these type of attacks were traditionally performed on smart cards, they are effective on embedded devices as well.

Even the strongest cryptography algorithms, such as AES, are susceptible to SCA attacks, especially if no countermeasures are in place. That’s why, Ledger Dojon’s discovery that the key used by the flash encryption feature of the ESP32 chip could be extracted through a power analysis attack, was not surprising. Nonetheless, their in-depth research is very cool and we definitely recommend to watch their Black Hat presentation and read their paper. Espressif released an advisory related to their research results.

Ledger’s research inspired us, especially because we use the ESP32 chip for our hardware security trainings, to break the hardware AES engine using a power analysis attack as well. The results of this activity are described in this blog post. Other interesting examples include SCA attacks on the iPhone (EM), Xbox 360 (Timing) and ARMv8 Cryptographic Extensions (CE) (EM).

Please note, in this blog post we will not explain the theory behind power analysis attacks, notably Correlation Power Attacks (CPA) on the AES algorithm. There’s an abundance of information publicly available where these attacks are described in utmost detail and clarity. For example, by Yan1x0s, Colin O’Flynn and Jasper van Woudenberg, NewAE, Ceesb and Paul Kocher. We definitely used their write-ups for inspiration and reference.

Test application

The first thing we had to find out is how to communicate with the hardware AES engine of the ESP32 chip. Conveniently, the ESP32 chip includes a built-in ROM API to decrease the complexity of interfacing with its hardware features, including the hardware AES engine. We simply used this ROM API in order to set the key and perform an encryption with the AES engine. We use a standard GPIO pin to determine where exactly this ROM API call is executed and to align our measurement with the oscilloscope. A simplified snippet of our test application is shown below.

    ...
    case 'K':
        ets_aes_setkey_enc(key, AES128);
        break;
    case 'L':
        /* receive input */
        for(int i = 0; i < 16; i++) {
            while(esp_rom_uart_rx_one_char(&input_buffer[i]) != 0){};
        }

        GPIO_OUTPUT_SET(26,1);
        ets_aes_crypt(input_buffer, output_buffer);
        GPIO_OUTPUT_SET(26,0);

        /* send output */
        for(int i = 0; i < 16; i++) {
            ets_printf("%02x", output_buffer[i]);
        }
    ...

When we execute the above test application it results in a trigger window (i.e., time between trigger up and down) of roughly 3.1 μs as is shown below.

Trigger window (time between trigger up and down)

It’s good to point out that the receiving of input data and sending of output data is outside of this trigger window.

Power domain

The ESP32’s hardware AES engine is powered according to the Technical Reference Manual by the VDD3P3_CPU power domain. On most development boards, including the ones we have access to, it’s not trivial to control this power domain separately from the others.

It’s possible to modify the development board, as shown by Limited Results, however, that’s not ideal for security trainings as it’s time consuming and fragile. Moreover, we noticed that the placement of the VDD3P3_CPU pin is drastically different between the ESP32-D0WD and ESP32-D0WDQ6, which makes it even more annoying to make the required modification. Therefore, we decided, in similar fashion as Ledger’s scaffold, to make our own custom board where all the relevant signals are routed to dedicated pins.

Raelize's custom ESP32 board (v0)

If you are interested, the schematics of this board can be found here. There are a few issues with the board and therefore we are currently in the process of making an updated version of this board with several improvements.

Power analysis setup

We use Riscure’s Current Probe to measure the current of the VDD3P3_CPU power domain, which is powered by two AA batteries in series to create a clean voltage signal of about 3 volts. Inside this device, the power signal (i.e., current carrying conductor) goes through a current transformer in order to measure the fluctuations in the power consumption.

The advantage of using the Current Probe, compared to the typical ‘measure the voltage drop over a resistor approach’, is its low impedance and a high sensitivity. The output of the Current Probe, as well as the GPIO pin used for the trigger, are connected to a Picoscope 3206D oscilloscope. We use a standard FTDI-based USB-to-UART adapter to communicate with the ESP32 chip. A diagram of the power analysis setup that we used is shown below.

Power Analysis setup

The actual setup in our lab is shown below.

Power Analysis setup

We use Riscure’s FiPy to control the setup during the acquisition. This is a Python framework that is controlled and access from the browser. It’s shown below during the acquisition of multiple encryption operations.

Riscure's FiPy

Even though this Python framework is typically used for Fault Injection attacks, it can be used conveniently for SCA acquisition as well.

Acquisition speed

The acquisition speed of your measurements is typically quite important when performing a side channel attack. There is typically a minimum amount of measurements required to extract the entire key.

Throughout our research we used two acquisition techniques that are supported by our oscilloscope: normal block mode and rapid block mode. We used Picoscope’s Python bindings to communicate with the oscilloscope. We used their ps3000aRapidBlockExample.py as a reference to integrate rapid block mode into Riscure’s FiPy.

In normal block mode we initiate a single cryptographic operation in order to measure the power consumption. This means that the overhead for communicating with both the target and oscilloscope is there for each measurement. Using rapid block mode, we can minimize this overhead by initiating multiple cryptographic operations, which are measured by the oscilloscope, and then sent all at once back to the workstation. This allows us, as you will find out after reading this entire blog post, to acquire traces much faster.

Input/Output correlation

Using normal block mode, we acquire 1M traces in ~9 hours while the hardware AES engine is encrypting random input data. We use Riscure’s Inspector software to compute the input and output correlation which is shown below.

Input correlation

Output correlation

We can use the input and output correlation to determine that the AES operation is performed between 150 μs and 180 μs. In principle, we can use this information to decrease our attack window from the moment the trigger goes up and down to the mount we see input and output correlation. This will decrease the amount of samples we need to measure and transfer, which will increase the acquisition speed.

Known Key Correlation

We use the same trace set, containing 1M traces, to compute the correlation with intermediate values. We used the Known Key Correlation module from Riscure’s Inspector software to compute the correlation with the default intermediates that can be attacked (e.g., HW(S-Box output), HD(S-Box input ^ S-Box output), etc.).

Riscure's Known Key Correlation module

The output of this module shows that the hardware AES engine leaks the Hamming Weight (HW) of the S-Box output, a typical leakage model for AES implementations. The output trace below shows the correlation for each key byte intermediate (i.e., 16 in total). The leakage is significant for all key byte intermediates at sample 400 which translates to roughly 1.6 μs after the trigger up signal.

Intermediate correlation (Hamming Weight of S-Box output)

The other peaks are likely ghost peaks that can be safely ignored as they do not appear at the same time for each key byte intermediate (i.e., something you would expect from a hardware AES implementation).

We observe no significant peaks for the Hamming Distance (HD) of the S-Box input and S-Box output, another typical leakage model for AES implementations, as shown in the picture below.

Intermediate correlation (Hamming Distance of S-Box input / S-Box output)

The peaks that are there are likely ghost peaks that can again be safely ignored for similar reasons as before. From this point on we will only consider the HW of S-Box output as leakage model for our attacks.

Known Key Analysis

We used the Known Key Analysis module from Riscure’s Inspector software, using the same trace set, to perform a known key analysis. This is useful for determining how many traces are required to extract the entire key. Moreover, even if you do not extract the key, it gives an idea of how many more traces you need to do so.

Riscure's Known Key Analysis module

We applied known key analysis to samples from 390 to 410, whose output is shown below. On the left side, an heat map provides an indication of the leakage for each fragment (i.e., sample). This output shows that significant leakage is present at fragment 9 (i.e., sample 399).

The output of this module can be used to determine how high the correct key byte ranks among all the possible key bytes. When we run this module only 50k traces, we are unable to recover the key as is shown in the output below.

Riscure's Known Key Analysis module output

By looking at the key ranking, another output of this module, we indeed determine that not all correct key bytes rank the highest. This is a clear indication that the correlation found is not significant enough for the amount of traces analyzed.

Results after 50000 traces
Analysing Round 0 (round key: 1a7a8edb19ce775d413941a4412721ba)
Best correlation Round 0: Key: Column 0, Row 0 in the range 399 till 400:
+ rank: 1, candidate:  26 (0x1A), confidence: 0.0266 at position: 399
Best correlation Round 0: Key: Column 0, Row 1 in the range 399 till 400:
+ rank: 1, candidate: 122 (0x7A), confidence: 0.0167 at position: 399
Best correlation Round 0: Key: Column 0, Row 2 in the range 399 till 400:
+ rank: 1, candidate: 142 (0x8E), confidence: 0.0169 at position: 399
Best correlation Round 0: Key: Column 0, Row 3 in the range 399 till 400:
- rank: 11, candidate: 219 (0xDB), confidence: 0.0095 at position: 399
Best correlation Round 0: Key: Column 1, Row 0 in the range 399 till 400:
+ rank: 1, candidate:  25 (0x19), confidence: 0.0233 at position: 399
Best correlation Round 0: Key: Column 1, Row 1 in the range 399 till 400:
- rank: 3, candidate: 206 (0xCE), confidence: 0.0137 at position: 399
Best correlation Round 0: Key: Column 1, Row 2 in the range 399 till 400:
+ rank: 1, candidate: 119 (0x77), confidence: 0.0188 at position: 399
Best correlation Round 0: Key: Column 1, Row 3 in the range 399 till 400:
+ rank: 1, candidate:  93 (0x5D), confidence: 0.0134 at position: 399
Best correlation Round 0: Key: Column 2, Row 0 in the range 399 till 400:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0198 at position: 399
Best correlation Round 0: Key: Column 2, Row 1 in the range 399 till 400:
+ rank: 1, candidate:  57 (0x39), confidence: 0.0181 at position: 399
Best correlation Round 0: Key: Column 2, Row 2 in the range 399 till 400:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0241 at position: 399
Best correlation Round 0: Key: Column 2, Row 3 in the range 399 till 400:
+ rank: 1, candidate: 164 (0xA4), confidence: 0.0184 at position: 399
Best correlation Round 0: Key: Column 3, Row 0 in the range 399 till 400:
- rank: 15, candidate:  65 (0x41), confidence: 0.0328 at position: 399
Best correlation Round 0: Key: Column 3, Row 1 in the range 399 till 400:
- rank: 10, candidate:  39 (0x27), confidence: 0.0123 at position: 399
Best correlation Round 0: Key: Column 3, Row 2 in the range 399 till 400:
- rank: 10, candidate:  33 (0x21), confidence: 0.0115 at position: 399
Best correlation Round 0: Key: Column 3, Row 3 in the range 399 till 400:
- rank: 3, candidate: 186 (0xBA), confidence: 0.0131 at position: 399
Best global key rank estimate in the range 399 till 400 (entropy): 41.24538723481172

When this module is re-run using 200,000 traces, we are able to recover the key entirely. Interestingly, the leakage in fragment 12 (i.e., sample 402) seems more significant than in other fragments. The plot for fragment 12 shows that all key bytes actually already converge to 0 after 140,000 traces.

Riscure's Known Key Analysis module output

By analyzing the key ranking, we see that this time all key bytes rank the highest. This is a clear indication that the correlation found is now significant enough to extract the entire key.

Results after 200000 traces
Analysing Round 0 (round key: 1a7a8edb19ce775d413941a4412721ba)
Best correlation Round 0: Key: Column 0, Row 0 in the range 402 till 403:
+ rank: 1, candidate:  26 (0x1A), confidence: 0.0150 at position: 402
Best correlation Round 0: Key: Column 0, Row 1 in the range 402 till 403:
+ rank: 1, candidate: 122 (0x7A), confidence: 0.0137 at position: 402
Best correlation Round 0: Key: Column 0, Row 2 in the range 402 till 403:
+ rank: 1, candidate: 142 (0x8E), confidence: 0.0234 at position: 402
Best correlation Round 0: Key: Column 0, Row 3 in the range 402 till 403:
+ rank: 1, candidate: 219 (0xDB), confidence: 0.0168 at position: 402
Best correlation Round 0: Key: Column 1, Row 0 in the range 402 till 403:
+ rank: 1, candidate:  25 (0x19), confidence: 0.0172 at position: 402
Best correlation Round 0: Key: Column 1, Row 1 in the range 402 till 403:
+ rank: 1, candidate: 206 (0xCE), confidence: 0.0096 at position: 402
Best correlation Round 0: Key: Column 1, Row 2 in the range 402 till 403:
+ rank: 1, candidate: 119 (0x77), confidence: 0.0195 at position: 402
Best correlation Round 0: Key: Column 1, Row 3 in the range 402 till 403:
+ rank: 1, candidate:  93 (0x5D), confidence: 0.0186 at position: 402
Best correlation Round 0: Key: Column 2, Row 0 in the range 402 till 403:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0184 at position: 402
Best correlation Round 0: Key: Column 2, Row 1 in the range 402 till 403:
+ rank: 1, candidate:  57 (0x39), confidence: 0.0163 at position: 402
Best correlation Round 0: Key: Column 2, Row 2 in the range 402 till 403:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0167 at position: 402
Best correlation Round 0: Key: Column 2, Row 3 in the range 402 till 403:
+ rank: 1, candidate: 164 (0xA4), confidence: 0.0180 at position: 402
Best correlation Round 0: Key: Column 3, Row 0 in the range 402 till 403:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0284 at position: 402
Best correlation Round 0: Key: Column 3, Row 1 in the range 402 till 403:
+ rank: 1, candidate:  39 (0x27), confidence: 0.0135 at position: 402
Best correlation Round 0: Key: Column 3, Row 2 in the range 402 till 403:
+ rank: 1, candidate:  33 (0x21), confidence: 0.0130 at position: 402
Best correlation Round 0: Key: Column 3, Row 3 in the range 402 till 403:
+ rank: 1, candidate: 186 (0xBA), confidence: 0.0174 at position: 402
Best global key rank estimate in the range 402 till 403 (entropy): 0.0

We can now use the information obtained from the known key analysis to perform our attack where we aim to extract an unknown key.

First Order Analysis

During a real attack scenario, the attacker is supposed not to have knowledge of the key. A side-channel attack is supposed to be executed in absence of such knowledge. This can be done using Riscure’s First Order Analysis module which is shown below.

Riscure's First Order Analysis module

The output of this module after 50,000 traces is shown below. We already know from the known key analysis that the intermediate correlation, with this amount of traces, is not significant enough for extracting the entire key. Interestingly, we were still able to extract the key by brute forcing the incorrect key byte guesses.

Results after 50000 traces
Best score for Round 0: Key: Column 0, Row 0 with rdm: 3.3968:
+ rank: 1, candidate:  26 (0x1A), confidence: 0.0253 at position: 402
- rank: 2, candidate:  16 (0x10), confidence: 0.0148 at position: 402
- rank: 3, candidate: 235 (0xEB), confidence: 0.0117 at position: 402
- rank: 4, candidate:  46 (0x2E), confidence: 0.0115 at position: 402
Best score for Round 0: Key: Column 0, Row 1 with rdm: 1.7616:
+ rank: 1, candidate: 122 (0x7A), confidence: 0.0191 at position: 402
- rank: 2, candidate: 246 (0xF6), confidence: 0.0138 at position: 402
- rank: 3, candidate: 108 (0x6C), confidence: 0.0123 at position: 402
- rank: 4, candidate: 147 (0x93), confidence: 0.0123 at position: 402
Best score for Round 0: Key: Column 0, Row 2 with rdm: 2.5288:
+ rank: 1, candidate: 142 (0x8E), confidence: 0.0203 at position: 402
- rank: 2, candidate:  87 (0x57), confidence: 0.0131 at position: 402
- rank: 3, candidate: 129 (0x81), confidence: 0.0123 at position: 402
- rank: 4, candidate: 192 (0xC0), confidence: 0.0117 at position: 402
Best score for Round 0: Key: Column 0, Row 3 with rdm: 0.0746:
- rank: 1, candidate: 248 (0xF8), confidence: 0.0124 at position: 402
- rank: 2, candidate: 220 (0xDC), confidence: 0.0122 at position: 402
- rank: 3, candidate:  17 (0x11), confidence: 0.0117 at position: 402
+ rank: 4, candidate: 219 (0xDB), confidence: 0.0113 at position: 402
Best score for Round 0: Key: Column 1, Row 0 with rdm: 0.0749:
- rank: 1, candidate: 194 (0xC2), confidence: 0.0159 at position: 402
+ rank: 2, candidate:  25 (0x19), confidence: 0.0156 at position: 402
- rank: 3, candidate:  63 (0x3F), confidence: 0.0136 at position: 402
- rank: 4, candidate: 118 (0x76), confidence: 0.0121 at position: 402
Best score for Round 0: Key: Column 1, Row 1 with rdm: 0.5460:
- rank: 1, candidate: 220 (0xDC), confidence: 0.0159 at position: 402
- rank: 2, candidate:  13 (0x0D), confidence: 0.0141 at position: 402
- rank: 3, candidate: 114 (0x72), confidence: 0.0137 at position: 402
- rank: 4, candidate: 241 (0xF1), confidence: 0.0132 at position: 402
Best score for Round 0: Key: Column 1, Row 2 with rdm: 1.7964:
+ rank: 1, candidate: 119 (0x77), confidence: 0.0190 at position: 402
- rank: 2, candidate: 150 (0x96), confidence: 0.0132 at position: 402
- rank: 3, candidate:  56 (0x38), confidence: 0.0126 at position: 402
- rank: 4, candidate: 104 (0x68), confidence: 0.0125 at position: 402
Best score for Round 0: Key: Column 1, Row 3 with rdm: 0.4219:
+ rank: 1, candidate:  93 (0x5D), confidence: 0.0135 at position: 402
- rank: 2, candidate:  27 (0x1B), confidence: 0.0123 at position: 402
- rank: 3, candidate: 244 (0xF4), confidence: 0.0120 at position: 402
- rank: 4, candidate: 157 (0x9D), confidence: 0.0111 at position: 402
Best score for Round 0: Key: Column 2, Row 0 with rdm: 0.9682:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0200 at position: 402
- rank: 2, candidate: 248 (0xF8), confidence: 0.0163 at position: 402
- rank: 3, candidate: 252 (0xFC), confidence: 0.0144 at position: 402
- rank: 4, candidate:  18 (0x12), confidence: 0.0143 at position: 402
Best score for Round 0: Key: Column 2, Row 1 with rdm: 1.6868:
+ rank: 1, candidate:  57 (0x39), confidence: 0.0205 at position: 402
- rank: 2, candidate:  67 (0x43), confidence: 0.0146 at position: 402
- rank: 3, candidate:  93 (0x5D), confidence: 0.0141 at position: 402
- rank: 4, candidate: 177 (0xB1), confidence: 0.0135 at position: 402
Best score for Round 0: Key: Column 2, Row 2 with rdm: 1.1896:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0257 at position: 402
- rank: 2, candidate:  72 (0x48), confidence: 0.0202 at position: 402
- rank: 3, candidate: 239 (0xEF), confidence: 0.0199 at position: 402
- rank: 4, candidate: 180 (0xB4), confidence: 0.0184 at position: 402
Best score for Round 0: Key: Column 2, Row 3 with rdm: 1.8430:
+ rank: 1, candidate: 164 (0xA4), confidence: 0.0202 at position: 402
- rank: 2, candidate: 208 (0xD0), confidence: 0.0140 at position: 402
- rank: 3, candidate: 109 (0x6D), confidence: 0.0138 at position: 402
- rank: 4, candidate: 152 (0x98), confidence: 0.0132 at position: 402
Best score for Round 0: Key: Column 3, Row 0 with rdm: 0.5792:
- rank: 1, candidate:  55 (0x37), confidence: 0.0318 at position: 402
- rank: 2, candidate: 230 (0xE6), confidence: 0.0284 at position: 402
- rank: 3, candidate:  72 (0x48), confidence: 0.0280 at position: 402
- rank: 4, candidate: 202 (0xCA), confidence: 0.0270 at position: 402
Best score for Round 0: Key: Column 3, Row 1 with rdm: 1.0305:
+ rank: 1, candidate:  39 (0x27), confidence: 0.0142 at position: 402
- rank: 2, candidate:   2 (0x02), confidence: 0.0115 at position: 402
- rank: 3, candidate: 103 (0x67), confidence: 0.0108 at position: 402
- rank: 4, candidate:  79 (0x4F), confidence: 0.0101 at position: 402
Best score for Round 0: Key: Column 3, Row 2 with rdm: 1.7148:
- rank: 1, candidate: 121 (0x79), confidence: 0.0239 at position: 402
- rank: 2, candidate: 222 (0xDE), confidence: 0.0168 at position: 402
- rank: 3, candidate: 173 (0xAD), confidence: 0.0168 at position: 402
- rank: 4, candidate:   3 (0x03), confidence: 0.0167 at position: 402
Best score for Round 0: Key: Column 3, Row 3 with rdm: 0.2780:
- rank: 1, candidate: 120 (0x78), confidence: 0.0167 at position: 402
+ rank: 2, candidate: 186 (0xBA), confidence: 0.0157 at position: 402
- rank: 3, candidate: 240 (0xF0), confidence: 0.0150 at position: 402
- rank: 4, candidate:  47 (0x2F), confidence: 0.0137 at position: 402
Unverified key: (0x1a7a8ef8c2dc775d413941a437277978)
Preparing for key enumeration (SKEA)
Press abort to stop searching
Starting SKEA algorithm to a maximum of 30 bits
Tue Feb 07 16:30:10 CET 2023: explored search space of 21 bits... (3.32M keys/sec,  max remaining time: 000h 05m 23s,   ETA: Tue Feb 07 16:35:33 CET 2023)
Tue Feb 07 16:30:10 CET 2023: explored search space of 22 bits... (4.11M keys/sec,  max remaining time: 000h 04m 20s,   ETA: Tue Feb 07 16:34:30 CET 2023)
Tue Feb 07 16:30:11 CET 2023: explored search space of 23 bits... (4.76M keys/sec,  max remaining time: 000h 03m 43s,   ETA: Tue Feb 07 16:33:54 CET 2023)
Tue Feb 07 16:30:13 CET 2023: explored search space of 24 bits... (5.00M keys/sec,  max remaining time: 000h 03m 31s,   ETA: Tue Feb 07 16:33:44 CET 2023)
Tue Feb 07 16:30:16 CET 2023: explored search space of 25 bits... (5.22M keys/sec,  max remaining time: 000h 03m 19s,   ETA: Tue Feb 07 16:33:35 CET 2023)
Tue Feb 07 16:30:22 CET 2023: explored search space of 26 bits... (5.27M keys/sec,  max remaining time: 000h 03m 11s,   ETA: Tue Feb 07 16:33:33 CET 2023)
Tue Feb 07 16:30:34 CET 2023: explored search space of 27 bits... (5.42M keys/sec,  max remaining time: 000h 02m 53s,   ETA: Tue Feb 07 16:33:27 CET 2023)
Tue Feb 07 16:30:58 CET 2023: explored search space of 28 bits... (5.51M keys/sec,  max remaining time: 000h 02m 26s,   ETA: Tue Feb 07 16:33:24 CET 2023)
Tue Feb 07 16:31:46 CET 2023: explored search space of 29 bits... (5.56M keys/sec,  max remaining time: 000h 01m 36s,   ETA: Tue Feb 07 16:33:22 CET 2023)
Process finished after evaluating 717.36M key candidates
Correct key found: 1a7a8edb19ce775d413941a4412721ba

The output of the module for 200,000 traces is shown below.

Results after 200000 traces
Best score for Round 0: Key: Column 0, Row 0 with rdm: 3.1367:
+ rank: 1, candidate:  26 (0x1A), confidence: 0.0150 at position: 402
- rank: 2, candidate: 242 (0xF2), confidence: 0.0089 at position: 402
- rank: 3, candidate: 158 (0x9E), confidence: 0.0074 at position: 402
- rank: 4, candidate: 115 (0x73), confidence: 0.0071 at position: 402
Best score for Round 0: Key: Column 0, Row 1 with rdm: 3.0664:
+ rank: 1, candidate: 122 (0x7A), confidence: 0.0137 at position: 402
- rank: 2, candidate:  61 (0x3D), confidence: 0.0080 at position: 402
- rank: 3, candidate: 103 (0x67), confidence: 0.0080 at position: 402
- rank: 4, candidate: 133 (0x85), confidence: 0.0073 at position: 402
Best score for Round 0: Key: Column 0, Row 2 with rdm: 7.2396:
+ rank: 1, candidate: 142 (0x8E), confidence: 0.0234 at position: 402
- rank: 2, candidate: 133 (0x85), confidence: 0.0076 at position: 402
- rank: 3, candidate: 219 (0xDB), confidence: 0.0073 at position: 402
- rank: 4, candidate:  97 (0x61), confidence: 0.0073 at position: 402
Best score for Round 0: Key: Column 0, Row 3 with rdm: 3.8561:
+ rank: 1, candidate: 219 (0xDB), confidence: 0.0168 at position: 402
- rank: 2, candidate:  17 (0x11), confidence: 0.0094 at position: 402
- rank: 3, candidate: 135 (0x87), confidence: 0.0089 at position: 402
- rank: 4, candidate: 117 (0x75), confidence: 0.0077 at position: 402
Best score for Round 0: Key: Column 1, Row 0 with rdm: 3.1664:
+ rank: 1, candidate:  25 (0x19), confidence: 0.0172 at position: 402
- rank: 2, candidate:  83 (0x53), confidence: 0.0099 at position: 402
- rank: 3, candidate: 176 (0xB0), confidence: 0.0096 at position: 402
- rank: 4, candidate: 194 (0xC2), confidence: 0.0094 at position: 402
Best score for Round 0: Key: Column 1, Row 1 with rdm: 1.3449:
+ rank: 1, candidate: 206 (0xCE), confidence: 0.0096 at position: 402
- rank: 2, candidate:  10 (0x0A), confidence: 0.0073 at position: 402
- rank: 3, candidate: 100 (0x64), confidence: 0.0070 at position: 402
- rank: 4, candidate:  92 (0x5C), confidence: 0.0067 at position: 402
Best score for Round 0: Key: Column 1, Row 2 with rdm: 3.8297:
+ rank: 1, candidate: 119 (0x77), confidence: 0.0195 at position: 402
- rank: 2, candidate:  48 (0x30), confidence: 0.0105 at position: 402
- rank: 3, candidate:  92 (0x5C), confidence: 0.0086 at position: 402
- rank: 4, candidate:  73 (0x49), confidence: 0.0083 at position: 402
Best score for Round 0: Key: Column 1, Row 3 with rdm: 3.2113:
+ rank: 1, candidate:  93 (0x5D), confidence: 0.0186 at position: 402
- rank: 2, candidate: 244 (0xF4), confidence: 0.0113 at position: 402
- rank: 3, candidate:  73 (0x49), confidence: 0.0098 at position: 402
- rank: 4, candidate: 196 (0xC4), confidence: 0.0098 at position: 402
Best score for Round 0: Key: Column 2, Row 0 with rdm: 3.1708:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0184 at position: 402
- rank: 2, candidate:   9 (0x09), confidence: 0.0102 at position: 402
- rank: 3, candidate: 216 (0xD8), confidence: 0.0098 at position: 402
- rank: 4, candidate: 250 (0xFA), confidence: 0.0092 at position: 402
- Best score for Round 0: Key: Column 2, Row 1 with rdm: 2.2755:
+ rank: 1, candidate:  57 (0x39), confidence: 0.0163 at position: 402
- rank: 2, candidate:  70 (0x46), confidence: 0.0104 at position: 402
- rank: 3, candidate:  91 (0x5B), confidence: 0.0101 at position: 402
- rank: 4, candidate: 120 (0x78), confidence: 0.0100 at position: 402
Best score for Round 0: Key: Column 2, Row 2 with rdm: 1.2491:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0167 at position: 402
- rank: 2, candidate:  67 (0x43), confidence: 0.0132 at position: 402
- rank: 3, candidate: 244 (0xF4), confidence: 0.0116 at position: 402
- rank: 4, candidate:  96 (0x60), confidence: 0.0113 at position: 402
Best score for Round 0: Key: Column 2, Row 3 with rdm: 1.9663:
+ rank: 1, candidate: 164 (0xA4), confidence: 0.0180 at position: 402
- rank: 2, candidate: 244 (0xF4), confidence: 0.0130 at position: 402
- rank: 3, candidate: 208 (0xD0), confidence: 0.0101 at position: 402
- rank: 4, candidate:  27 (0x1B), confidence: 0.0101 at position: 402
Best score for Round 0: Key: Column 3, Row 0 with rdm: 0.8957:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0284 at position: 402
- rank: 2, candidate: 142 (0x8E), confidence: 0.0243 at position: 402
- rank: 3, candidate:  19 (0x13), confidence: 0.0234 at position: 402
- rank: 4, candidate: 140 (0x8C), confidence: 0.0234 at position: 402
Best score for Round 0: Key: Column 3, Row 1 with rdm: 3.3628:
+ rank: 1, candidate:  39 (0x27), confidence: 0.0135 at position: 402
- rank: 2, candidate: 239 (0xEF), confidence: 0.0079 at position: 402
- rank: 3, candidate: 209 (0xD1), confidence: 0.0070 at position: 402
- rank: 4, candidate: 184 (0xB8), confidence: 0.0067 at position: 402
Best score for Round 0: Key: Column 3, Row 2 with rdm: 0.1975:
+ rank: 1, candidate:  33 (0x21), confidence: 0.0130 at position: 402
- rank: 2, candidate: 111 (0x6F), confidence: 0.0125 at position: 402
- rank: 3, candidate: 114 (0x72), confidence: 0.0122 at position: 402
- rank: 4, candidate: 141 (0x8D), confidence: 0.0108 at position: 402
Best score for Round 0: Key: Column 3, Row 3 with rdm: 1.6783:
+ rank: 1, candidate: 186 (0xBA), confidence: 0.0174 at position: 402
- rank: 2, candidate: 105 (0x69), confidence: 0.0125 at position: 402
- rank: 3, candidate: 212 (0xD4), confidence: 0.0114 at position: 402
- rank: 4, candidate: 244 (0xF4), confidence: 0.0110 at position: 402
Unverified key: (0x1a7a8edb19ce775d413941a4412721ba)
Process finished after evaluating 1.00 key candidates
Correct key found: 1a7a8edb19ce775d413941a4412721ba

Acquiring 200,000 traces may sound like an hefty requirement to extract the entire key, especially considering it takes multiple hours to acquire such a trace set. To lower this requirement, as an attacker you have basically two options, make the analysis more efficient (i.e., less traces are required) or increase the acquisition speed. We chose the latter…

Speeding up the attack

Now that we have all ingredients (i.e., leakage model and timing), we can cook up an approach for recovering the key as fast as possible. We use the following strategy:

  • Use Picoscope’s Rapid Block Mode, inspired by the work of ceesb), which allows us to measure multiple cryptographic operations per acquisition in order to minimize the communication overhead.
  • Only acquire the sample(s) that leaks well (e.g., sample 410).
  • Use the hardware SHA1 engine to generate inputs for each encryption operation.

As we are randomizing the data for each encryption, we need to generate the input data for the encryption operation executed on the device. This is typically done offline (i.e., on our workstation), but this requires sending input data for each iteration of the encryption operation. This slows down the acquisition significantly, hence we benefit of measuring multiple cryptographic operation in a single communication cycle.

Therefore, we decided to use the hardware SHA1 accelerator present on the target to deterministically derive semi-random inputs, out of a randomized seed received from our workstation. We could also leverage another cryptographic engine, even the AES engine itself, to accomplish the same, likely even faster. The modified encryption loop on the ESP32 chip is shown below.

    ...
    iterations = 20000
    for(int i= 0; i < iterations; i++) {
        ets_sha_init(&ctx);
        ets_sha_update(&ctx, 0, sha_buffer_out, 20 * 8);
        ets_sha_finish(&ctx, 0, sha_buffer_out);

        GPIO_OUTPUT_SET(26,1);
        ets_aes_crypt(sha_buffer_out, tout);
        GPIO_OUTPUT_SET(26,0);
    }
    ...

Using this approach, we are able to acquire 200,000 measurements, an amount sufficient to recover the entire key without brute forcing, in only ~16 seconds.

The traces processing performed with Riscure’s Inspector allows us to successfully recover the key in ~1 minute, as is shown below.

Results after 200000 traces
Best score for Round 0: Key: Column 0, Row 0 with rdm: 2.6537:
+ rank: 1, candidate:  26 (0x1A), confidence: 0.0136 at position: 0
- rank: 2, candidate:  94 (0x5E), confidence: 0.0085 at position: 0
- rank: 3, candidate:  69 (0x45), confidence: 0.0081 at position: 0
- rank: 4, candidate:  47 (0x2F), confidence: 0.0078 at position: 0
Best score for Round 0: Key: Column 0, Row 1 with rdm: 3.9071:
+ rank: 1, candidate: 122 (0x7A), confidence: 0.0187 at position: 0
- rank: 2, candidate:  69 (0x45), confidence: 0.0100 at position: 0
- rank: 3, candidate: 108 (0x6C), confidence: 0.0092 at position: 0
- rank: 4, candidate: 221 (0xDD), confidence: 0.0088 at position: 0
Best score for Round 0: Key: Column 0, Row 2 with rdm: 5.8470:
+ rank: 1, candidate: 142 (0x8E), confidence: 0.0218 at position: 0
- rank: 2, candidate:  12 (0x0C), confidence: 0.0092 at position: 0
- rank: 3, candidate: 152 (0x98), confidence: 0.0083 at position: 0
- rank: 4, candidate:  97 (0x61), confidence: 0.0080 at position: 0
Best score for Round 0: Key: Column 0, Row 3 with rdm: 1.3096:
+ rank: 1, candidate: 219 (0xDB), confidence: 0.0117 at position: 0
- rank: 2, candidate: 240 (0xF0), confidence: 0.0091 at position: 0
- rank: 3, candidate: 148 (0x94), confidence: 0.0088 at position: 0
- rank: 4, candidate: 223 (0xDF), confidence: 0.0085 at position: 0
Best score for Round 0: Key: Column 1, Row 0 with rdm: 3.1125:
+ rank: 1, candidate:  25 (0x19), confidence: 0.0182 at position: 0
- rank: 2, candidate:  94 (0x5E), confidence: 0.0106 at position: 0
- rank: 3, candidate: 194 (0xC2), confidence: 0.0101 at position: 0
- rank: 4, candidate: 148 (0x94), confidence: 0.0099 at position: 0
Best score for Round 0: Key: Column 1, Row 1 with rdm: 3.2461:
+ rank: 1, candidate: 206 (0xCE), confidence: 0.0125 at position: 0
- rank: 2, candidate: 164 (0xA4), confidence: 0.0070 at position: 0
- rank: 3, candidate:  76 (0x4C), confidence: 0.0069 at position: 0
- rank: 4, candidate: 111 (0x6F), confidence: 0.0064 at position: 0
Best score for Round 0: Key: Column 1, Row 2 with rdm: 1.3049:
+ rank: 1, candidate: 119 (0x77), confidence: 0.0158 at position: 0
- rank: 2, candidate:  72 (0x48), confidence: 0.0126 at position: 0
- rank: 3, candidate:  94 (0x5E), confidence: 0.0115 at position: 0
- rank: 4, candidate: 124 (0x7C), confidence: 0.0099 at position: 0
Best score for Round 0: Key: Column 1, Row 3 with rdm: 4.7617:
+ rank: 1, candidate:  93 (0x5D), confidence: 0.0222 at position: 0
- rank: 2, candidate: 134 (0x86), confidence: 0.0108 at position: 0
- rank: 3, candidate:  47 (0x2F), confidence: 0.0090 at position: 0
- rank: 4, candidate:  57 (0x39), confidence: 0.0089 at position: 0
Best score for Round 0: Key: Column 2, Row 0 with rdm: 2.0899:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0159 at position: 0
- rank: 2, candidate: 244 (0xF4), confidence: 0.0106 at position: 0
- rank: 3, candidate: 180 (0xB4), confidence: 0.0102 at position: 0
- rank: 4, candidate:  75 (0x4B), confidence: 0.0095 at position: 0
Best score for Round 0: Key: Column 2, Row 1 with rdm: 2.3057:
+ rank: 1, candidate:  57 (0x39), confidence: 0.0162 at position: 0
- rank: 2, candidate: 228 (0xE4), confidence: 0.0112 at position: 0
- rank: 3, candidate: 194 (0xC2), confidence: 0.0092 at position: 0
- rank: 4, candidate: 110 (0x6E), confidence: 0.0085 at position: 0
Best score for Round 0: Key: Column 2, Row 2 with rdm: 2.0476:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0168 at position: 0
- rank: 2, candidate:  25 (0x19), confidence: 0.0111 at position: 0
- rank: 3, candidate: 116 (0x74), confidence: 0.0110 at position: 0
- rank: 4, candidate: 126 (0x7E), confidence: 0.0109 at position: 0
Best score for Round 0: Key: Column 2, Row 3 with rdm: 2.2039:
+ rank: 1, candidate: 164 (0xA4), confidence: 0.0153 at position: 0
- rank: 2, candidate: 179 (0xB3), confidence: 0.0101 at position: 0
- rank: 3, candidate: 118 (0x76), confidence: 0.0095 at position: 0
- rank: 4, candidate: 247 (0xF7), confidence: 0.0094 at position: 0
Best score for Round 0: Key: Column 3, Row 0 with rdm: 0.4566:
+ rank: 1, candidate:  65 (0x41), confidence: 0.0276 at position: 0
- rank: 2, candidate: 245 (0xF5), confidence: 0.0254 at position: 0
- rank: 3, candidate: 115 (0x73), confidence: 0.0248 at position: 0
- rank: 4, candidate:  78 (0x4E), confidence: 0.0247 at position: 0
Best score for Round 0: Key: Column 3, Row 1 with rdm: 1.8494:
+ rank: 1, candidate:  39 (0x27), confidence: 0.0156 at position: 0
- rank: 2, candidate:  82 (0x52), confidence: 0.0115 at position: 0
- rank: 3, candidate: 203 (0xCB), confidence: 0.0107 at position: 0
- rank: 4, candidate:  44 (0x2C), confidence: 0.0097 at position: 0
Best score for Round 0: Key: Column 3, Row 2 with rdm: 1.9529:
+ rank: 1, candidate:  33 (0x21), confidence: 0.0175 at position: 0
- rank: 2, candidate: 102 (0x66), confidence: 0.0127 at position: 0
- rank: 3, candidate: 134 (0x86), confidence: 0.0123 at position: 0
- rank: 4, candidate:  91 (0x5B), confidence: 0.0103 at position: 0
Best score for Round 0: Key: Column 3, Row 3 with rdm: 0.6008:
+ rank: 1, candidate: 186 (0xBA), confidence: 0.0161 at position: 0
- rank: 2, candidate: 246 (0xF6), confidence: 0.0142 at position: 0
- rank: 3, candidate: 111 (0x6F), confidence: 0.0136 at position: 0
- rank: 4, candidate: 105 (0x69), confidence: 0.0131 at position: 0
Unverified key: (0x1a7a8edb19ce775d413941a4412721ba)
Process finished after evaluating 1.00 key candidates
Correct key found: 1a7a8edb19ce775d413941a4412721ba
Runtime (s): 56.6904158

We can speed up the attack phase by using Jlsca, a SCA toolkit made by ceesb and available on Riscure’s GitHub repository. The script we used to extract the entire key is shown below.

using Jlsca.Sca
using Jlsca.Trs
using Jlsca.Aes

filename = "ESP32-HW-AES-SINGLE-SAMPLE-200k.trs"
trs = InspectorTrace(filename)
params = DpaAttack(AesSboxAttack(), IncrementalCPA())
params.dataOffset = 1
params.attack.direction = FORWARD
params.analysis.leakages = [HW()]
numberOfTraces = length(trs);

@time rankData = sca(trs, params, 1, numberOfTraces)

Using the above script, of which the output is shown below, we were able to extract the entire key in less than 10 seconds, without any brute forcing.

julia attack.jl
Opened ESP32-HW-AES-SINGLE-SAMPLE-200k.trs
#traces 200000, #samples 1 (Float32), #data 32

Jlsca running in Julia version: 1.8.5, 1 processes/1 workers/16 threads per worker

DPA parameters
attack:       AES Sbox CIPHER KL128 FORWARD
mode:         CIPHER
key length:   KL128
direction:    FORWARD
xor:          false
analysis:     Incremental CPA
leakages:     HW
maximization: abs global max
data at:      1

phase: 1 / 1, #targets 16

Attacking columns 1:1 out of 1 columns (run 1 out of 1)
Running "Incremental correlation" on trace range 1:1:200000, 1 data passes, 0 sample passes
Processing traces 1:200000 .. 100% |...| Time: 0:00:02
Incremental CPA on range 1:1 produced (1, 4096) correlation matrix
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 1, phase: 1, ...
+ rank:   1, candidate: 0x1a, score: 0.013637 @ 1
- rank:   2, candidate: 0x5e, score: 0.008511 @ 1
- rank:   3, candidate: 0x45, score: 0.008067 @ 1
- rank:   4, candidate: 0x2f, score: 0.007813 @ 1
- rank:   5, candidate: 0x0c, score: 0.007084 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 2, phase: 1, ...
+ rank:   1, candidate: 0x7a, score: 0.018708 @ 1
- rank:   2, candidate: 0x45, score: 0.010001 @ 1
- rank:   3, candidate: 0x6c, score: 0.009226 @ 1
- rank:   4, candidate: 0xdd, score: 0.008752 @ 1
- rank:   5, candidate: 0x67, score: 0.008268 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 3, phase: 1, ...
+ rank:   1, candidate: 0x8e, score: 0.021768 @ 1
- rank:   2, candidate: 0x0c, score: 0.009159 @ 1
- rank:   3, candidate: 0x98, score: 0.008293 @ 1
- rank:   4, candidate: 0x61, score: 0.008021 @ 1
- rank:   5, candidate: 0x8c, score: 0.007858 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 4, phase: 1, ...
+ rank:   1, candidate: 0xdb, score: 0.011662 @ 1
- rank:   2, candidate: 0xf0, score: 0.009129 @ 1
- rank:   3, candidate: 0x94, score: 0.008829 @ 1
- rank:   4, candidate: 0xdf, score: 0.008490 @ 1
- rank:   5, candidate: 0xf4, score: 0.007312 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 5, phase: 1, ...
+ rank:   1, candidate: 0x19, score: 0.018190 @ 1
- rank:   2, candidate: 0x5e, score: 0.010612 @ 1
- rank:   3, candidate: 0xc2, score: 0.010127 @ 1
- rank:   4, candidate: 0x94, score: 0.009853 @ 1
- rank:   5, candidate: 0xe3, score: 0.009075 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 6, phase: 1, ...
+ rank:   1, candidate: 0xce, score: 0.012541 @ 1
- rank:   2, candidate: 0xa4, score: 0.006998 @ 1
- rank:   3, candidate: 0x4c, score: 0.006910 @ 1
- rank:   4, candidate: 0x6f, score: 0.006442 @ 1
- rank:   5, candidate: 0x3d, score: 0.006071 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 7, phase: 1, ...
+ rank:   1, candidate: 0x77, score: 0.015756 @ 1
- rank:   2, candidate: 0x48, score: 0.012625 @ 1
- rank:   3, candidate: 0x5e, score: 0.011476 @ 1
- rank:   4, candidate: 0x7c, score: 0.009862 @ 1
- rank:   5, candidate: 0x54, score: 0.009093 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 8, phase: 1, ...
+ rank:   1, candidate: 0x5d, score: 0.022229 @ 1
- rank:   2, candidate: 0x86, score: 0.010802 @ 1
- rank:   3, candidate: 0x2f, score: 0.009040 @ 1
- rank:   4, candidate: 0x39, score: 0.008853 @ 1
- rank:   5, candidate: 0x59, score: 0.008491 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 9, phase: 1, ...
+ rank:   1, candidate: 0x41, score: 0.015887 @ 1
- rank:   2, candidate: 0xf4, score: 0.010560 @ 1
- rank:   3, candidate: 0xb4, score: 0.010201 @ 1
- rank:   4, candidate: 0x4b, score: 0.009462 @ 1
- rank:   5, candidate: 0x2d, score: 0.009280 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 10, phase: 1, ...
+ rank:   1, candidate: 0x39, score: 0.016188 @ 1
- rank:   2, candidate: 0xe4, score: 0.011168 @ 1
- rank:   3, candidate: 0xc2, score: 0.009159 @ 1
- rank:   4, candidate: 0x6e, score: 0.008456 @ 1
- rank:   5, candidate: 0x07, score: 0.008258 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 11, phase: 1, ...
+ rank:   1, candidate: 0x41, score: 0.016778 @ 1
- rank:   2, candidate: 0x19, score: 0.011101 @ 1
- rank:   3, candidate: 0x74, score: 0.010976 @ 1
- rank:   4, candidate: 0x7e, score: 0.010926 @ 1
- rank:   5, candidate: 0xe2, score: 0.010595 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 12, phase: 1, ...
+ rank:   1, candidate: 0xa4, score: 0.015283 @ 1
- rank:   2, candidate: 0xb3, score: 0.010129 @ 1
- rank:   3, candidate: 0x76, score: 0.009530 @ 1
- rank:   4, candidate: 0xf7, score: 0.009418 @ 1
- rank:   5, candidate: 0x15, score: 0.009243 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 13, phase: 1, ...
+ rank:   1, candidate: 0x41, score: 0.027563 @ 1
- rank:   2, candidate: 0xf5, score: 0.025414 @ 1
- rank:   3, candidate: 0x73, score: 0.024782 @ 1
- rank:   4, candidate: 0x4e, score: 0.024713 @ 1
- rank:   5, candidate: 0xb5, score: 0.024684 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 14, phase: 1, ...
+ rank:   1, candidate: 0x27, score: 0.015643 @ 1
- rank:   2, candidate: 0x52, score: 0.011513 @ 1
- rank:   3, candidate: 0xcb, score: 0.010737 @ 1
- rank:   4, candidate: 0x2c, score: 0.009734 @ 1
- rank:   5, candidate: 0x69, score: 0.009411 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 15, phase: 1, ...
+ rank:   1, candidate: 0x21, score: 0.017519 @ 1
- rank:   2, candidate: 0x66, score: 0.012684 @ 1
- rank:   3, candidate: 0x86, score: 0.012334 @ 1
- rank:   4, candidate: 0x5b, score: 0.010321 @ 1
- rank:   5, candidate: 0x8f, score: 0.010318 @ 1
Results @ 200000 rows, 1 cols (200000 rows consumed) target: 16, phase: 1, ...
+ rank:   1, candidate: 0xba, score: 0.016071 @ 1
- rank:   2, candidate: 0xf6, score: 0.014246 @ 1
- rank:   3, candidate: 0x6f, score: 0.013595 @ 1
- rank:   4, candidate: 0x69, score: 0.013145 @ 1
- rank:   5, candidate: 0x2b, score: 0.012718 @ 1
recovered key material: 1a7a8edb19ce775d413941a4412721ba
recovered key: 1a7a8edb19ce775d413941a4412721ba
Runtime (s): 8.682181 seconds (43.60 M allocations: 1.897 GiB, ...)

To summarize, by combining Picoscope’s Rapid Block Mode, Riscure’s FiPy and Riscure’s Jlsca toolkit, we are able to acquire 200,000 traces and perform the CPA attack in order to extract the entire key in ~25 seconds, without any brute forcing.

Final words

Power analysis attacks on cryptographic algorithms, like AES, are known to be effective for over multiple decades. Therefore, it’s not surprising at all, that the ESP32’s hardware AES engine is vulnerable to a straight-forward power analysis attack. It’s simply not protected against such threats.

The abundance of available tooling and knowledge in today’s world definitely decreases the complexity for extracting cryptographic keys.

Where it used to take an attacker with an Expert skill-level to perform these type of attacks on cryptographic implementations, it can nowadays be successfully performed by attackers with an Intermediate skill-level.

Needless to say, when cryptographic algorithms are sufficiently hardened by using dedicated countermeasures (e.g., random masking, random delays, noise generation, parallel execution, etc.), it may not be so trivial to perform a successful attack.

In our next blog post, we will perform a similar attack by measuring the electromagnetic emissions emitted from the chip. But, for now, we hope you have enjoyed this write-up.

Feel free to reach out for questions or remarks related to this research. As always, we are available to give training related to our research, during which you will gain hands-on experience exploiting the vulnerabilities described in this blog post.

- Raelize.