Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize OTFI #371

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 33 additions & 163 deletions target/communication/fi_crypto_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,178 +5,48 @@

Communication with OpenTitan happens over the uJSON command interface.
"""
import copy
import json
import time
from typing import Optional


class OTFICrypto:
def __init__(self, target) -> None:
self.target = target

def _ujson_crypto_cmd(self) -> None:
time.sleep(0.01)
self.target.write(json.dumps("CryptoFi").encode("ascii"))
time.sleep(0.01)

def init(self) -> None:
""" Initialize the Crypto FI code on the chip.
Returns:
The device ID of the device.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Init command.
time.sleep(0.01)
self.target.write(json.dumps("Init").encode("ascii"))
# Read back device ID from device.
return self.read_response(max_tries=30)

def crypto_shadow_reg_access(self) -> None:
""" Starts the crypto.fi.shadow_reg_access test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# ShadowRegAccess command.
time.sleep(0.01)
self.target.write(json.dumps("ShadowRegAccess").encode("ascii"))

def crypto_aes_key(self) -> None:
""" Starts the crypto.fi.aes_key test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Aes command.
time.sleep(0.01)
self.target.write(json.dumps("Aes").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": True, "plaintext_trigger": False,
"encrypt_trigger": False, "ciphertext_trigger": False}
self.target.write(json.dumps(mode).encode("ascii"))

def crypto_aes_plaintext(self) -> None:
""" Starts the crypto.fi.aes_plaintext test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Aes command.
time.sleep(0.01)
self.target.write(json.dumps("Aes").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": False, "plaintext_trigger": True,
"encrypt_trigger": False, "ciphertext_trigger": False}
self.target.write(json.dumps(mode).encode("ascii"))
from target.communication.otfi import OTFI
from target.communication.otfi_test import OTFITest

def crypto_aes_encrypt(self) -> None:
""" Starts the crypto.fi.aes_encrypt test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Aes command.
time.sleep(0.01)
self.target.write(json.dumps("Aes").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": False, "plaintext_trigger": False,
"encrypt_trigger": True, "ciphertext_trigger": False}
self.target.write(json.dumps(mode).encode("ascii"))

def crypto_aes_ciphertext(self) -> None:
""" Starts the crypto.fi.aes_ciphertext test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Aes command.
time.sleep(0.01)
self.target.write(json.dumps("Aes").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": False, "plaintext_trigger": False,
"encrypt_trigger": False, "ciphertext_trigger": True}
self.target.write(json.dumps(mode).encode("ascii"))
MODES = {
"aes": {
"key_trigger": False, "plaintext_trigger": False,
"encrypt_trigger": False, "ciphertext_trigger": False
},
"kmac": {
"key_trigger": False, "absorb_trigger": False,
"static_trigger": False, "squeeze_trigger": False
},
}

def crypto_kmac_key(self) -> None:
""" Starts the crypto.fi.kmac_key test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Kmac command.
time.sleep(0.01)
self.target.write(json.dumps("Kmac").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": True, "absorb_trigger": False,
"static_trigger": False, "squeeze_trigger": False}
self.target.write(json.dumps(mode).encode("ascii"))

def crypto_kmac_absorb(self) -> None:
""" Starts the crypto.fi.kmac_absorb test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Kmac command.
time.sleep(0.01)
self.target.write(json.dumps("Kmac").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": False, "absorb_trigger": True,
"static_trigger": False, "squeeze_trigger": False}
self.target.write(json.dumps(mode).encode("ascii"))
def _get_mode(ip, mode_id):
assert ip in MODES, f"IP {ip} not in MODES ({MODES})"
mode = copy.deepcopy(MODES[ip])
assert mode_id in mode, f"Mode id {mode_id} not in {ip} mode ({mode})"
mode[mode_id] = True
return mode

def crypto_kmac_squeeze(self) -> None:
""" Starts the crypto.fi.kmac_squeeze test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Kmac command.
time.sleep(0.01)
self.target.write(json.dumps("Kmac").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": False, "absorb_trigger": False,
"static_trigger": False, "squeeze_trigger": True}
self.target.write(json.dumps(mode).encode("ascii"))

def crypto_kmac_static(self) -> None:
""" Starts the crypto.fi.kmac_static test.
"""
# CryptoFi command.
self._ujson_crypto_cmd()
# Kmac command.
time.sleep(0.01)
self.target.write(json.dumps("Kmac").encode("ascii"))
# Mode payload.
time.sleep(0.01)
mode = {"key_trigger": False, "absorb_trigger": False,
"static_trigger": True, "squeeze_trigger": False}
self.target.write(json.dumps(mode).encode("ascii"))
class OTFICrypto(OTFI):
TESTS = [
OTFITest("shadow_reg_access"),
OTFITest("aes_key", "Aes", _get_mode("aes", "key_trigger")),
OTFITest("aes_plaintext", "Aes", _get_mode("aes", "plaintext_trigger")),
OTFITest("aes_encrypt", "Aes", _get_mode("aes", "encrypt_trigger")),
OTFITest("aes_ciphertext", "Aes", _get_mode("aes", "ciphertext_trigger")),
OTFITest("kmac_key", "Kmac", _get_mode("kmac", "key_trigger")),
OTFITest("kmac_absorb", "Kmac", _get_mode("kmac", "absorb_trigger")),
OTFITest("kmac_static", "Kmac", _get_mode("kmac", "static_trigger")),
OTFITest("kmac_squeeze", "Kmac", _get_mode("kmac", "squeeze_trigger")),
]

def start_test(self, cfg: dict) -> None:
""" Start the selected test.

Call the function selected in the config file. Uses the getattr()
construct to call the function.

Args:
cfg: Config dict containing the selected test.
"""
test_function = getattr(self, cfg["test"]["which_test"])
test_function()

def read_response(self, max_tries: Optional[int] = 1) -> str:
""" Read response from Crypto FI 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 ""
def __init__(self, target) -> None:
super().__init__(target, "Crypto")
Loading