This is an example of using Jlsca to analyze the trace set from the simplest SCA challenge of RHme2 embedded CTF (http://rhme.riscure.com/home).
The challenge features an unprotected SW AES-128 implementation on an 8-bit AVR microcontroller. You can send plaintext blocks to the device and receive blocks of ciphertext. The device LED blinks on the start of the encryption. The goal is to recover the encryption key.
Power traces were acquired using ChipWhisperer Lite and accompanying software (https://wiki.newae.com/Main_Page). The trigger was at the start of the cipher execution by using the blinking LED. After some trivial exploration, first round S-boxes can could be identified. For the attack in this example, only the corresponding part of the execution was captured: 10000 samples, at 105 MS/s sampling rate.
The small tarball with traces is available at https://drive.google.com/open?id=0B2slHLSL3nXaWFJ0dHVPWFJqalE, shasum 13b0a41e597cf90d495ad3322bf947e675c71c8d
. Uncompress it next to this notebook.
In [1]:
# load the tools
using Jlsca.Sca
using Jlsca.Trs
using Jlsca.Align
using Jlsca.Aes
using PyCall
using Plots
In [2]:
insfname = "rhme2-pieceofscake-firstroundsboxes.trs"
if !isfile(insfname)
# prefix identifying the capture, bulky as it is
# (so far have been lazy to automate based on ChipWhisperer config file)
prefix = "rhme2-pieceofscake-firstroundsboxes/2017.01.26-17.11.15_"
numpy = pyimport("numpy")
# read the data from chipwhisperer capture
samples = numpy.load("$(prefix)traces.npy");
input = numpy.load("$(prefix)textin.npy");
output = numpy.load("$(prefix)textout.npy");
# get sizes
print(size(samples))
print(size(input))
print(size(output))
# set the parameters
numberOfTraces = size(input)[1] #weirdly, ChipWhisperer capture saves more traces then inputs
numberOfSamples = size(samples)[2]
dataSpace = size(input)[2] + size(output)[2]
sampleType = Float32;
# create and save the trs
trs = InspectorTrace(insfname, dataSpace, sampleType, numberOfSamples)
for t in 1:numberOfTraces
trs[t] = (vcat(input[t,:],output[t,:]), map(Float32, samples[t,:]))
end
close(trs)
end
In [3]:
# load the traceset
trs = InspectorTrace(insfname)
In [4]:
# read and plot 3 traces with some zoom
((data,samples),eof) = readTraces(trs, 1:3)
plot(samples[1:3,1:40]', linewidth=.3) # note the transpose; and here you can play with the zoom
Out[4]:
Well aligned, should be piece of cake indeed. Let's close the file for now.
In [5]:
close(trs)
In [ ]:
trs = InspectorTrace(insfname)
params = DpaAttack(AesSboxAttack(), IncrementalCPA())
params.dataOffset = 1 # plaintext starts from byte 1
params.attack.direction = FORWARD
params.analysis.leakages = [HW()]
numberOfTraces = length(trs);
rankData = sca(trs, params, 1, numberOfTraces)
key = getKey(params,rankData)
Check the key using a paintext-ciphertext pair from the traceset
In [ ]:
w = KeyExpansion(key, 10, 4)
Cipher(trs[1][1][1:16], w) == trs[1][1][17:32]
Done.