Skip to content

Commit 26519a1

Browse files
committed
[device] CW340 support
This PR adds experimental CW340 support with a minimal running capture script. Signed-off-by: Pascal Nasahl <nasahlpa@lowrisc.org>
1 parent 5abf4c6 commit 26519a1

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

cw/cw340_aes_sca.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#!/usr/bin/env python3
2+
# Copyright lowRISC contributors.
3+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4+
# SPDX-License-Identifier: Apache-2.0
5+
import binascii
6+
import random
7+
import signal
8+
import sys
9+
import time
10+
from datetime import datetime
11+
from functools import partial
12+
from pathlib import Path
13+
14+
import chipwhisperer as cw
15+
import numpy as np
16+
import yaml
17+
from Crypto.Cipher import AES
18+
from tqdm import tqdm
19+
20+
from util import device, plot, trace_util
21+
22+
def setup_target(scope):
23+
target = cw.target(scope)
24+
target.baud = int(115200)
25+
target.flush()
26+
version = None
27+
ping_cnt = 0
28+
while not version:
29+
if ping_cnt == 3:
30+
print("no response from target")
31+
sys.exit(0)
32+
target.write('v' + '\n')
33+
ping_cnt += 1
34+
time.sleep(0.5)
35+
version = target.read().strip()
36+
print(version)
37+
return target
38+
39+
def setup_scope(cfg):
40+
scope = cw.scope()
41+
scope.gain.db = cfg["cwfpgahusky"]["scope_gain"]
42+
scope.adc.basic_mode = "rising_edge"
43+
scope.clock.clkgen_src = 'extclk'
44+
scope.clock.clkgen_freq = cfg["cwfpgahusky"]["pll_frequency"]
45+
scope.clock.adc_mul = cfg["cwfpgahusky"]["adc_mul"]
46+
scope.clock.extclk_monitor_enabled = False
47+
scope.adc.samples = cfg["cwfpgahusky"]["num_samples"]
48+
if cfg["cwfpgahusky"]["offset"] >= 0:
49+
scope.adc.offset = cfg["cwfpgahusky"]["offset"]
50+
else:
51+
scope.adc.offset = 0
52+
scope.adc.presamples = -cfg["cwfpgahusky"]["offset"]
53+
scope.trigger.triggers = "tio4"
54+
scope.io.tio1 = "serial_tx"
55+
scope.io.tio2 = "serial_rx"
56+
scope.io.hs2 = "disabled"
57+
scope.clock.clkgen_src = 'extclk'
58+
if not scope.clock.clkgen_locked:
59+
print("scope.clock.clkgen is not locked")
60+
sys.exit(0)
61+
if not scope.clock.adc_locked:
62+
print("scope.clock.adc is not locked")
63+
sys.exit(0)
64+
return scope
65+
66+
def prepare_aes(cfg):
67+
# Preparation of Key and plaintext generation
68+
# Generate key at random based on test_random_seed (not used atm)
69+
random.seed(cfg["test"]["test_random_seed"])
70+
key = bytearray(cfg["test"]["key_len_bytes"])
71+
for i in range(0, cfg["test"]["key_len_bytes"]):
72+
key[i] = random.randint(0, 255)
73+
# Load initial key and text values from cfg
74+
key = bytearray(cfg["test"]["key"])
75+
print(f'Using key: {binascii.b2a_hex(bytes(key))}')
76+
text = bytearray(cfg["test"]["text"])
77+
# Prepare generation of new texts/keys by encryption using key_for_generation
78+
key_for_gen = bytearray(cfg["test"]["key_for_gen"])
79+
cipher_gen = AES.new(bytes(key_for_gen), AES.MODE_ECB)
80+
return key, text, key_for_gen, cipher_gen
81+
82+
83+
if __name__ == '__main__':
84+
# Load configuration from file
85+
with open('simple_capture_aes_sca_cw340.yaml') as f:
86+
cfg = yaml.load(f, Loader=yaml.FullLoader)
87+
scope = setup_scope(cfg)
88+
target = setup_target(scope)
89+
90+
# Create ChipWhisperer project for storage of traces and metadata
91+
project = cw.create_project(cfg["capture"]["project_name"], overwrite=True)
92+
93+
key, text, key_for_gen, cipher_gen = prepare_aes(cfg)
94+
95+
# Set key
96+
target.simpleserial_write("k", key)
97+
98+
# Cipher to compute expected responses
99+
cipher = AES.new(bytes(key), AES.MODE_ECB)
100+
101+
# Main loop for measurements with progress bar
102+
for _ in tqdm(range(cfg["capture"]["num_traces"]), desc='Capturing', ncols=80):
103+
scope.arm()
104+
105+
# Generate new text for this iteration
106+
text = bytearray(cipher_gen.encrypt(text))
107+
# Load text and trigger execution
108+
target.simpleserial_write('p', text)
109+
110+
# Capture trace
111+
ret = scope.capture(poll_done=False)
112+
i = 0
113+
while not target.is_done():
114+
i += 1
115+
time.sleep(0.05)
116+
if i > 100:
117+
print("Warning: Target did not finish operation")
118+
if ret:
119+
print("Warning: Timeout happened during capture")
120+
121+
# Get trace
122+
wave = scope.get_last_trace(as_int=True)
123+
124+
125+
# Get response from device and verify
126+
response = target.simpleserial_read('r', target.output_len, ack=False)
127+
if binascii.b2a_hex(response) != binascii.b2a_hex(cipher.encrypt(bytes(text))):
128+
raise RuntimeError(f'Bad ciphertext: {response} != {cipher.encrypt(bytes(text))}.')
129+
130+
# Sanity check retrieved data (wave) and create CW Trace
131+
if len(wave) >= 1:
132+
trace = cw.Trace(wave, text, response, key)
133+
else:
134+
raise RuntimeError('Capture failed.')
135+
136+
# Check if ADC range has been exceeded for Husky.
137+
trace_util.check_range(trace.wave, scope.adc.bits_per_sample)
138+
139+
# Append CW trace to CW project storage
140+
project.traces.append(trace, dtype=np.uint16)
141+
142+
# Save metadata and entire configuration cfg to project file
143+
project.settingsDict['datetime'] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
144+
project.settingsDict['cfg'] = cfg
145+
sample_rate = int(round(scope.clock.adc_freq, -6))
146+
project.settingsDict['sample_rate'] = sample_rate
147+
project.save()
148+
149+
# Create and show test plot
150+
if cfg["capture"]["show_plot"]:
151+
plot.save_plot_to_file(project.waves, None, cfg["capture"]["plot_traces"],
152+
cfg["capture"]["trace_image_filename"], add_mean_stddev=True)
153+
print(f'Created plot with {cfg["capture"]["plot_traces"]} traces: '
154+
f'{Path(cfg["capture"]["trace_image_filename"]).resolve()}')

cw/simple_capture_aes_sca_cw340.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
cwfpgahusky:
2+
baudrate: 115200
3+
output_len_bytes: 16
4+
pll_frequency: 100000000
5+
adc_mul: 2
6+
num_segments: 1
7+
num_samples: 1200
8+
offset: -40
9+
scope_gain: 31.5
10+
capture:
11+
scope_select: husky
12+
num_traces: 1000
13+
project_name: "projects/simple_capture_aes_sca"
14+
show_plot: True
15+
plot_traces: 100
16+
trace_image_filename: "projects/simple_capture_aes_sca_sample_traces.html"
17+
test:
18+
key_len_bytes: 16
19+
test_random_seed: 0
20+
key: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9]
21+
text: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]
22+
key_for_gen: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0]

0 commit comments

Comments
 (0)