Using CWlite, electromagnetic analysis was conducted to compare with power analysis attacks. When experiments were conducted using the code below for both power analysis and electromagnetic analysis, power analysis succeeded with 30-40 traces, whereas electromagnetic analysis succeeded with traces ranging between 1000 and 6000. Given the significant difference, I would like your comments on whether there is anything strange in the code.
The intended functionality of the code is to perform analysis after capturing each trace and, in the end, output the number of traces required to guess the correct key.
from tqdm.notebook import trange
import numpy as np
Capturing waveforms and guessing keys
def realtime_cpa(scope, target, ktp, correct_key, max_traces=10000):
trace_array =
textin_array =
# Split the correct key into a 16-byte list
correct_key = [correct_key[i] for i in range(16)]
best_guess = [0] * 16 # The guessed key
num_traces = 0
for i in trange(max_traces, desc="Capturing and analyzing traces"):
num_traces += 1
key, text = ktp.next()
target.set_key(key)
# Capture waveform
scope.arm()
target.simpleserial_write('p', text)
ret = scope.capture()
if ret:
print("Target timed out!")
continue
trace_array.append(scope.get_last_trace())
textin_array.append(text)
trace_array_np = np.array(trace_array)
# Perform CPA analysis byte by byte
t_bar = mean(trace_array_np)
o_t = std_dev(trace_array_np, t_bar)
success = True
for bnum in range(16):
max_cpa = [0] * 256
for kguess in range(256):
hws = np.array([[HW[aes_internal(textin[bnum], kguess)] for textin in textin_array]]).transpose()
hws_bar = mean(hws)
o_hws = std_dev(hws, hws_bar)
correlation = cov(trace_array_np, t_bar, hws, hws_bar)
cpaoutput = correlation / (o_t * o_hws)
max_cpa[kguess] = max(abs(cpaoutput))
best_guess[bnum] = np.argmax(max_cpa)
# If the current guess does not match the correct key
if best_guess[bnum] != correct_key[bnum]:
success = False
# If the key matches, output the result and exit
if success:
print(f"Key matched after {num_traces} traces!")
print("Guessed Key: ", ''.join(f"{k:02x}" for k in best_guess))
return num_traces, best_guess
# If no match was found within the maximum number of traces
print("Failed to match key within the maximum number of traces.")
print("Last Guessed Key: ", ''.join(f"{k:02x}" for k in best_guess))
return num_traces, best_guess
ktp = cw.ktp.Basic()
correct_key = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]
num_traces, guessed_key = realtime_cpa(scope, target, ktp, correct_key)