Introduction to DPA & HW Assumption

Supported setups:






In [1]:


In [2]:

cd ../hardware/victims/firmware/simpleserial-aes

Out [2]:

rm -f -- simpleserial-aes-CWLITEXMEGA.hex

rm -f -- simpleserial-aes-CWLITEXMEGA.eep

rm -f -- simpleserial-aes-CWLITEXMEGA.cof

rm -f -- simpleserial-aes-CWLITEXMEGA.elf

rm -f --

rm -f -- simpleserial-aes-CWLITEXMEGA.sym

rm -f -- simpleserial-aes-CWLITEXMEGA.lss

rm -f -- objdir/*.o

rm -f -- objdir/*.lst

rm -f -- simpleserial-aes.s simpleserial.s XMEGA_AES_driver.s uart.s usart_driver.s xmega_hal.s aes-independant.s aes_enc.s aes_keyschedule.s aes_sbox.s aes128_enc.s

rm -f -- simpleserial-aes.d simpleserial.d XMEGA_AES_driver.d uart.d usart_driver.d xmega_hal.d aes-independant.d aes_enc.d aes_keyschedule.d aes_sbox.d aes128_enc.d

rm -f -- simpleserial-aes.i simpleserial.i XMEGA_AES_driver.i uart.i usart_driver.i xmega_hal.i aes-independant.i aes_enc.i aes_keyschedule.i aes_sbox.i aes128_enc.i


-------- begin --------

avr-gcc (WinAVR 20100110) 4.3.3

Copyright (C) 2008 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO



Compiling C: simpleserial-aes.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-aes.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/simpleserial-aes.o.d simpleserial-aes.c -o objdir/simpleserial-aes.o


Compiling C: .././simpleserial/simpleserial.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/simpleserial.o.d .././simpleserial/simpleserial.c -o objdir/simpleserial.o


Compiling C: .././hal/xmega/XMEGA_AES_driver.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/XMEGA_AES_driver.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/XMEGA_AES_driver.o.d .././hal/xmega/XMEGA_AES_driver.c -o objdir/XMEGA_AES_driver.o


Compiling C: .././hal/xmega/uart.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/uart.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/uart.o.d .././hal/xmega/uart.c -o objdir/uart.o


Compiling C: .././hal/xmega/usart_driver.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/usart_driver.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/usart_driver.o.d .././hal/xmega/usart_driver.c -o objdir/usart_driver.o


Compiling C: .././hal/xmega/xmega_hal.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/xmega_hal.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/xmega_hal.o.d .././hal/xmega/xmega_hal.c -o objdir/xmega_hal.o


Compiling C: .././crypto/aes-independant.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/aes-independant.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/aes-independant.o.d .././crypto/aes-independant.c -o objdir/aes-independant.o


Compiling C: .././crypto/avrcryptolib//aes/aes_enc.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/aes_enc.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/aes_enc.o.d .././crypto/avrcryptolib//aes/aes_enc.c -o objdir/aes_enc.o


Compiling C: .././crypto/avrcryptolib//aes/aes_keyschedule.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/aes_keyschedule.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/aes_keyschedule.o.d .././crypto/avrcryptolib//aes/aes_keyschedule.c -o objdir/aes_keyschedule.o


Compiling C: .././crypto/avrcryptolib//aes/aes_sbox.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/aes_sbox.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/aes_sbox.o.d .././crypto/avrcryptolib//aes/aes_sbox.c -o objdir/aes_sbox.o


Compiling C: .././crypto/avrcryptolib//aes/aes128_enc.c

avr-gcc -c -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/aes128_enc.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/aes128_enc.o.d .././crypto/avrcryptolib//aes/aes128_enc.c -o objdir/aes128_enc.o


Assembling: .././crypto/avrcryptolib//gf256mul/gf256mul.S

avr-gcc -c -mmcu=atxmega128d3 -I. -x assembler-with-cpp -DF_CPU=7372800 -Wa,-gstabs,-adhlns=objdir/gf256mul.lst -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul .././crypto/avrcryptolib//gf256mul/gf256mul.S -o objdir/gf256mul.o


Linking: simpleserial-aes-CWLITEXMEGA.elf

avr-gcc -mmcu=atxmega128d3 -I. -DNO_EXTRA_OPTS -fpack-struct -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_xmega -DPLATFORM=CWLITEXMEGA -DAVRCRYPTOLIB -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-aes.o -I.././simpleserial/ -I.././hal -I.././hal/xmega -I.././crypto/ -I.././crypto/avrcryptolib//aes -I.././crypto/avrcryptolib//gf256mul -std=gnu99 -MMD -MP -MF .dep/simpleserial-aes-CWLITEXMEGA.elf.d objdir/simpleserial-aes.o objdir/simpleserial.o objdir/XMEGA_AES_driver.o objdir/uart.o objdir/usart_driver.o objdir/xmega_hal.o objdir/aes-independant.o objdir/aes_enc.o objdir/aes_keyschedule.o objdir/aes_sbox.o objdir/aes128_enc.o objdir/gf256mul.o --output simpleserial-aes-CWLITEXMEGA.elf -Wl,,--cref   -lm


Creating load file for Flash: simpleserial-aes-CWLITEXMEGA.hex

avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-aes-CWLITEXMEGA.elf simpleserial-aes-CWLITEXMEGA.hex


Creating load file for EEPROM: simpleserial-aes-CWLITEXMEGA.eep

avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
    --change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-aes-CWLITEXMEGA.elf simpleserial-aes-CWLITEXMEGA.eep || exit 0


Creating Extended Listing: simpleserial-aes-CWLITEXMEGA.lss

avr-objdump -h -S -z simpleserial-aes-CWLITEXMEGA.elf > simpleserial-aes-CWLITEXMEGA.lss


Creating Symbol Table: simpleserial-aes-CWLITEXMEGA.sym

avr-nm -n simpleserial-aes-CWLITEXMEGA.elf > simpleserial-aes-CWLITEXMEGA.sym

Size after:

   text        data     bss     dec     hex filename

   3440          32     228    3700     e74 simpleserial-aes-CWLITEXMEGA.elf


+ Built for platform CW-Lite XMEGA


DPA Attack Theory

It’s first suggested that you complete PA_Intro_1 and PA_Intro_2, since that will introduce Jupyter and show how to interface with ChipWhisperer using Python. Assuming you’ve done that, let’s look at what we are trying to accomplish here. Going back to the theory, remember that we have an assumed relationship between power on the data lines and measured power consumption. You can see this in the following:

Power lines

Power lines

How do we prove this is true? Let’s plot the Hamming weight (HW) of the data to figure this out along with the power traces! We are going to use the AES algorithm (it doesn’t matter what we use), because that is an easy firmware to use as part of our attack.

Capturing Power Traces

Capturing power traces will be very similar to previous tutorials, except this time we’ll be using a loop to capture multiple traces, as well as numpy to store them. It’s not necessary, but we’ll also plot the trace we get using bokeh.


We’ll use some helper scripts to make setup and programming easier. If you’re using an XMEGA or STM (CWLITEARM) target, binaries with the correct should be setup for you:

In [3]:

%run "Helper_Scripts/Setup_Generic.ipynb"

In [4]:

fw_path = "../hardware/victims/firmware/simpleserial-aes/simpleserial-aes-{}.hex".format(PLATFORM)

In [5]:

cw.program_target(scope, prog, fw_path)

Out [5]:

XMEGA Programming flash...
XMEGA Reading flash...
Verified flash OK, 3471 bytes

Capturing Traces

Below you can see the capture loop. The main body of the loop loads some new plaintext, arms the scope, sends the key and plaintext, then finally records and appends our new trace to the traces[] list. At the end, we convert the trace data to numpy arrays, since that’s what we’ll be using for analysis.

In [6]:

#Capture Traces
from tqdm import tnrange
import numpy as np
import time

ktp = cw.ktp.Basic()

traces = []
N = 1000  # Number of traces

for i in tnrange(N, desc='Capturing traces'):
    key, text =  # manual creation of a key, text pair can be substituted here

    trace = cw.capture_trace(scope, target, text, key)

    if trace is None:

#Convert traces to numpy arrays
trace_array = np.asarray([trace.wave for trace in traces])  # if you prefer to work with numpy array for number crunching
textin_array = np.asarray([trace.textin for trace in traces])
known_keys = np.asarray([trace.key for trace in traces])  # for fixed key, these keys are all the same

Out [6]:

Now that we have our traces, we can also plot them using Bokeh:

In [7]:

from bokeh.plotting import figure, show
from import output_notebook

p = figure()

xrange = range(len(traces[0].wave))
p.line(xrange, traces[2].wave, line_color="red")

Out [7]:

Loading BokehJS ...

In [8]:

# cleanup the connection to the target and scope

Trace Analysis

Using the Trace Data

Now that we have some traces, let’s look at what we’ve actually recorded. Looking at the earlier parts of the script, we can see that the trace data is in trace_array, while textin_array stores what we sent to our target to be encrypted. For now, let’s get some basic information (the total number of traces, as well as the number of sample points in each trace) about the traces, since we’ll need that later:

In [9]:

numtraces = np.shape(trace_array)[0] #total number of traces
numpoints = np.shape(trace_array)[1] #samples per trace

For the analysis, we’ll need to loop over every byte in the key we want to attack, as well as every trace:

for bnum in range(0, 16):
    for tnum in range(0, numtraces):

Though we didn’t loop over them, note that each trace is made up of a bunch of sample points. Let’s take a closer look at AES so that we can replace that pass with some actual code.

Calculating Hamming weight (HW) of Data

Now that we have some power traces of our target that we can use, we can move on to the next steps of our attack. Looking way back to how AES works, remember we are effectively attemping to target the position at the bottom of this figure:

S-Box HW Leakage Point

S-Box HW Leakage Point

The objective is thus to determine the output of the S-Box, where the S-Box is defined as follows:

In [10]:

sbox = (
    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
    0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
    0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
    0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
    0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
    0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
    0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
    0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
    0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
    0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
    0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16)

Thus we need to write a function taking a single byte of input, a single byte of the key, and return the output of the S-Box:

In [11]:

def intermediate(pt, keyguess):
    return sbox[pt ^ keyguess]

Finally, remember we want the Hamming Weight of the S-Box output. Our assumption is that the system is leaking the Hamming Weight of the output of that S-Box. As a dumb solution, we could first convert every number to binary and count the 1’s:

>>> bin(0x1F)
>>> bin(0x1F).count('1')

This will ultimately be fairly slow. Instead we make a lookup table using this idea:

In [12]:

HW = [bin(n).count("1") for n in range(0, 256)]

def intermediate(pt, key):
    return sbox[pt ^ key]

#Example - PlainText is 0x12, key is 0xAB
HW[intermediate(0x12, 0xAB)]

Out [12]:


Plotting HW

Finally, what we are going to do is plot each of the different “classes” in a different color. With this we should see if there is some location that has relatively obvious difference in Hamming weight. We get that easily using the HW array and intermediate() function we defined earlier and a loop to plot all of the traces.

To make this easier, we can zoom in on some specific area. In the following example a small subset of the full capture is plotted only. You can more easily figure out what this point should be by using the CPA attack (we’ll talk about later) which provides more information about where the leakage is happening. For now let’s pretend we know already what a “good” point is:

In [13]:

from bokeh.plotting import figure, show
from import output_notebook
from bokeh.palettes import brewer

p = figure()

#Must run S-Box() script first to define the HW[] array and intermediate() function

#Must adjust these points for different compilers/targets
    plot_start = 930
    plot_end = 970
    plot_start = 1370
    plot_end = 1410
    plot_start = 590
    plot_end = 620

xrange = range(len(traces[0].wave))[plot_start:plot_end]
bnum = 0

color_mapper = (brewer['Reds'][9])

for trace in traces:
    hw_of_byte = HW[intermediate(trace.textin[bnum], trace.key[bnum])]
    p.line(xrange, trace.wave[plot_start:plot_end], line_color=color_mapper[hw_of_byte])


Out [13]:

Loading BokehJS ...
['#67000d', '#a50f15', '#cb181d', '#ef3b2c', '#fb6a4a', '#fc9272', '#fcbba1', '#fee0d2', '#fff5f0']