diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD index 0d73a233bb5022..e2812f59f78e3a 100644 --- a/sw/device/tests/BUILD +++ b/sw/device/tests/BUILD @@ -6279,3 +6279,61 @@ opentitan_test( "//sw/device/lib/testing/test_framework:ottf_utils", ], ) + +opentitan_test( + name = "aes_force_prng_reseed_test", + srcs = ["aes_force_prng_reseed_test.c"], + verilator = verilator_params( + timeout = "long", + ), + exec_env = dicts.add( + { + "//hw/top_earlgrey:sim_verilator": None, + "//hw/top_earlgrey:fpga_cw340_sival": None, + }, + ), + deps = [ + "//hw/ip/aes:model", + "//hw/top_earlgrey/sw/autogen:top_earlgrey", + "//sw/device/lib/base:memory", + "//sw/device/lib/base:mmio", + "//sw/device/lib/dif:aes", + "//sw/device/lib/dif:edn", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:aes_testutils", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/lib/dif:entropy_src", + "//sw/device/lib/testing:entropy_testutils", + "//sw/device/sca/lib:simple_serial", + ], +) + +opentitan_test( + name = "aes_prng_reseed_test", + srcs = ["aes_prng_reseed_test.c"], + verilator = verilator_params( + timeout = "long", + ), + exec_env = dicts.add( + { + "//hw/top_earlgrey:sim_verilator": None, + "//hw/top_earlgrey:fpga_cw340_sival": None, + }, + ), + deps = [ + "//hw/ip/aes:model", + "//hw/top_earlgrey/sw/autogen:top_earlgrey", + "//sw/device/lib/base:memory", + "//sw/device/lib/base:mmio", + "//sw/device/lib/dif:aes", + "//sw/device/lib/dif:edn", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:aes_testutils", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/lib/dif:entropy_src", + "//sw/device/lib/testing:entropy_testutils", + "//sw/device/lib/testing/test_framework:check", + "//sw/device/lib/testing/test_framework:ottf_utils", + "//sw/device/sca/lib:simple_serial", + ], +) diff --git a/sw/device/tests/aes_force_prng_reseed_test.c b/sw/device/tests/aes_force_prng_reseed_test.c new file mode 100644 index 00000000000000..1489c003436793 --- /dev/null +++ b/sw/device/tests/aes_force_prng_reseed_test.c @@ -0,0 +1,274 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/lib/base/bitfield.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/base/multibits.h" +#include "sw/device/lib/dif/dif_aes.h" +#include "sw/device/lib/dif/dif_csrng.h" +#include "sw/device/lib/dif/dif_csrng_shared.h" +#include "sw/device/lib/dif/dif_edn.h" +#include "sw/device/lib/dif/dif_entropy_src.h" +#include "sw/device/lib/runtime/hart.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/aes_testutils.h" +#include "sw/device/lib/testing/csrng_testutils.h" +#include "sw/device/lib/testing/entropy_testutils.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/sca/lib/simple_serial.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" + +OTTF_DEFINE_TEST_CONFIG(); + +enum { + kTestTimeout = 1000 * 1000, // Timeout for waiting for AES operations +}; + +static dif_aes_t aes; +static dif_edn_t edn0, edn1; +static dif_csrng_t csrng; +static dif_entropy_src_t entropy_src; + +// Function to fetch and log CSRNG internal state +static void log_csrng_internal_state(const dif_csrng_t *csrng) { + dif_csrng_internal_state_t csrng_state; + dif_csrng_internal_state_id_t instance_id = kCsrngInternalStateIdSw; + + CHECK_DIF_OK(dif_csrng_get_internal_state(csrng, instance_id, &csrng_state)); + + LOG_INFO("CSRNG internal state: 0x%x", csrng_state); +} + +void monitor_entropy_sources(void) { + // EDN status monitoring + bool edn_status0, edn_status1; + CHECK_DIF_OK(dif_edn_get_status(&edn0, kDifEdnStatusReady, &edn_status0)); + CHECK_DIF_OK(dif_edn_get_status(&edn1, kDifEdnStatusReady, &edn_status1)); + LOG_INFO("EDN0 status: 0x%x", edn_status0); + LOG_INFO("EDN1 status: 0x%x", edn_status1); +} + +// Function to check the status of EDN +static void monitor_edn_status(const dif_edn_t *edn0, const dif_edn_t *edn1) { + bool edn_status0, edn_status1; + + // Check EDN0 status using kDifEdnStatusReady flag + CHECK_DIF_OK(dif_edn_get_status(edn0, kDifEdnStatusReady, &edn_status0)); + LOG_INFO("EDN0 status (Ready): 0x%x", edn_status0); + + // Check EDN1 status using kDifEdnStatusReady flag + CHECK_DIF_OK(dif_edn_get_status(edn1, kDifEdnStatusReady, &edn_status1)); + LOG_INFO("EDN1 status (Ready): 0x%x", edn_status1); +} + +// AES key used for the test +static const unsigned char kAesModesKey128[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; + +static const unsigned char kAesModesPlainText[16] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, +}; + +static const unsigned char kAesModesCipherTextEcb128[16] = { + 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, + 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97}; + +/* +The mask share, used to mask kKey. Note that the masking should not be done +manually. Software is expected to get the key in two shares right from the +beginning. +*/ +static const uint8_t kKeyShare1[] = { + 0x0f, 0x1f, 0x2f, 0x3F, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf, + 0xbf, 0xcf, 0xdf, 0xef, 0xff, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, + 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, +}; + +// Function to print AES blocks key and data +static void aes_print_block(const unsigned char *data, const int num_bytes) { + for (int i = 0; i < num_bytes; i++) { + LOG_INFO("%02x ", data[i]); + } + LOG_INFO(""); +} + +status_t disable_entropy_complex(void) { + // Use the entropy test utility to stop all EDN0, EDN1, CSRNG, and the Entropy + // Source + TRY(entropy_testutils_stop_all()); + LOG_INFO("The entire entropy complex is stopped"); + return OK_STATUS(); +} + +status_t enable_entropy_complex(void) { + // Use the entropy test utility to enable all EDN0, EDN1, CSRNG, and the + // Entropy Source + TRY(entropy_testutils_auto_mode_init()); + LOG_INFO("The entire entropy complex is enabled"); + return OK_STATUS(); +} + +status_t execute_test(void) { + // Initialize AES, EDN, CSRNG, and Entropy Source + + // Initialize all modules + LOG_INFO("Initializing AES unit."); + CHECK_DIF_OK( + dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes)); + CHECK_DIF_OK(dif_aes_reset(&aes)); + LOG_INFO("Module initialized: AES"); + LOG_INFO("Starting AES PRNG reseed stall test..."); + CHECK_DIF_OK( + dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0)); + CHECK_DIF_OK( + dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1)); + CHECK_DIF_OK(dif_csrng_init( + mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR), &csrng)); + CHECK_DIF_OK(dif_entropy_src_init( + mmio_region_from_addr(TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR), &entropy_src)); + LOG_INFO("Modules initialized: EDN0, EDN1, CSRNG, Entropy Source"); + + // Configure AES for ECB mode, 128-bit key, and manual operation + dif_aes_transaction_t transaction = { + .operation = kDifAesOperationEncrypt, + .mode = kDifAesModeEcb, + .key_len = kDifAesKey128, + .key_provider = kDifAesKeySoftwareProvided, + .mask_reseeding = kDifAesReseedPerBlock, + .manual_operation = kDifAesManualOperationManual, + .reseed_on_key_change = true, + .force_masks = false, + .ctrl_aux_lock = false, + }; + + LOG_INFO( + "AES transaction configured: ECB mode, 128-bit key, manual operation."); + + // Disable EDN and CSRNG to simulate stalling + LOG_INFO( + "Disabling entropy complex- EDN0, EDN1, CSRNG, and the Entropy Source " + "..."); + disable_entropy_complex(); + busy_spin_micros(500); + + // Expanding aes_testutils_setup_encryption T1 to T8: + // T: Start of aes_testutils_setup_encryption function steps + // T1: Mask the key. Note that this should not be done manually. Software is + // expected to get the key in two shares right from the beginning. + uint8_t key_share0[sizeof(kAesModesKey128)]; + for (int i = 0; i < sizeof(kAesModesKey128); ++i) { + key_share0[i] = kAesModesKey128[i] ^ kKeyShare1[i]; + } + + // T2: "Convert" key share byte arrays to `dif_aes_key_share_t`. + dif_aes_key_share_t key; + memcpy(key.share0, key_share0, sizeof(key.share0)); + memcpy(key.share1, kKeyShare1, sizeof(key.share1)); + + // T3: Wait for status kDifAesStatusIdle + // Start AES with the given transaction + AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, true, kTestTimeout); + + // T4: dif_aes_start + CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL)); + + // Trigger PRNG reseed for the first key + CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed)); + + // Generate the second key key2 by slightly modifying the first key to ensure + // difference (adding 1) Declare second key shares (ensure it's a new + // declaration) + uint8_t key2_share0[sizeof(kAesModesKey128)]; + + // Generate the second key by modifying the first key (to ensure it’s + // different) + for (int i = 0; i < sizeof(kAesModesKey128); ++i) { + key2_share0[i] = (kAesModesKey128[i] ^ kKeyShare1[i]) + 1; + } + + // Load the second key + dif_aes_key_share_t key2; + memcpy(key2.share0, key2_share0, sizeof(key2_share0)); + memcpy(key2.share1, kKeyShare1, sizeof(key2.share1)); + + LOG_INFO("Conditionally checking AES status after stopping EDN and CSRNG."); + LOG_INFO("Waiting for AES to stall after PRNG reseed request..."); + bool stall = false; + CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusStall, &stall)); + + if (stall) { + LOG_INFO("AES encryption has stalled as expected."); + } else { + LOG_ERROR( + "ERROR:AES encryption did not stall as expected after EDN stop! Lets " + "proceed " + "for now to verify further steps..."); + } + + log_csrng_internal_state(&csrng); + monitor_entropy_sources(); + + LOG_INFO( + "Enabling entropy complex- EDN0, EDN1, CSRNG, and the Entropy Source " + "..."); + enable_entropy_complex(); + monitor_edn_status(&edn0, &edn1); + + // Trigger PRNG reseed request + LOG_INFO("Triggering PRNG reseed..."); + CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed)); + + // T5: "Convert" plain data byte arrays to `dif_aes_data_t` + dif_aes_data_t in_data_plain; + memcpy(in_data_plain.data, kAesModesPlainText, sizeof(in_data_plain.data)); + + // T6: Wait ofr Status kDifAesStatusIdle + LOG_INFO( + "Now Starting AES encryption process firstly by observing if AES is in " + "Idle state"); + AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, true, kTestTimeout); + + // T7: Wait for Status input DifAesStatusInputReady + LOG_INFO("AES started: ECB encryption, waiting for input ready."); + AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusInputReady, true, + kTestTimeout); + // T8: Load the plain text to trigger the encryption operation + CHECK_DIF_OK(dif_aes_load_data(&aes, in_data_plain)); + + // Load the second key into AES (key2) + CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key2, NULL)); + + // Trigger AES reseed request, specific for manual operation case + LOG_INFO("AES encryption started."); + CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerStart)); + + busy_spin_micros(500); + + // LOG_INFO("Setting EDN to auto mode..."); + // TRY(entropy_testutils_auto_mode_init()); + //// CHECK_DIF_OK(entropy_testutils_auto_mode_init()); + // monitor_edn_status(&edn0, &edn1); + + // Read out the produced cipher text. + dif_aes_data_t out_data; + LOG_INFO("AES dif_aes_read_output:"); + CHECK_DIF_OK(dif_aes_read_output(&aes, &out_data)); + + LOG_INFO("Encrypted text:"); + aes_print_block((const unsigned char *)out_data.data, 16); + + // Finish the ECB encryption transaction. + CHECK_DIF_OK(dif_aes_end(&aes)); + LOG_INFO("AES comparison out_data with CipherText:"); + CHECK_ARRAYS_EQ((uint8_t *)out_data.data, kAesModesCipherTextEcb128, + sizeof(out_data.data)); + + return OK_STATUS(); +} + +bool test_main(void) { return status_ok(execute_test()); } diff --git a/sw/device/tests/aes_prng_reseed_test.c b/sw/device/tests/aes_prng_reseed_test.c new file mode 100644 index 00000000000000..851bb029ea5cb6 --- /dev/null +++ b/sw/device/tests/aes_prng_reseed_test.c @@ -0,0 +1,382 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "hw/ip/aes/model/aes_modes.h" +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/base/multibits.h" +#include "sw/device/lib/dif/dif_aes.h" +#include "sw/device/lib/dif/dif_csrng.h" +#include "sw/device/lib/dif/dif_csrng_shared.h" +#include "sw/device/lib/dif/dif_edn.h" +#include "sw/device/lib/dif/dif_entropy_src.h" +#include "sw/device/lib/runtime/hart.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/aes_testutils.h" +#include "sw/device/lib/testing/csrng_testutils.h" +#include "sw/device/lib/testing/entropy_testutils.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/sca/lib/simple_serial.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" + +OTTF_DEFINE_TEST_CONFIG(); + +enum { + kTestTimeout = (1000 * 1000), +}; + +static dif_aes_t aes; +static dif_edn_t edn0, edn1; +static dif_csrng_t csrng; +static dif_entropy_src_t entropy_src; + +// Function to fetch and log CSRNG internal state +static void log_csrng_internal_state(const dif_csrng_t *csrng) { + dif_csrng_internal_state_t csrng_state; + dif_csrng_internal_state_id_t instance_id = kCsrngInternalStateIdSw; + + CHECK_DIF_OK(dif_csrng_get_internal_state(csrng, instance_id, &csrng_state)); + + LOG_INFO("CSRNG internal state: 0x%x", csrng_state); +} + +void monitor_entropy_sources(void) { + // EDN status monitoring + bool edn_status0, edn_status1; + CHECK_DIF_OK(dif_edn_get_status(&edn0, kDifEdnStatusReady, &edn_status0)); + CHECK_DIF_OK(dif_edn_get_status(&edn1, kDifEdnStatusReady, &edn_status1)); + LOG_INFO("EDN0 status: 0x%x", edn_status0); + LOG_INFO("EDN1 status: 0x%x", edn_status1); +} + +// Function to check the status of EDN +static void monitor_edn_status(const dif_edn_t *edn0, const dif_edn_t *edn1) { + bool edn_status0, edn_status1; + + // Check EDN0 status using kDifEdnStatusReady flag + CHECK_DIF_OK(dif_edn_get_status(edn0, kDifEdnStatusReady, &edn_status0)); + LOG_INFO("EDN0 status (Ready): 0x%x", edn_status0); + + // Check EDN1 status using kDifEdnStatusReady flag + CHECK_DIF_OK(dif_edn_get_status(edn1, kDifEdnStatusReady, &edn_status1)); + LOG_INFO("EDN1 status (Ready): 0x%x", edn_status1); +} + +// The mask share, used to mask kKey. Note that the masking should not be done +// manually. Software is expected to get the key in two shares right from the +// beginning. + +static const unsigned char kAesModesPlainText_block12[32] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, + 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, + 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, +}; + +static const unsigned char kAesModesPlainText_block34[32] = { + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, + 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, + 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}; + +static const uint8_t kKeyShare1[] = { + 0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf, + 0xbf, 0xcf, 0xdf, 0xef, 0xff, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, + 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, +}; + +static void monitor_aes_registers(const dif_aes_t *aes) { + bool idle, stalled, input_ready, output_valid, output_lost, alert_fatal_fault, + alert_recoverable_err; + + // Check AES idle status + CHECK_DIF_OK(dif_aes_get_status(aes, kDifAesStatusIdle, &idle)); + LOG_INFO("AES idle status: %d", idle); + + // Check AES stall status + CHECK_DIF_OK(dif_aes_get_status(aes, kDifAesStatusStall, &stalled)); + LOG_INFO("AES stall status: %d", stalled); + + // Check AES output lost status + CHECK_DIF_OK(dif_aes_get_status(aes, kDifAesStatusOutputLost, &output_lost)); + LOG_INFO("AES output lost status: %d", output_lost); + + // Check AES output valid status + CHECK_DIF_OK( + dif_aes_get_status(aes, kDifAesStatusOutputValid, &output_valid)); + LOG_INFO("AES output valid status: %d", output_valid); + + // Check AES input ready status + CHECK_DIF_OK(dif_aes_get_status(aes, kDifAesStatusInputReady, &input_ready)); + LOG_INFO("AES input ready status: %d", input_ready); + + // Check AES alert recoverable error status + CHECK_DIF_OK(dif_aes_get_status(aes, kDifAesStatusAlertRecovCtrlUpdateErr, + &alert_recoverable_err)); + LOG_INFO("AES alert recoverable control update error status: %d", + alert_recoverable_err); + + // Check AES alert fatal fault status + CHECK_DIF_OK(dif_aes_get_status(aes, kDifAesStatusAlertFatalFault, + &alert_fatal_fault)); + LOG_INFO("AES alert fatal fault status: %d", alert_fatal_fault); +} + +// Function to print AES blocks key and data +static void aes_print_block(const unsigned char *data, const int num_bytes) { + for (int i = 0; i < num_bytes; i++) { + LOG_INFO("%02x ", data[i]); + } + LOG_INFO(""); +} + +status_t disable_entropy_complex(void) { + // Use the entropy test utility to stop all EDN0, EDN1, CSRNG, and the Entropy + // Source + TRY(entropy_testutils_stop_all()); + LOG_INFO("The entire entropy complex is stopped"); + return OK_STATUS(); +} + +status_t enable_entropy_complex(void) { + // Use the entropy test utility to enable all EDN0, EDN1, CSRNG, and the + // Entropy Source + TRY(entropy_testutils_auto_mode_init()); + LOG_INFO("The entire entropy complex is enabled"); + return OK_STATUS(); +} + +status_t execute_test(void) { + // Initialize AES, EDN, CSRNG, and Entropy Source + + // Initialize all modules + LOG_INFO("Initializing AES unit."); + CHECK_DIF_OK( + dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes)); + CHECK_DIF_OK(dif_aes_reset(&aes)); + LOG_INFO("Module initialized: AES"); + LOG_INFO("Starting AES PRNG reseed stall test..."); + CHECK_DIF_OK( + dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0)); + CHECK_DIF_OK( + dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1)); + CHECK_DIF_OK(dif_csrng_init( + mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR), &csrng)); + CHECK_DIF_OK(dif_entropy_src_init( + mmio_region_from_addr(TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR), &entropy_src)); + LOG_INFO("Modules initialized: EDN0, EDN1, CSRNG, Entropy Source"); + + // Mask the key. Note that this should not be done manually. Software is + // expected to get the key in two shares right from the beginning. + + uint8_t key_share0[sizeof(kAesModesKey128)]; + for (int i = 0; i < sizeof(kAesModesKey128); ++i) { + key_share0[i] = kAesModesKey128[i] ^ kKeyShare1[i]; + } + + // "Convert" key share byte arrays to `dif_aes_key_share_t`. + dif_aes_key_share_t key; + memcpy(key.share0, key_share0, sizeof(key.share0)); + memcpy(key.share1, kKeyShare1, sizeof(key.share1)); + + // Write the initial key share, data in CSRs (known combinations). + + dif_aes_transaction_t transaction = { + .operation = kDifAesOperationEncrypt, + .mode = kDifAesModeEcb, + .key_len = kDifAesKey128, + .key_provider = kDifAesKeySoftwareProvided, + .mask_reseeding = kDifAesReseedPer64Block, + .manual_operation = kDifAesManualOperationAuto, + .reseed_on_key_change = true, + .force_masks = false, + .ctrl_aux_lock = false, + }; + + LOG_INFO("dif_aes_start1"); + CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL)); + LOG_INFO("monitor_aes_registers1"); + monitor_aes_registers(&aes); + + // "Convert" plain data byte arrays to `dif_aes_data_t` array. + enum { + kAesNumBlocks = 2, + }; + + dif_aes_data_t plain_text[kAesNumBlocks]; + dif_aes_data_t cipher_text[kAesNumBlocks]; + + memcpy(plain_text[0].data, kAesModesPlainText_block12, + sizeof(kAesModesPlainText_block12)); + + // Encrypt kAesNumBlocks blocks. + + CHECK_DIF_OK(dif_aes_process_data(&aes, plain_text, cipher_text, + (size_t)kAesNumBlocks)); + + CHECK_DIF_OK(dif_aes_load_data(&aes, plain_text[0])); + + LOG_INFO("Started AES Encrypt with load function"); + + bool ready = false; + + do { + CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusOutputValid, &ready)); + } while (!ready); + + // Trigger PRNG reseed for the first key + LOG_INFO("Triggering PRNG reseed 1..."); + CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed)); + + // Disable EDN and CSRNG to simulate stalling + LOG_INFO( + "Disabling entropy complex- EDN0, EDN1, CSRNG, and the Entropy Source " + "..."); + disable_entropy_complex(); + busy_spin_micros(500); + + LOG_INFO("monitor_aes_registers2"); + monitor_aes_registers(&aes); + + // Perform an trial encryption using a different data and key. Message size, + // key size and mode can be chosen arbitrarily. + + dif_aes_t aes2; + + LOG_INFO("aes2"); + CHECK_DIF_OK( + dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes2)); + + // Mask the key. Note that this should not be done manually. Software is + // expected to get the key in two shares right from the beginning. + + uint8_t key_share0_t[sizeof(kAesModesKey256)]; + for (int i = 0; i < sizeof(kAesModesKey256); ++i) { + key_share0_t[i] = kAesModesKey256[i] ^ kKeyShare1[i]; + } + + // "Convert" key share byte arrays to `dif_aes_key_share_t`. + dif_aes_key_share_t key_t; + memcpy(key_t.share0, key_share0_t, sizeof(key_t.share0)); + memcpy(key_t.share1, kKeyShare1, sizeof(key_t.share1)); + + dif_aes_transaction_t transaction_trial = { + .operation = kDifAesOperationEncrypt, + .mode = kDifAesModeEcb, + .key_len = kDifAesKey128, + .key_provider = kDifAesKeySoftwareProvided, + .mask_reseeding = kDifAesReseedPer64Block, + .manual_operation = kDifAesManualOperationAuto, + .reseed_on_key_change = false, + .ctrl_aux_lock = false, + }; + + LOG_INFO("monitor_aes_registers3"); + monitor_aes_registers(&aes); + + LOG_INFO("dif_aes_start2"); + CHECK_DIF_OK(dif_aes_start(&aes2, &transaction_trial, &key_t, NULL)); + + // "Convert" plain data byte arrays to `dif_aes_data_t` array. + enum { + kAesNumBlocks_t2 = 64, + }; + + dif_aes_data_t plain_text2[kAesNumBlocks_t2]; + dif_aes_data_t cipher_text2[kAesNumBlocks_t2]; + memcpy(plain_text2[0].data, kAesModesPlainText, sizeof(kAesModesPlainText)); + + CHECK_DIF_OK(dif_aes_process_data(&aes2, plain_text2, cipher_text2, + (size_t)kAesNumBlocks_t2)); + + CHECK_DIF_OK(dif_aes_load_data(&aes2, plain_text2[0])); + LOG_INFO("Started AES trial Encrypt"); + CHECK_DIF_OK(dif_aes_end(&aes2)); + + /** Not checking successful encryption here since its a trial transaction + * Trial encryption ends here + * Resume the Original Encryption below + */ + + transaction.manual_operation = kDifAesManualOperationAuto; + + CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL)); + + memcpy(plain_text[0].data, kAesModesPlainText_block34, + sizeof(kAesModesPlainText_block34)); + + CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusInputReady, &ready)); + LOG_INFO("Resuming Encrypt with the remaining 2 blocks of data "); + + LOG_INFO("monitor_aes_registers4"); + monitor_aes_registers(&aes); + + // Trigger PRNG reseed for the first key + LOG_INFO("Triggering PRNG reseed 2..."); + CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed)); + + LOG_INFO("dif_aes_process_data..."); + CHECK_DIF_OK(dif_aes_process_data(&aes, plain_text, cipher_text, + (size_t)kAesNumBlocks)); + LOG_INFO("dif_aes_load_data..."); + CHECK_DIF_OK(dif_aes_load_data(&aes, plain_text[0])); + + do { + CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusOutputValid, &ready)); + } while (!ready); + + // Decrypt operation below + + dif_aes_transaction_t transactiond = { + .operation = kDifAesOperationDecrypt, + .mode = kDifAesModeEcb, + .key_len = kDifAesKey128, + .key_provider = kDifAesKeySoftwareProvided, + .mask_reseeding = kDifAesReseedPer64Block, + .manual_operation = kDifAesManualOperationAuto, + .reseed_on_key_change = false, + .ctrl_aux_lock = false, + }; + + for (int i = 0; i < sizeof(kAesModesKey128); ++i) { + key_share0[i] = kAesModesKey128[i] ^ kKeyShare1[i]; + } + + // "Convert" key share byte arrays to `dif_aes_key_share_t`. + + memcpy(key.share0, key_share0, sizeof(key.share0)); + memcpy(key.share1, kKeyShare1, sizeof(key.share1)); + + do { + CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusInputReady, &ready)); + } while (!ready); + + CHECK_DIF_OK(dif_aes_start(&aes, &transactiond, &key, NULL)); + + memcpy(cipher_text[0].data, kAesModesCipherTextCbc128, + sizeof(cipher_text[0].data)); + + CHECK_DIF_OK(dif_aes_load_data(&aes, cipher_text[0])); + + do { + CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusOutputValid, &ready)); + } while (!ready); + + dif_aes_data_t out_data2; + CHECK_DIF_OK(dif_aes_read_output(&aes, &out_data2)); + CHECK_DIF_OK(dif_aes_end(&aes)); + // Finish the CBC decryption transaction. + + CHECK_ARRAYS_EQ((uint8_t *)out_data2.data, kAesModesPlainText, + sizeof(out_data2.data)); + LOG_INFO("Decryption Successful"); + + return OK_STATUS(); +} + +bool test_main(void) { + LOG_INFO("Entering AES Interrupt Encrypt Tests"); + + return status_ok(execute_test()); +}