blob: f34a2eefd39865118c561fa42aeed00abd602e5b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_aes.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/aes_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 "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
// The following plaintext, key and ciphertext are extracted from Appendix C of
// the Advanced Encryption Standard (AES) FIPS Publication 197 available at
// https://www.nist.gov/publications/advanced-encryption-standard-aes
#define TIMEOUT (1000 * 1000)
static const uint32_t kPlainText[] = {
0x33221100,
0x77665544,
0xbbaa9988,
0xffeeddcc,
};
static const uint8_t kKey[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
};
static const uint32_t kCipherTextGold[] = {
0x493350e6,
0x4a0a5568,
0x9d4d4aa1,
0xd256e2e0,
};
static const uint32_t kIv[] = {
0x01020304,
0x0c0d0e0f,
0x1718191a,
0x1c1d1e1f,
};
// 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,
};
const test_config_t kTestConfig;
bool test_main(void) {
dif_aes_t aes;
// First of all, we need to get the entropy complex up and running.
entropy_testutils_boot_mode_init();
// Initialise AES.
CHECK_DIF_OK(
dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
CHECK_DIF_OK(dif_aes_reset(&aes));
// 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[ARRAYSIZE(kKey)];
for (int i = 0; i < ARRAYSIZE(kKey); ++i) {
key_share0[i] = kKey[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, ARRAYSIZE(kKey));
memcpy(key.share1, kKeyShare1, ARRAYSIZE(kKey));
// "Convert" iv byte arrays to `dif_aes_iv_t`.
dif_aes_iv_t iv;
memcpy(iv.iv, kIv, ARRAYSIZE(kIv));
// Setup CBC encryption transaction.
dif_aes_transaction_t transaction = {
.operation = kDifAesOperationEncrypt,
.mode = kDifAesModeCbc,
.key_len = kDifAesKey256,
.manual_operation = kDifAesManualOperationManual,
};
// Write the initial key share, IV and data in CSRs (known combinations).
CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, &iv));
dif_aes_data_t in_data_plain;
memcpy(in_data_plain.data, kPlainText, ARRAYSIZE(kPlainText));
AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusInputReady, true, TIMEOUT);
CHECK_DIF_OK(dif_aes_load_data(&aes, in_data_plain));
// Write the PRNG_RESEED bit to reseed the internal state of the PRNG.
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerPrngReseed));
// Trigger the AES operation to run and wait for it to complete.
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerStart));
AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusOutputValid, true, TIMEOUT);
// Check the ciphertext against the expected value.
dif_aes_data_t out_data;
CHECK_DIF_OK(dif_aes_read_output(&aes, &out_data));
CHECK_ARRAYS_EQ(out_data.data, kCipherTextGold, ARRAYSIZE(kCipherTextGold));
// Write the KEY_IV_DATA_IN_CLEAR and DATA_OUT_CLEAR trigger bits to 1 and
// wait for it to complete by polling the status idle bit.
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerDataOutClear));
CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerKeyIvDataInClear));
AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, true, TIMEOUT);
// Read back the data out CSRs - they should all read garbage values.
CHECK(dif_aes_read_output(&aes, &out_data) == kDifError);
CHECK(!aes_testutils_get_status(&aes, kDifAesStatusOutputValid));
// Assertion check verifies that the internal states (data_in, key share and
// IV are also garbage, i.e. different from the originally written values.
CHECK_DIF_OK(dif_aes_read_iv(&aes, &iv));
CHECK_ARRAYS_NE(iv.iv, kIv, ARRAYSIZE(kIv));
CHECK_DIF_OK(dif_aes_end(&aes));
return true;
}