Skip to content

Commit fb253ec

Browse files
committed
[test] Add sca sha3
Add the test and host scripts for sha3. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent a6fdd2f commit fb253ec

4 files changed

Lines changed: 329 additions & 4 deletions

File tree

communication/sca_sha3_commands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def absorb_batch(self, num_segments):
145145
self.target.write(json.dumps("Batch").encode("ascii"))
146146
# Num_segments payload.
147147
time.sleep(0.01)
148-
num_segments_data = {"data": [x for x in num_segments]}
148+
num_segments_data = {"num_enc": num_segments}
149149
self.target.write(json.dumps(num_segments_data).encode("ascii"))
150150
# Wait for ack.
151151
self._ujson_sha3_sca_ack()

test/penetrationtests/sca/BUILD

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ py_binary(
5353
"//communication:sca_aes_commands",
5454
"//test/penetrationtests/util:utils",
5555
"@rules_python//python/runfiles",
56+
requirement("pycryptodome"),
5657
],
5758
data = [
5859
"@lowrisc_opentitan//sw/host/opentitantool",
@@ -93,6 +94,7 @@ py_binary(
9394
"//communication:sca_hmac_commands",
9495
"//test/penetrationtests/util:utils",
9596
"@rules_python//python/runfiles",
97+
requirement("pycryptodome"),
9698
],
9799
data = [
98100
"@lowrisc_opentitan//sw/host/opentitantool",
@@ -133,6 +135,7 @@ py_binary(
133135
"//communication:sca_kmac_commands",
134136
"//test/penetrationtests/util:utils",
135137
"@rules_python//python/runfiles",
138+
requirement("pycryptodome"),
136139
],
137140
data = [
138141
"@lowrisc_opentitan//sw/host/opentitantool",
@@ -202,6 +205,47 @@ py_binary(
202205
}),
203206
)
204207

208+
py_binary(
209+
name = "sca_sha3_test",
210+
srcs = ["test_scripts/sca_sha3_test.py"],
211+
testonly = True,
212+
deps = [
213+
":sca_sha3_functions",
214+
"//communication:dut",
215+
"//communication:chip",
216+
"//communication:sca_sha3_commands",
217+
"//test/penetrationtests/util:utils",
218+
"@rules_python//python/runfiles",
219+
requirement("pycryptodome"),
220+
],
221+
data = [
222+
"@lowrisc_opentitan//sw/host/opentitantool",
223+
] +
224+
select({
225+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_silicon_owner_gb_rom_ext": [
226+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_silicon_owner_gb_rom_ext",
227+
],
228+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_fpga_cw310_rom_with_fake_keys": [
229+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_fpga_cw310_rom_with_fake_keys",
230+
],
231+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_fpga_cw310_sival_rom_ext": [
232+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_fpga_cw310_sival_rom_ext",
233+
],
234+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_fpga_cw310_test_rom": [
235+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_fpga_cw310_test_rom",
236+
],
237+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_silicon_owner_a2_rom_ext": [
238+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_silicon_owner_a2_rom_ext",
239+
],
240+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_silicon_owner_sival_rom_ext": [
241+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_silicon_owner_sival_rom_ext",
242+
],
243+
"//conditions:default": [
244+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_sca_silicon_owner_gb_rom_ext",
245+
],
246+
}),
247+
)
248+
205249
py_library(
206250
name = "sca_ibex_functions",
207251
srcs = ["host_scripts/sca_ibex_functions.py"],
@@ -223,7 +267,6 @@ py_library(
223267
"//communication:sca_prng_commands",
224268
"//communication:sca_trigger_commands",
225269
"//communication:data_generator",
226-
requirement("pycryptodome"),
227270
],
228271
)
229272

@@ -236,7 +279,6 @@ py_library(
236279
"//communication:sca_hmac_commands",
237280
"//communication:sca_prng_commands",
238281
"//communication:sca_trigger_commands",
239-
requirement("pycryptodome"),
240282
],
241283
)
242284

@@ -249,7 +291,6 @@ py_library(
249291
"//communication:sca_kmac_commands",
250292
"//communication:sca_prng_commands",
251293
"//communication:sca_trigger_commands",
252-
requirement("pycryptodome"),
253294
],
254295
)
255296

@@ -261,4 +302,16 @@ py_library(
261302
"//communication:chip",
262303
"//communication:sca_otbn_commands",
263304
],
305+
)
306+
307+
py_library(
308+
name = "sca_sha3_functions",
309+
srcs = ["host_scripts/sca_sha3_functions.py"],
310+
deps = [
311+
"//communication:dut",
312+
"//communication:chip",
313+
"//communication:sca_prng_commands",
314+
"//communication:sca_trigger_commands",
315+
"//communication:sca_sha3_commands",
316+
],
264317
)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from communication.sca_sha3_commands import OTSHA3
2+
from communication.sca_prng_commands import OTPRNG
3+
from communication.sca_trigger_commands import OTTRIGGER
4+
from communication.chip import *
5+
from communication.dut import DUT
6+
import time
7+
import random
8+
9+
def char_sha3_single_absorb(opentitantool, iterations, masking, text):
10+
target = DUT()
11+
reset_target(opentitantool)
12+
# Clear the output from the reset
13+
target.dump_all()
14+
15+
sha3sca = OTSHA3(target, "ujson")
16+
# Initialize our chip and catch its output
17+
device_id, owner_page, boot_log, boot_measurements, version = sha3sca.init(0)
18+
19+
if masking:
20+
lfsr_seed = [0, 1, 2, 3]
21+
sha3sca.write_lfsr_seed(lfsr_seed)
22+
else:
23+
sha3sca.set_mask_off()
24+
25+
# Set the trigger
26+
triggersca = OTTRIGGER(target, "ujson")
27+
triggersca.select_trigger(0)
28+
29+
for _ in range(iterations):
30+
sha3sca.absorb(text, len(text))
31+
response = target.read_response()
32+
return response
33+
34+
def char_sha3_batch_absorb(opentitantool, iterations, num_segments, masking, text):
35+
target = DUT()
36+
reset_target(opentitantool)
37+
# Clear the output from the reset
38+
target.dump_all()
39+
40+
sha3sca = OTSHA3(target, "ujson")
41+
# Initialize our chip and catch its output
42+
device_id, owner_page, boot_log, boot_measurements, version = sha3sca.init(0)
43+
44+
if masking:
45+
lfsr_seed = [0, 1, 2, 3]
46+
sha3sca.write_lfsr_seed(lfsr_seed)
47+
else:
48+
sha3sca.set_mask_off()
49+
50+
# Set the internal prng
51+
ot_prng = OTPRNG(target=target, protocol="ujson")
52+
ot_prng.seed_prng([1,0,0,0])
53+
54+
# Set the trigger
55+
triggersca = OTTRIGGER(target, "ujson")
56+
triggersca.select_trigger(0)
57+
58+
sha3sca.fvsr_fixed_msg_set(text, len(text))
59+
60+
for _ in range(iterations):
61+
sha3sca.absorb_batch(num_segments)
62+
response = target.read_response()
63+
return response
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
from test.penetrationtests.sca.host_scripts.sca_sha3_functions import *
2+
from communication.sca_sha3_commands import OTSHA3
3+
from python.runfiles import Runfiles
4+
from communication.chip import *
5+
from test.penetrationtests.util.utils import *
6+
import os
7+
import json
8+
import random
9+
from Crypto.Hash import SHA3_256
10+
11+
12+
ignored_keys_set = set([])
13+
14+
def reset_test(opentitantool, target):
15+
reset_target(opentitantool)
16+
while True:
17+
read_line = str(target.readline().decode().strip())
18+
if len(read_line) > 0:
19+
if "firmware_sca.c" in read_line:
20+
return True
21+
else:
22+
return False
23+
24+
25+
def init_test(opentitantool, target):
26+
sha3sca = OTSHA3(target, "ujson")
27+
device_id, owner_page, boot_log, boot_measurements, version = sha3sca.init(0)
28+
device_id_json = json.loads(device_id)
29+
owner_page_json = json.loads(owner_page)
30+
boot_log_json = json.loads(boot_log)
31+
boot_measurements_json = json.loads(boot_measurements)
32+
33+
expected_device_id_keys = {
34+
"device_id",
35+
"rom_digest",
36+
"icache_en",
37+
"dummy_instr_en",
38+
"clock_jitter_locked",
39+
"clock_jitter_en",
40+
"sram_main_readback_locked",
41+
"sram_main_readback_en",
42+
"sram_ret_readback_locked",
43+
"sram_ret_readback_en"
44+
}
45+
actual_device_id_keys = set(device_id_json.keys())
46+
47+
if not actual_device_id_keys == expected_device_id_keys:
48+
print("device_id keys do not match the expected set.")
49+
print(f"Expected: {expected_device_id_keys}")
50+
print(f"Actual: {actual_device_id_keys}")
51+
return False
52+
53+
expected_owner_page_keys = {
54+
"config_version",
55+
"sram_exec_mode",
56+
"ownership_key_alg",
57+
"update_mode",
58+
"min_security_version_bl0",
59+
"lock_constraint"
60+
}
61+
actual_owner_page_keys = set(owner_page_json.keys())
62+
if not expected_owner_page_keys == actual_owner_page_keys:
63+
print("owner_page keys do not match the expected set.")
64+
print(f"Expected: {expected_owner_page_keys}")
65+
print(f"Actual: {actual_owner_page_keys}")
66+
return False
67+
68+
expected_boot_log_keys = {
69+
"digest",
70+
"identifier",
71+
"scm_revision_low",
72+
"scm_revision_high",
73+
"rom_ext_slot",
74+
"rom_ext_major",
75+
"rom_ext_minor",
76+
"rom_ext_size",
77+
"bl0_slot",
78+
"ownership_state",
79+
"ownership_transfers",
80+
"rom_ext_min_sec_ver",
81+
"bl0_min_sec_ver",
82+
"primary_bl0_slot",
83+
"retention_ram_initialized"
84+
}
85+
actual_boot_log_keys = set(boot_log_json.keys())
86+
if not expected_boot_log_keys == actual_boot_log_keys:
87+
print("boot_log keys do not match the expected set.")
88+
print(f"Expected: {expected_boot_log_keys}")
89+
print(f"Actual: {actual_boot_log_keys}")
90+
return False
91+
92+
expected_boot_measurements_keys = {
93+
"bl0",
94+
"rom_ext"
95+
}
96+
actual_boot_measurements_keys = set(boot_measurements_json.keys())
97+
if not expected_boot_measurements_keys == actual_boot_measurements_keys:
98+
print("boot_measurements keys do not match the expected set.")
99+
print(f"Expected: {expected_boot_measurements_keys}")
100+
print(f"Actual: {actual_boot_measurements_keys}")
101+
return False
102+
103+
if "PENTEST" not in version:
104+
print("Did not receive a PENTEST version.")
105+
print(f"Actual: {version}")
106+
return False
107+
108+
return True
109+
110+
def char_sha3_single_absorb_test(opentitantool_path, iterations):
111+
text = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
112+
masking = True
113+
actual_result = char_sha3_single_absorb(opentitantool_path, iterations, masking, text)
114+
try:
115+
actual_result_json = json.loads(actual_result)
116+
except:
117+
print("char_sha3_single_absorb gave an unexpected result")
118+
print(f"Actual: {actual_result}")
119+
return False
120+
121+
mac = SHA3_256.new()
122+
mac.update(bytes(text))
123+
tag = bytearray(mac.digest())
124+
expected_result = [x for x in tag]
125+
126+
expected_result_json = {
127+
"batch_digest": expected_result,
128+
}
129+
if not compare_json_data(actual_result_json, expected_result_json, ignored_keys_set):
130+
print("char_sha3_single_absorb failed")
131+
print(f"Expected: {expected_result_json}")
132+
print(f"Actual: {actual_result_json}")
133+
print("")
134+
return False
135+
return True
136+
137+
def char_sha3_batch_absorb_test(opentitantool_path, iterations, num_segments):
138+
text = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
139+
masking = True
140+
actual_result = char_sha3_batch_absorb(opentitantool_path, iterations, num_segments, masking, text)
141+
try:
142+
actual_result_json = json.loads(actual_result)
143+
except:
144+
print("char_sha3_batch_absorb gave an unexpected result")
145+
print(f"Actual: {actual_result}")
146+
return False
147+
148+
# Seed the synchronized randomness with the same seed as in the chip which is 1
149+
random.seed(1)
150+
151+
# Generate the batch data
152+
sample_fixed = 0
153+
for _ in range(iterations):
154+
xor_tag = [0 for _ in range(32)]
155+
for __ in range(num_segments):
156+
if sample_fixed == 1:
157+
batch_data = text
158+
else:
159+
batch_data = [random.randint(0, 255) for _ in range(16)]
160+
dummy = [random.randint(0, 255) for _ in range(16)]
161+
sample_fixed = dummy[0] & 0x1
162+
mac = SHA3_256.new()
163+
mac.update(bytes(batch_data))
164+
tag = [x for x in bytearray(mac.digest())]
165+
xor_tag = [xor_tag[i] ^ tag[i] for i in range(32)]
166+
167+
expected_result_json = {
168+
"batch_digest": xor_tag,
169+
}
170+
if not compare_json_data(actual_result_json, expected_result_json, ignored_keys_set):
171+
print("char_sha3_batch_absorb failed")
172+
print(f"Expected: {expected_result_json}")
173+
print(f"Actual: {actual_result_json}")
174+
print("")
175+
return False
176+
return True
177+
178+
def main():
179+
r = Runfiles.Create()
180+
opentitantool_path = r.Rlocation("lowrisc_opentitan/sw/host/opentitantool/opentitantool")
181+
182+
firmware_target_name = os.environ.get("SELECTED_FIRMWARE_TARGET", "pen_test_sca_silicon_owner_gb_rom_ext")
183+
firmware_path = r.Rlocation(f"lowrisc_opentitan/sw/device/tests/penetrationtests/firmware/{firmware_target_name}.img")
184+
185+
target = DUT()
186+
187+
flash_target(opentitantool_path, firmware_path)
188+
target.dump_all()
189+
190+
if not reset_test(opentitantool_path, target):
191+
print("Reset test failure")
192+
return False
193+
194+
if not init_test(opentitantool_path, target):
195+
print("Init test failure")
196+
return False
197+
198+
iterations = 10
199+
num_segments_list = [1, 2, 5, 10, 12, 50]
200+
201+
char_sha3_single_absorb_test(opentitantool_path, iterations)
202+
for num_segments in num_segments_list:
203+
char_sha3_batch_absorb_test(opentitantool_path, iterations, num_segments)
204+
205+
print("Testing finished")
206+
return True
207+
208+
if __name__ == "__main__":
209+
main()

0 commit comments

Comments
 (0)