Skip to content

Commit ecbad43

Browse files
committed
[test] Make bazel framework for testing
Make a bazel framework in ot-sca as extension of OpenTitan and add test scripts (pytests) from the host side for the penetrationtests. Integrate the capture and fault injection scripts to the latest testOS and add the Bazel framework. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent c81a42a commit ecbad43

252 files changed

Lines changed: 29069 additions & 8369 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.bazelversion

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
6.2.1

BUILD.bazel

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright lowRISC contributors (OpenTitan project).
2+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
package(default_visibility = ["//visibility:public"])
6+
7+
exports_files([
8+
"WORKSPACE",
9+
"python-requirements.txt",
10+
])

MODULE.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
###############################################################################
2+
# Bazel now uses Bzlmod by default to manage external dependencies.
3+
# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel.
4+
#
5+
# For more details, please check https://github.com/bazelbuild/bazel/issues/18958
6+
###############################################################################

MODULE.bazel.lock

Lines changed: 139 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

WORKSPACE.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# DO NOT MODIFY THIS FILE.
2+
#
3+
# It must match what is in the open source OpenTitan repository.
4+
workspace(name = "otsca_exts")

analysis/BUILD

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright lowRISC contributors (OpenTitan project).
2+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
load("@//third_party/python:requirements.bzl", "requirement")
6+
7+
package(default_visibility = ["//visibility:public"])
8+
9+
py_library(
10+
name = "ceca",
11+
srcs = ["ceca.py"],
12+
deps = [
13+
requirement("numpy"),
14+
requirement("chipwhisperer"),
15+
],
16+
)
17+
18+
py_library(
19+
name = "trace_preprocessing",
20+
srcs = ["trace_preprocessing.py"],
21+
deps = [
22+
requirement("numpy"),
23+
requirement("chipwhisperer"),
24+
requirement("tqdm"),
25+
],
26+
)
27+
28+
py_library(
29+
name = "tvla",
30+
srcs = ["tvla.py"],
31+
deps = [
32+
requirement("numpy"),
33+
],
34+
)

analysis/ceca.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# Append ot-sca root directory to path such that ceca.py can find the
2222
# project_library module located in the capture/ directory.
2323
ABS_PATH = os.path.dirname(os.path.abspath(__file__))
24-
sys.path.append(ABS_PATH + '/..')
24+
sys.path.append(ABS_PATH + "/..")
2525
from capture.project_library.project import ProjectConfig # noqa : E402
2626
from capture.project_library.project import SCAProject # noqa : E402
2727

@@ -91,28 +91,29 @@ def __init__(self, project_file, trace_slice, attack_window, attack_direction):
9191
# ChipWhisperer or ot_trace_library project?
9292
project_type = "cw"
9393
if ".db" in project_file:
94-
project_type = 'ot_trace_library'
94+
project_type = "ot_trace_library"
9595

9696
# Open the project.
97-
project_cfg = ProjectConfig(type = project_type,
98-
path = project_file,
99-
wave_dtype = np.uint16,
100-
overwrite = False
101-
)
97+
project_cfg = ProjectConfig(
98+
type=project_type, path=project_file, wave_dtype=np.uint16, overwrite=False
99+
)
102100
self.project = SCAProject(project_cfg)
103101
self.project.open_project()
104102

105103
# TODO: Consider more efficient formats.
106104
self.num_samples = attack_window.stop - attack_window.start
107105
if attack_direction == AttackDirection.INPUT:
108-
self.texts = np.vstack(self.project.get_plaintexts(
109-
trace_slice.start, trace_slice.stop))
106+
self.texts = np.vstack(
107+
self.project.get_plaintexts(trace_slice.start, trace_slice.stop)
108+
)
110109
else:
111-
self.texts = np.vstack(self.project.get_ciphertexts(
112-
trace_slice.start, trace_slice.stop))
110+
self.texts = np.vstack(
111+
self.project.get_ciphertexts(trace_slice.start, trace_slice.stop)
112+
)
113113

114-
self.traces = np.asarray(self.project.get_waves(
115-
trace_slice.start, trace_slice.stop))[:, attack_window]
114+
self.traces = np.asarray(
115+
self.project.get_waves(trace_slice.start, trace_slice.stop)
116+
)[:, attack_window]
116117

117118
self.project.close(save=False)
118119

@@ -176,7 +177,7 @@ def count_and_sum_text_traces(self):
176177
val_changes = np.where(np.roll(sorted_bytes, 1) != sorted_bytes)[0]
177178
# Append the number of rows to be able to use ``pairwise``.
178179
val_indices = list(val_changes) + [sorted_bytes.shape[0]]
179-
for (start, end) in more_itertools.pairwise(val_indices):
180+
for start, end in more_itertools.pairwise(val_indices):
180181
byte_val = sorted_bytes[start]
181182
cnts[byte_pos, byte_val] = end - start
182183
act_indices = sorted_indices[start:end]
@@ -213,8 +214,7 @@ def compute_mean_and_std(workers):
213214
running_cnt += cnt
214215
else:
215216
running_sum_dev_prods += sum_dev_prods + (
216-
(cnt * running_sum - running_cnt * sum_) ** 2 /
217-
(cnt * running_cnt * (cnt + running_cnt))
217+
(cnt * running_sum - running_cnt * sum_) ** 2 / (cnt * running_cnt * (cnt + running_cnt))
218218
)
219219
running_sum += sum_
220220
running_cnt += cnt
@@ -396,7 +396,7 @@ def find_best_diffs(pairwise_diffs_scores):
396396
# other bytes.
397397
diffs = np.zeros(16, dtype=np.uint8)
398398
for byte in range(1, 16):
399-
for (a, b) in more_itertools.pairwise(paths[byte]):
399+
for a, b in more_itertools.pairwise(paths[byte]):
400400
diffs[byte] ^= int(pairwise_diffs_scores[a, b, 0])
401401
return diffs
402402

@@ -502,14 +502,12 @@ def perform_attack(
502502
# ChipWhisperer or ot_trace_library project?
503503
project_type = "cw"
504504
if ".db" in project_file:
505-
project_type = 'ot_trace_library'
505+
project_type = "ot_trace_library"
506506

507507
# Open the project.
508-
project_cfg = ProjectConfig(type = project_type,
509-
path = project_file,
510-
wave_dtype = np.uint16,
511-
overwrite = False
512-
)
508+
project_cfg = ProjectConfig(
509+
type=project_type, path=project_file, wave_dtype=np.uint16, overwrite=False
510+
)
513511
project = SCAProject(project_cfg)
514512
project.open_project()
515513

@@ -559,7 +557,7 @@ def worker_trace_slices():
559557
num_traces = filter_noisy_traces(workers, mean, std_dev, max_std)
560558
logging.info(
561559
f"Will use {num_traces} traces "
562-
f"({100*num_traces/orig_num_traces:.1f}% of all traces)"
560+
f"({100 * num_traces / orig_num_traces:.1f}% of all traces)"
563561
)
564562
# Mean traces for all values of all text bytes.
565563
mean_text_traces = compute_mean_text_traces(workers)
@@ -568,18 +566,21 @@ def worker_trace_slices():
568566
diffs = find_best_diffs(pairwise_diffs_scores)
569567
logging.info(f"Difference values (delta_0_i): {diffs}")
570568
# Recover the key.
571-
key = recover_key(diffs, attack_direction, project.get_plaintexts(0),
572-
project.get_ciphertexts(0))
569+
key = recover_key(
570+
diffs, attack_direction, project.get_plaintexts(0), project.get_ciphertexts(0)
571+
)
573572
if key is not None:
574573
logging.info(f"Recovered AES key: {bytes(key).hex()}")
575574
else:
576575
logging.error("Failed to recover the AES key")
577576
# Compare differences - both matrices are symmetric and have an all-zero main diagonal.
578-
correct_diffs = compare_diffs(pairwise_diffs_scores, attack_direction,
579-
project.get_keys(0))
577+
correct_diffs = compare_diffs(
578+
pairwise_diffs_scores, attack_direction, project.get_keys(0)
579+
)
580580
logging.info(
581-
f"Recovered {((np.sum(correct_diffs)-16)/2).astype(int)}/120 "
582-
"differences between key bytes")
581+
f"Recovered {((np.sum(correct_diffs) - 16) / 2).astype(int)}/120 "
582+
"differences between key bytes"
583+
)
583584
project.close(save=False)
584585
return key
585586

@@ -592,8 +593,10 @@ def parse_args():
592593
Mischke, and T. Eisenbarth (https://eprint.iacr.org/2010/297.pdf)."""
593594
)
594595
parser.add_argument(
595-
"-f", "--project-file", required=True,
596-
help="chipwhisperer or ot_trace_library project file"
596+
"-f",
597+
"--project-file",
598+
required=True,
599+
help="chipwhisperer or ot_trace_library project file",
597600
)
598601
parser.add_argument(
599602
"-n",
@@ -658,9 +661,12 @@ def main():
658661
attack."""
659662
args = parse_args()
660663
config_logger()
661-
ray.init(runtime_env={"working_dir": "../",
662-
"excludes": ["*.db", "*.cwp", "*.npy", "*.bit",
663-
"*/lfs/*", "*.pack"]})
664+
ray.init(
665+
runtime_env={
666+
"working_dir": "../",
667+
"excludes": ["*.db", "*.cwp", "*.npy", "*.bit", "*/lfs/*", "*.pack"],
668+
}
669+
)
664670

665671
key = perform_attack(**vars(args))
666672
sys.exit(0 if key is not None else 1)

0 commit comments

Comments
 (0)