Skip to content

Commit

Permalink
Tests for aes_prng_reseed and aes_prng_force_reseed
Browse files Browse the repository at this point in the history
Signed-off-by: Varunkumar Trivedi <[email protected]>
  • Loading branch information
github-gcontributor committed Oct 1, 2024
1 parent 7fad7db commit 2786b0b
Show file tree
Hide file tree
Showing 3 changed files with 577 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 @@ -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"],
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",
],
)
275 changes: 275 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,275 @@
// 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();

static dif_aes_t aes;
dif_aes_transaction_t transaction;
dif_aes_key_share_t key;
// Prepare plaintext data
enum {
kAesNumBlocks = 8,
};
// NumBytes should be 1 i.e. 8 bits
enum {
kDifAesBlockNumBytes = 1,
};
enum {
disable_entropy_after_block = 0,
};
enum {
disable_entropy_at_start_en = 1,
};
enum {
generate_new_key_at_block = 3,
};

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;

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();
}

// Function to generate a new key based on an index
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 of 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), "
"generating new key at block: %d and disabling entropy at start enable"
": %d and disabling entropy after block: %d",
kAesNumBlocks, kAesNumBlocks - 1, generate_new_key_at_block - 1,
disable_entropy_at_start_en, disable_entropy_after_block - 1);
// 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));
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_new_key(&key, 0);

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
// For demonstration, we'll fill the 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));
// Check for stall and trigger reseed
bool stalled = false;
CHECK_DIF_OK(dif_aes_get_status(&aes, kDifAesStatusStall, &stalled));
if (stalled) {
// Trigger PRNG reseed due to stall
LOG_INFO("Trigger PRNG reseed due to stall enabled to proceed");
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 && i == disable_entropy_after_block) ||
(i == 0 && disable_entropy_at_start_en == 1)) {
LOG_INFO(
"Conditionally 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_INFO("AES encryption has output_valid as expected.");
} else {
LOG_ERROR(
"ERROR:AES encryption did not generate output_valid after stopping "
"entropy indicating virtual stall!");
}

LOG_INFO(
"Conditionally checking AES status after stopping EDN and CSRNG.");
LOG_INFO("Waiting for AES kDifAesStatusStall bit to get enabled...");
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_WARNING(
"AES encryption status bit kDifAesStatusStall did not get enable "
"after stopping entropy Lets "
"proceed "
"for now to verify further steps...");
}
// Wait for the AES module to resume and produce output valid
LOG_INFO("Enabling entropy complex");
CHECK_STATUS_OK(enable_entropy_complex());
busy_spin_micros(500);
}

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]));

// Disable entropy complex after processing enough blocks
if (i == generate_new_key_at_block - 1 ||
i == disable_entropy_after_block - 1) {
LOG_INFO("Changing AES key after block %d", i);

// End the current AES operation
CHECK_DIF_OK(dif_aes_end(&aes));

// Generate new key using the existing 'key' variable
// Here 'i' serves as the index for variation
generate_new_key(&key, i);

// Start a new AES operation with the new key
CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL));

if (i == disable_entropy_after_block - 1) {
LOG_INFO("Disabling entropy complex to induce AES stall at block: %d",
i);
CHECK_STATUS_OK(disable_entropy_complex());
busy_spin_micros(500);

// Manually trigger a PRNG reseed to force entropy request
LOG_INFO("Triggering PRNG reseed to force entropy request");
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed));
}
}
}

LOG_INFO("cipher_text data generated");

// 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 2786b0b

Please sign in to comment.