Skip to content

Commit

Permalink
[sival/aes] Add aes_prng_reseed,aes_prng_force_reseed
Browse files Browse the repository at this point in the history
This commit introduces the AES PRNG reseed test and AES FORCE PRNG reseed, to handle the reseed process by disabling entrpy complex and triggering PRNG reseed accordingly. The tests follows procedure as per description mentioned in chip_aes_testplan.hjson:
aes_force_prng_reseed: https://github.com/github-gcontributor/opentitan/blob/master/hw/top_earlgrey/data/ip/chip_aes_testplan.hjson#L185
aes_prng_reseed: https://github.com/github-gcontributor/opentitan/blob/master/hw/top_earlgrey/data/ip/chip_aes_testplan.hjson#L145

Number of blocks set to 68 (4 more to see if tests auto generates reseed post 64Block)
Added aes_process_data() functoin to process first two blocks of data as
per test description
Remove the trigger prng reseed (Not required for Auto test)
Commenting out the enabling of the entropy complex at block 32 -- correct test procedure (Enable once entire 64 block of data is processed)
Do not generate new key while running the test (as per auto mode should do it on its own)
Enabling the entropy complex only after entire encryption process completes (after 68 blocks) -- correct procedure.
Remove code dif_aes_end, new_key_generation and dif_aes_start - incorrect logic for auto mode
Remove check for Stall signal bit set (remove Stall check logic from the code) -- as per correct procedure of the test
After entropy disabled, wait for output valid normally
Create CL for "Change of test case description-aes_prng_reseed_test" --> Ambiguity in interpreting encryption stalling with STALL register bit Created issue: #24857

Create CL for "Clarification needed on PRNG_RESEED_RATE PER_64 behavior in aes_prng_reseed_test" #24899

Signed-off-by: Varunkumar Trivedi <[email protected]>
  • Loading branch information
github-gcontributor committed Oct 31, 2024
1 parent 7fad7db commit befede4
Show file tree
Hide file tree
Showing 3 changed files with 523 additions and 0 deletions.
58 changes: 58 additions & 0 deletions sw/device/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,64 @@ opentitan_test(
],
)

opentitan_test(
name = "aes_force_prng_reseed_test",
srcs = ["aes_force_prng_reseed_test.c"],
exec_env = dicts.add(
{
"//hw/top_earlgrey:sim_verilator": None,
"//hw/top_earlgrey:fpga_cw340_sival": None,
},
),
verilator = verilator_params(
timeout = "long",
),
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/dif:entropy_src",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing:aes_testutils",
"//sw/device/lib/testing:entropy_testutils",
"//sw/device/lib/testing/test_framework:ottf_main",
"//sw/device/sca/lib:simple_serial",
],
)

opentitan_test(
name = "aes_prng_reseed_test",
srcs = ["aes_prng_reseed_test.c"],
exec_env = dicts.add(
{
"//hw/top_earlgrey:sim_verilator": None,
"//hw/top_earlgrey:fpga_cw340_sival": None,
},
),
verilator = verilator_params(
timeout = "long",
),
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/dif:entropy_src",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing:aes_testutils",
"//sw/device/lib/testing:entropy_testutils",
"//sw/device/lib/testing/test_framework:check",
"//sw/device/lib/testing/test_framework:ottf_main",
"//sw/device/lib/testing/test_framework:ottf_utils",
"//sw/device/sca/lib:simple_serial",
],
)

opentitan_test(
name = "alert_handler_ping_timeout_test",
srcs = ["alert_handler_ping_timeout_test.c"],
Expand Down
222 changes: 222 additions & 0 deletions sw/device/tests/aes_force_prng_reseed_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
// 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/dif/dif_rv_core_ibex.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/rv_core_ibex_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();

static dif_aes_t aes;
dif_aes_transaction_t transaction;
dif_aes_key_share_t key;
enum {
kAesNumBlocks = 8,
// NumBytes in one block is 4x8 i.e. 32 bits in 1 block
kDifAesBlockNumBytes = 4,
disable_entropy_at_start_en = 1,
};

static const uint8_t kKeyShare1[16] = {
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
};

///////////////////////////////////////////////////////////////////////////////
static dif_edn_t edn0, edn1;
static dif_csrng_t csrng;
static dif_entropy_src_t entropy_src;

// Function to disable entropy complex
status_t disable_entropy_complex(void) {
// Using 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();
}

// Function to enable entropy complex
status_t enable_entropy_complex(void) {
// Using 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();
}

// Function to generate a new key based on provided index value
void generate_new_key(dif_aes_key_share_t *key, int index) {
uint8_t new_key_share0[sizeof(kAesModesKey128)];
// Generate new key share0 by XOR-ing base key with kKeyShare1*index
for (size_t i = 0; i < sizeof(kAesModesKey128); ++i) {
new_key_share0[i] = kAesModesKey128[i] ^ kKeyShare1[i] * (uint8_t)(index);
}
// Update the key shares
memcpy(key->share0, new_key_share0, sizeof(key->share0));
memcpy(key->share1, kKeyShare1, sizeof(key->share1));
}

status_t execute_test(void) {
bool aes_idle = false;
bool input_ready = false;
bool output_valid = false;

LOG_INFO(
"Testing aes_prng_reseed_test with number of blocks: %d (Block 0 to %d), "
"and disabling entropy at start enable"
": %d",
kAesNumBlocks, kAesNumBlocks - 1, disable_entropy_at_start_en);
// Initialize AES
CHECK_DIF_OK(
dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
CHECK_DIF_OK(dif_aes_reset(&aes));
// Initialize EDN0, EDN1, CSRNG and Entropy Source
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));

// Generate key with index 0
generate_new_key(&key, 0);

// Prepare transaction
transaction.operation = kDifAesOperationEncrypt;
transaction.mode = kDifAesModeEcb;
transaction.key_len = kDifAesKey128;
transaction.key_provider = kDifAesKeySoftwareProvided;
transaction.mask_reseeding = kDifAesReseedPerBlock;
transaction.manual_operation = kDifAesManualOperationManual;
transaction.reseed_on_key_change = true;
transaction.force_masks = true;
transaction.ctrl_aux_lock = false;

if (disable_entropy_at_start_en == 1) {
LOG_INFO(
"Disabling entropy complex to induce AES stall before starting AES");
CHECK_STATUS_OK(disable_entropy_complex());
busy_spin_micros(500);
}

// Start the AES operation
// Wait for AES to be idle before starting encryption
aes_idle = false;
do {
CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusIdle, &aes_idle));
} while (!aes_idle);

CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL));

dif_aes_data_t plain_text[kAesNumBlocks];
dif_aes_data_t cipher_text[kAesNumBlocks];

// Initialize plaintext data dynamically
// Create plaintext with incremental data
for (int i = 0; i < kAesNumBlocks; ++i) {
for (int j = 0; j < kDifAesBlockNumBytes; ++j) {
plain_text[i].data[j] = (uint8_t)((i * kDifAesBlockNumBytes + j) & 0xFF);
}
}

// Start encryption process
for (int i = 0; i < kAesNumBlocks; ++i) {
if (transaction.manual_operation == kDifAesManualOperationManual) {
// Wait for AES to be idle before starting encryption
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed));
}

// Wait for input ready
input_ready = false;
do {
CHECK_DIF_OK(
dif_aes_get_status(&aes, kDifAesStatusInputReady, &input_ready));
} while (!input_ready);

// Load data
CHECK_DIF_OK(dif_aes_load_data(&aes, plain_text[i]));

// Trigger AES reseed request, specific for manual operation case as per
// documentation
if (transaction.manual_operation == kDifAesManualOperationManual) {
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerStart));
}

// Check for stall after entropy disabled
if (i == 0 && disable_entropy_at_start_en == 1) {
LOG_INFO(
"Checking AES status OutputValid status after stopping "
"EDN and CSRNG");
output_valid = false;
CHECK_DIF_OK(
dif_aes_get_status(&aes, kDifAesStatusOutputValid, &output_valid));
if (output_valid) {
LOG_ERROR(
"ERROR:AES encryption generated output_valid after stopping "
"entropy indicating no stall!");
} else {
LOG_INFO(
"AES encryption is waiting for output_valid as expected at block "
"%d",
i);
}

CHECK_STATUS_OK(enable_entropy_complex());
busy_spin_micros(500);
}

// Wait for the AES module to resume and produce output valid
output_valid = false;
do {
CHECK_DIF_OK(
dif_aes_get_status(&aes, kDifAesStatusOutputValid, &output_valid));
} while (!output_valid);

// Read output data
CHECK_DIF_OK(dif_aes_read_output(&aes, &cipher_text[i]));
// LOG_INFO("BLOCK completed: %d",i);
}

LOG_INFO("cipher_text data generated successfully");

// Finish the AES encryption operation
LOG_INFO("End AES encryption operation");
CHECK_DIF_OK(dif_aes_end(&aes));

// Wait for AES to be idle before starting decryption
aes_idle = false;
do {
CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusIdle, &aes_idle));
} while (!aes_idle);
LOG_INFO("AES module is idle");

return OK_STATUS();
}

bool test_main(void) {
LOG_INFO("Entering AES aes_force_prng_reseed_test Test");

return status_ok(execute_test());
}
Loading

0 comments on commit befede4

Please sign in to comment.