From ada100f976107eb9c6193caca46e2a905ddee4b3 Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Fri, 14 Jun 2024 11:56:43 +0200 Subject: [PATCH] [sca] Add KeySideloadFvsr OTBN test This commit adds the following OTBN SCA routines to the code base: - init: Init the OTBN SCA test on the device - init_keymgr: Prepare the keymanager for the OTBN key sideloading test - key_sideload_fvsr: Start the test - read_response: Read response from device Signed-off-by: Pascal Nasahl --- capture/capture_otbn.py | 14 ++--- target/communication/sca_otbn_commands.py | 66 +++++++++++++++++++++-- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/capture/capture_otbn.py b/capture/capture_otbn.py index c399d498..25c848ba 100755 --- a/capture/capture_otbn.py +++ b/capture/capture_otbn.py @@ -21,7 +21,7 @@ from tqdm import tqdm import util.helpers as helpers -from target.communication.sca_otbn_commands import OTOTBNVERT +from target.communication.sca_otbn_commands import OTOTBN from target.communication.sca_trigger_commands import OTTRIGGER from target.targets import Target, TargetConfig from util import check_version @@ -194,7 +194,7 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OTBN. - ot_otbn_vert = OTOTBNVERT(target=target, protocol=capture_cfg.protocol) + ot_otbn_vert = OTOTBN(target=target, protocol=capture_cfg.protocol) # Create communication interface to SCA trigger. ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol) @@ -203,7 +203,7 @@ def establish_communication(target, capture_cfg: CaptureConfig): def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, - ot_otbn_vert) -> OTOTBNVERT: + ot_otbn_vert) -> OTOTBN: """ Configure the OTBN app. Establish communication with the OTBN keygen app and configure the seed. @@ -455,7 +455,7 @@ def generate_ref_crypto_modinv(cfg: dict, sample_fixed, curve_cfg: CurveConfig, return k_used, input_k0_used, input_k1_used, expected_output, sample_fixed -def check_ciphertext_keygen(ot_otbn_vert: OTOTBNVERT, expected_key, +def check_ciphertext_keygen(ot_otbn_vert: OTOTBN, expected_key, curve_cfg: CurveConfig): """ Compares the received with the generated key. @@ -492,7 +492,7 @@ def check_ciphertext_keygen(ot_otbn_vert: OTOTBNVERT, expected_key, return share0, share1 -def check_ciphertext_modinv(ot_otbn_vert: OTOTBNVERT, expected_output, +def check_ciphertext_modinv(ot_otbn_vert: OTOTBN, expected_output, curve_cfg: CurveConfig): """ Compares the received modular inverse output with the generated output. @@ -524,7 +524,7 @@ def check_ciphertext_modinv(ot_otbn_vert: OTOTBNVERT, expected_output, return actual_output -def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT, +def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, capture_cfg: CaptureConfig, curve_cfg: CurveConfig, project: SCAProject, target: Target): """ Capture power consumption during selected OTBN operation. @@ -602,7 +602,7 @@ def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT, pbar.update(capture_cfg.num_segments) -def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBNVERT, +def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, capture_cfg: CaptureConfig, curve_cfg: CurveConfig, project: SCAProject, target: Target): """ Capture power consumption during selected OTBN operation. diff --git a/target/communication/sca_otbn_commands.py b/target/communication/sca_otbn_commands.py index bf94ec2a..46d96fde 100644 --- a/target/communication/sca_otbn_commands.py +++ b/target/communication/sca_otbn_commands.py @@ -1,20 +1,64 @@ # Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -"""Communication interface for the SHA3 SCA application on OpenTitan. +"""Communication interface for the OTBN SCA application on OpenTitan. Communication with OpenTitan either happens over simpleserial or the uJson command interface. """ +import json +import time +from typing import Optional - -class OTOTBNVERT: +class OTOTBN: def __init__(self, target, protocol: str) -> None: self.target = target self.simple_serial = True if protocol == "ujson": self.simple_serial = False + def _ujson_otbn_sca_cmd(self): + # TODO: without the delay, the device uJSON command handler program + # does not recognize the commands. Tracked in issue #256. + time.sleep(0.01) + self.target.write(json.dumps("OtbnSca").encode("ascii")) + + def init(self): + """ Initializes OTBN on the target. + Returns: + The device ID of the device. + """ + if not self.simple_serial: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Init the OTBN core. + self.target.write(json.dumps("Init").encode("ascii")) + # Read back device ID from device. + return self.read_response(max_tries=30) + + def init_keymgr(self): + """ Initializes the key manager for OTBN on the target. + """ + if not self.simple_serial: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Init the key manager. + self.target.write(json.dumps("InitKeyMgr").encode("ascii")) + + def key_sideload_fvsr(self, seed: int): + """ Starts the key sidloading FvsR test on OTBN. + Args: + seed: The fixed seed used by the key manager. + """ + if not self.simple_serial: + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Start the KeySideloadFvsr test. + self.target.write(json.dumps("KeySideloadFvsr").encode("ascii")) + time.sleep(0.01) + seed_data = {"fixed_seed": seed} + self.target.write(json.dumps(seed_data).encode("ascii")) + def choose_otbn_app(self, app): """ Select the OTBN application. Args: @@ -105,3 +149,19 @@ def read_output(self, len_bytes): """ if self.simple_serial: return self.target.read("r", len_bytes, ack=False) + + def read_response(self, max_tries: Optional[int] = 1) -> str: + """ Read response from OTBN SCA framework. + Args: + max_tries: Maximum number of attempts to read from UART. + + Returns: + The JSON response of OpenTitan. + """ + it = 0 + while it != max_tries: + read_line = str(self.target.readline()) + if "RESP_OK" in read_line: + return read_line.split("RESP_OK:")[1].split(" CRC:")[0] + it += 1 + return "" \ No newline at end of file