blob: 69e711e09d12bd11957bd0dbd41444c312a130c6 [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/dif/dif_aes.h"
#include "gtest/gtest.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/base/mock_mmio.h"
#include "sw/device/lib/dif/dif_test_base.h"
extern "C" {
#include "aes_regs.h" // Generated.
} // extern "C"
namespace dif_aes_test {
namespace {
using mock_mmio::MmioTest;
using mock_mmio::MockDevice;
using testing::ElementsAreArray;
using testing::Test;
// Base class for the rest fixtures in this file.
class AesTest : public testing::Test, public mock_mmio::MmioTest {
public:
void ExpectReadMultreg(const uint32_t reg, const uint32_t *data,
size_t size) {
for (uint32_t i = 0; i < size; ++i) {
ptrdiff_t offset = reg + (i * sizeof(uint32_t));
EXPECT_READ32(offset, data[i]);
}
}
void ExpectWriteMultreg(const uint32_t reg, const uint32_t *data,
size_t size) {
for (uint32_t i = 0; i < size; ++i) {
ptrdiff_t offset = reg + (i * sizeof(uint32_t));
EXPECT_WRITE32(offset, data[i]);
}
}
void ExpectKey(const dif_aes_key_share_t &key, uint32_t key_size) {
ExpectWriteMultreg(AES_KEY_SHARE0_0_REG_OFFSET, key.share0, key_size);
ExpectWriteMultreg(AES_KEY_SHARE1_0_REG_OFFSET, key.share1, key_size);
}
void ExpectIv(const dif_aes_iv_t &iv, const uint32_t kIvSize = 4) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_IDLE_BIT, true}});
ExpectWriteMultreg(AES_IV_0_REG_OFFSET, iv.iv, kIvSize);
}
struct ConfigOptions {
uint32_t key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128;
uint32_t mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB;
uint32_t operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC;
uint32_t mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1;
bool manual_op = false;
bool force_zero_masks = false;
bool key_sideloaded = false;
};
void ExpectConfig(const ConfigOptions &options) {
EXPECT_WRITE32_SHADOWED(
AES_CTRL_SHADOWED_REG_OFFSET,
{{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, options.key_len},
{AES_CTRL_SHADOWED_MODE_OFFSET, options.mode},
{AES_CTRL_SHADOWED_OPERATION_OFFSET, options.operation},
{AES_CTRL_SHADOWED_PRNG_RESEED_RATE_OFFSET, options.mask_reseed},
{AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, options.manual_op},
{AES_CTRL_SHADOWED_SIDELOAD_BIT, options.key_sideloaded},
{AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, options.force_zero_masks}});
}
struct AuxConfigOptions {
bool reseed_on_key_change = false;
bool lock = false;
};
void ExpectAuxConfig(const AuxConfigOptions &options) {
EXPECT_READ32(AES_CTRL_AUX_REGWEN_REG_OFFSET,
{{AES_CTRL_AUX_REGWEN_CTRL_AUX_REGWEN_BIT, 1}});
EXPECT_WRITE32_SHADOWED(AES_CTRL_AUX_SHADOWED_REG_OFFSET,
{{AES_CTRL_AUX_SHADOWED_KEY_TOUCH_FORCES_RESEED_BIT,
options.reseed_on_key_change}});
EXPECT_WRITE32(AES_CTRL_AUX_REGWEN_REG_OFFSET,
{{AES_CTRL_AUX_REGWEN_CTRL_AUX_REGWEN_BIT, !options.lock}});
}
};
// Init tests
class AesInitTest : public AesTest {};
TEST_F(AesInitTest, NullArgs) {
EXPECT_DIF_BADARG(dif_aes_init(dev().region(), nullptr));
}
TEST_F(AesInitTest, Sucess) {
dif_aes_t aes;
EXPECT_DIF_OK(dif_aes_init(dev().region(), &aes));
}
// Base class for the rest of the tests in this file, provides a
// `dif_aes_t` instance.
class AesTestInitialized : public AesTest {
protected:
dif_aes_t aes_;
dif_aes_transaction_t transaction_ = {
.operation = kDifAesOperationEncrypt,
.mode = kDifAesModeEcb,
.key_len = kDifAesKey128,
.manual_operation = kDifAesManualOperationAuto,
.masking = kDifAesMaskingInternalPrng,
.key_provider = kDifAesKeySoftwareProvided,
.mask_reseeding = kDifAesReseedPerBlock,
.reseed_on_key_change_lock = false,
};
const dif_aes_key_share_t kKey = {
.share0 = {0x59, 0x70, 0x33, 0x73, 0x36, 0x76, 0x39, 0x79},
.share1 = {0x4B, 0x61, 0x50, 0x64, 0x53, 0x67, 0x56, 0x6B}};
const dif_aes_iv_t kIv = {0x50, 0x64, 0x53, 0x67};
AesTestInitialized() { EXPECT_DIF_OK(dif_aes_init(dev().region(), &aes_)); }
};
// ECB tests.
class EcbTest : public AesTestInitialized {
protected:
EcbTest() { transaction_.mode = kDifAesModeEcb; }
};
TEST_F(EcbTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
class CbcTest : public AesTestInitialized {
protected:
CbcTest() { transaction_.mode = kDifAesModeCbc; }
};
TEST_F(CbcTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_CBC,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
ExpectIv(kIv);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, &kIv));
}
// CFB tests.
class CFBTest : public AesTestInitialized {
protected:
CFBTest() { transaction_.mode = kDifAesModeCfb; }
};
TEST_F(CFBTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_CFB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
ExpectIv(kIv);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, &kIv));
}
// OFB tests.
class OFBTest : public AesTestInitialized {
protected:
OFBTest() { transaction_.mode = kDifAesModeOfb; }
};
TEST_F(OFBTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_OFB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
ExpectIv(kIv);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, &kIv));
}
// CTR tests.
class CTRTest : public AesTestInitialized {
protected:
CTRTest() { transaction_.mode = kDifAesModeCtr; }
};
TEST_F(CTRTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_CTR,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
ExpectIv(kIv);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, &kIv));
}
// Decrypt tests.
class DecryptTest : public AesTestInitialized {
protected:
DecryptTest() {
transaction_.mode = kDifAesModeEcb;
transaction_.operation = kDifAesOperationDecrypt;
}
};
TEST_F(DecryptTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_DEC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
// Key size test.
class Key192Test : public AesTestInitialized {
protected:
Key192Test() { transaction_.key_len = kDifAesKey192; }
};
TEST_F(Key192Test, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_192,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
// Key size test.
class Key256Test : public AesTestInitialized {
protected:
Key256Test() { transaction_.key_len = kDifAesKey256; }
};
TEST_F(Key256Test, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_256,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
// Manual operation
class ManualOperationTest : public AesTestInitialized {
protected:
ManualOperationTest() {
transaction_.manual_operation = kDifAesManualOperationManual;
}
};
TEST_F(ManualOperationTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
.manual_op = true,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
// Zero masking
class ZeroMaskingTest : public AesTestInitialized {
protected:
ZeroMaskingTest() { transaction_.masking = kDifAesMaskingForceZero; }
};
TEST_F(ZeroMaskingTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
.force_zero_masks = true,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
// Alert test.
class AlertTest : public AesTestInitialized {};
TEST_F(AlertTest, RecovCtrlUpdateErr) {
EXPECT_WRITE32(AES_ALERT_TEST_REG_OFFSET,
{{AES_ALERT_TEST_RECOV_CTRL_UPDATE_ERR_BIT, true},
{AES_ALERT_TEST_FATAL_FAULT_BIT, false}});
EXPECT_DIF_OK(dif_aes_alert_force(&aes_, kDifAesAlertRecovCtrlUpdateErr));
}
TEST_F(AlertTest, AlertFatalFault) {
EXPECT_WRITE32(AES_ALERT_TEST_REG_OFFSET,
{{AES_ALERT_TEST_RECOV_CTRL_UPDATE_ERR_BIT, false},
{AES_ALERT_TEST_FATAL_FAULT_BIT, true}});
EXPECT_DIF_OK(dif_aes_alert_force(&aes_, kDifAesAlertFatalFault));
}
// Data tests.
class DataTest : public AesTestInitialized {
protected:
const dif_aes_data_t data_ = {
.data = {0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A}};
};
TEST_F(DataTest, DataIn) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, true}});
ExpectWriteMultreg(AES_DATA_IN_0_REG_OFFSET, data_.data,
ARRAYSIZE(data_.data));
EXPECT_DIF_OK(dif_aes_load_data(&aes_, data_));
}
TEST_F(DataTest, DataOut) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {
{AES_STATUS_INPUT_READY_BIT, true},
{AES_STATUS_OUTPUT_VALID_BIT, true},
});
ExpectReadMultreg(AES_DATA_OUT_0_REG_OFFSET, data_.data,
ARRAYSIZE(data_.data));
dif_aes_data_t out;
EXPECT_DIF_OK(dif_aes_read_output(&aes_, &out));
EXPECT_THAT(out.data, ElementsAreArray(data_.data));
}
class DataProcessTest : public AesTestInitialized {
protected:
static constexpr size_t kBlockCount = 3;
static constexpr size_t kBlockSize = 4;
static constexpr dif_aes_data_t kDataIn[kBlockCount] = {
{.data = {0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A}},
{.data = {0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A}},
{.data = {0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A}},
};
static constexpr dif_aes_data_t kDataOut[kBlockCount] = {
{.data = {0xB44BB44B, 0xB44BB44B, 0xB44BB44B, 0xB44BB44B}},
{.data = {0x4BB4B44B, 0x4BB4B44B, 0x4BB4B44B, 0x4BB4B44B}},
{.data = {0xB44BB44B, 0xB44BB44B, 0xB44BB44B, 0xB44BB44B}},
};
};
constexpr size_t DataProcessTest::kBlockCount;
constexpr size_t DataProcessTest::kBlockSize;
constexpr dif_aes_data_t DataProcessTest::kDataIn[kBlockCount];
constexpr dif_aes_data_t DataProcessTest::kDataOut[kBlockCount];
TEST_F(DataProcessTest, ThreeBlocksSuccess) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, true},
{AES_STATUS_OUTPUT_VALID_BIT, true}});
ExpectWriteMultreg(AES_DATA_IN_0_REG_OFFSET, kDataIn[0].data, kBlockSize);
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, true}});
ExpectWriteMultreg(AES_DATA_IN_0_REG_OFFSET, kDataIn[1].data, kBlockSize);
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, true}});
ExpectReadMultreg(AES_DATA_OUT_0_REG_OFFSET, kDataOut[0].data, kBlockSize);
ExpectWriteMultreg(AES_DATA_IN_0_REG_OFFSET, kDataIn[2].data, kBlockSize);
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, true}});
ExpectReadMultreg(AES_DATA_OUT_0_REG_OFFSET, kDataOut[1].data, kBlockSize);
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, true}});
ExpectReadMultreg(AES_DATA_OUT_0_REG_OFFSET, kDataOut[2].data, kBlockSize);
dif_aes_data_t out[kBlockCount];
EXPECT_DIF_OK(dif_aes_process_data(&aes_, kDataIn, out, kBlockCount));
for (size_t i = 0; i < kBlockCount; ++i) {
EXPECT_THAT(out[i].data, ElementsAreArray(kDataOut[i].data));
}
}
TEST_F(DataProcessTest, OneBlockSuccess) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, true}});
ExpectWriteMultreg(AES_DATA_IN_0_REG_OFFSET, kDataIn[0].data, kBlockSize);
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, true}});
ExpectReadMultreg(AES_DATA_OUT_0_REG_OFFSET, kDataOut[0].data, kBlockSize);
dif_aes_data_t out[kBlockCount];
EXPECT_DIF_OK(dif_aes_process_data(&aes_, kDataIn, out, 1));
EXPECT_THAT(out[0].data, ElementsAreArray(kDataOut[0].data));
}
TEST_F(DataProcessTest, OneBlockUnavailable) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, false}});
dif_aes_data_t out[kBlockCount];
EXPECT_EQ(dif_aes_process_data(&aes_, kDataIn, out, 1), kDifUnavailable);
}
// Read the IV tests.
class IVTest : public AesTestInitialized {};
TEST_F(IVTest, Read) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_IDLE_BIT, true}});
ExpectReadMultreg(AES_IV_0_REG_OFFSET, kIv.iv, ARRAYSIZE(kIv.iv));
dif_aes_iv_t iv;
EXPECT_DIF_OK(dif_aes_read_iv(&aes_, &iv));
EXPECT_THAT(iv.iv, ElementsAreArray(kIv.iv));
}
// Trigger
class TriggerTest : public AesTestInitialized {};
TEST_F(TriggerTest, Start) {
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET, {{AES_TRIGGER_START_BIT, true}});
EXPECT_DIF_OK(dif_aes_trigger(&aes_, kDifAesTriggerStart));
}
TEST_F(TriggerTest, KeyIvDataInClear) {
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET,
{
{AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true},
});
EXPECT_DIF_OK(dif_aes_trigger(&aes_, kDifAesTriggerKeyIvDataInClear));
}
TEST_F(TriggerTest, DataOutClear) {
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET,
{
{AES_TRIGGER_DATA_OUT_CLEAR_BIT, true},
});
EXPECT_DIF_OK(dif_aes_trigger(&aes_, kDifAesTriggerDataOutClear));
}
TEST_F(TriggerTest, PrngReseed) {
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET,
{
{AES_TRIGGER_PRNG_RESEED_BIT, true},
});
EXPECT_DIF_OK(dif_aes_trigger(&aes_, kDifAesTriggerPrngReseed));
}
// Status
class Status : public AesTestInitialized {};
TEST_F(Status, True) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_IDLE_BIT, true}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_STALL_BIT, true}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_LOST_BIT, true}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, true}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, true}});
EXPECT_READ32(AES_STATUS_REG_OFFSET,
{{AES_STATUS_ALERT_FATAL_FAULT_BIT, true}});
EXPECT_READ32(AES_STATUS_REG_OFFSET,
{{AES_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_BIT, true}});
bool set;
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusIdle, &set));
EXPECT_TRUE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusStall, &set));
EXPECT_TRUE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusOutputLost, &set));
EXPECT_TRUE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusOutputValid, &set));
EXPECT_TRUE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusInputReady, &set));
EXPECT_TRUE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusAlertFatalFault, &set));
EXPECT_TRUE(set);
EXPECT_DIF_OK(
dif_aes_get_status(&aes_, kDifAesStatusAlertRecovCtrlUpdateErr, &set));
EXPECT_TRUE(set);
}
TEST_F(Status, False) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_IDLE_BIT, false}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_STALL_BIT, false}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_LOST_BIT, false}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, false}});
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_INPUT_READY_BIT, false}});
EXPECT_READ32(AES_STATUS_REG_OFFSET,
{{AES_STATUS_ALERT_FATAL_FAULT_BIT, false}});
EXPECT_READ32(AES_STATUS_REG_OFFSET,
{{AES_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_BIT, false}});
bool set;
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusIdle, &set));
EXPECT_FALSE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusStall, &set));
EXPECT_FALSE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusOutputLost, &set));
EXPECT_FALSE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusOutputValid, &set));
EXPECT_FALSE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusInputReady, &set));
EXPECT_FALSE(set);
EXPECT_DIF_OK(dif_aes_get_status(&aes_, kDifAesStatusAlertFatalFault, &set));
EXPECT_FALSE(set);
EXPECT_DIF_OK(
dif_aes_get_status(&aes_, kDifAesStatusAlertRecovCtrlUpdateErr, &set));
EXPECT_FALSE(set);
}
// Sideloaded key.
class SideloadedKeyTest : public AesTestInitialized {
protected:
SideloadedKeyTest() { transaction_.key_provider = kDifAesKeySideload; }
};
TEST_F(SideloadedKeyTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
.key_sideloaded = true});
ExpectAuxConfig({});
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, nullptr, nullptr));
}
// Mask reseeding.
class MaskReseedingTest : public AesTestInitialized {};
TEST_F(MaskReseedingTest, ReseedPer64Block) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_64,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
transaction_.mask_reseeding = kDifAesReseedPer64Block;
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
TEST_F(MaskReseedingTest, ReseedPer8kBlock) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_8K,
});
ExpectAuxConfig({});
ExpectKey(kKey, 8);
transaction_.mask_reseeding = kDifAesReseedPer8kBlock;
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
// Reseed on key change.
class RessedOnKeyChangeTest : public AesTestInitialized {};
TEST_F(RessedOnKeyChangeTest, Unlock) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
transaction_.reseed_on_key_change = true;
transaction_.reseed_on_key_change_lock = false;
ExpectAuxConfig({
.reseed_on_key_change = true,
});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
TEST_F(RessedOnKeyChangeTest, Lock) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
transaction_.reseed_on_key_change = true;
transaction_.reseed_on_key_change_lock = true;
ExpectAuxConfig({.reseed_on_key_change = true, .lock = true});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
TEST_F(RessedOnKeyChangeTest, LockedSuccess) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
transaction_.reseed_on_key_change = true;
transaction_.reseed_on_key_change_lock = true;
EXPECT_READ32(AES_CTRL_AUX_REGWEN_REG_OFFSET,
{{AES_CTRL_AUX_REGWEN_CTRL_AUX_REGWEN_BIT, 0}});
EXPECT_READ32(AES_CTRL_AUX_SHADOWED_REG_OFFSET,
{{AES_CTRL_AUX_SHADOWED_KEY_TOUCH_FORCES_RESEED_BIT, true}});
ExpectKey(kKey, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
TEST_F(RessedOnKeyChangeTest, LockedError) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
ExpectConfig({
.key_len = AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
.mode = AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
.operation = AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
.mask_reseed = AES_CTRL_SHADOWED_PRNG_RESEED_RATE_VALUE_PER_1,
});
transaction_.reseed_on_key_change = true;
transaction_.reseed_on_key_change_lock = true;
EXPECT_READ32(AES_CTRL_AUX_REGWEN_REG_OFFSET,
{{AES_CTRL_AUX_REGWEN_CTRL_AUX_REGWEN_BIT, 0}});
EXPECT_READ32(AES_CTRL_AUX_SHADOWED_REG_OFFSET,
{{AES_CTRL_AUX_SHADOWED_KEY_TOUCH_FORCES_RESEED_BIT, false}});
EXPECT_EQ(dif_aes_start(&aes_, &transaction_, &kKey, nullptr), kDifError);
}
// Dif functions.
class DifFunctionsTest : public AesTestInitialized {
protected:
DifFunctionsTest() {}
};
TEST_F(DifFunctionsTest, Reset) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
EXPECT_WRITE32_SHADOWED(AES_CTRL_SHADOWED_REG_OFFSET,
{{AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, true}});
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET,
{
{AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true},
{AES_TRIGGER_DATA_OUT_CLEAR_BIT, true},
});
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
EXPECT_WRITE32_SHADOWED(
AES_CTRL_SHADOWED_REG_OFFSET,
{{AES_CTRL_SHADOWED_OPERATION_OFFSET, AES_CTRL_SHADOWED_OPERATION_MASK},
{AES_CTRL_SHADOWED_MODE_OFFSET, AES_CTRL_SHADOWED_MODE_VALUE_AES_NONE},
{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, AES_CTRL_SHADOWED_KEY_LEN_MASK}});
EXPECT_DIF_OK(dif_aes_reset(&aes_));
}
TEST_F(DifFunctionsTest, End) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
EXPECT_WRITE32_SHADOWED(AES_CTRL_SHADOWED_REG_OFFSET,
{{AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, true}});
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET,
{
{AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true},
{AES_TRIGGER_DATA_OUT_CLEAR_BIT, true},
});
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
EXPECT_DIF_OK(dif_aes_end(&aes_));
}
// Dif errors
class DifBadArgError : public AesTestInitialized {
protected:
DifBadArgError() {
transaction_.key_provider = kDifAesKeySoftwareProvided;
transaction_.mode = kDifAesModeCbc;
}
};
TEST_F(DifBadArgError, start) {
EXPECT_DIF_BADARG(dif_aes_start(nullptr, &transaction_, &kKey, &kIv));
EXPECT_DIF_BADARG(dif_aes_start(&aes_, nullptr, &kKey, &kIv));
EXPECT_DIF_BADARG(dif_aes_start(&aes_, &transaction_, nullptr, &kIv));
EXPECT_DIF_BADARG(dif_aes_start(&aes_, &transaction_, &kKey, nullptr));
}
TEST_F(DifBadArgError, reset) { EXPECT_DIF_BADARG(dif_aes_reset(nullptr)); }
TEST_F(DifBadArgError, end) { EXPECT_DIF_BADARG(dif_aes_end(nullptr)); }
TEST_F(DifBadArgError, LoadData) {
dif_aes_data_t data = {};
EXPECT_DIF_BADARG(dif_aes_load_data(nullptr, data));
}
TEST_F(DifBadArgError, ReadOutput) {
dif_aes_data_t data = {};
EXPECT_DIF_BADARG(dif_aes_read_output(nullptr, &data));
EXPECT_DIF_BADARG(dif_aes_read_output(&aes_, nullptr));
}
TEST_F(DifBadArgError, Trigger) {
EXPECT_DIF_BADARG(dif_aes_trigger(nullptr, kDifAesTriggerPrngReseed));
}
TEST_F(DifBadArgError, GetStatus) {
bool set;
EXPECT_DIF_BADARG(dif_aes_get_status(nullptr, kDifAesStatusIdle, &set));
EXPECT_DIF_BADARG(dif_aes_get_status(&aes_, kDifAesStatusIdle, nullptr));
}
TEST_F(DifBadArgError, ReadIV) {
dif_aes_iv_t iv = {};
EXPECT_DIF_BADARG(dif_aes_read_iv(nullptr, &iv));
EXPECT_DIF_BADARG(dif_aes_read_iv(&aes_, nullptr));
}
TEST_F(DifBadArgError, ProcessData) {
dif_aes_data_t data[1] = {};
dif_aes_data_t out[1] = {};
EXPECT_DIF_BADARG(dif_aes_process_data(nullptr, data, out, 1));
EXPECT_DIF_BADARG(dif_aes_process_data(&aes_, nullptr, out, 1));
EXPECT_DIF_BADARG(dif_aes_process_data(&aes_, data, nullptr, 1));
EXPECT_DIF_BADARG(dif_aes_process_data(&aes_, data, out, 0));
}
class DifUnavailableError : public AesTestInitialized {
protected:
DifUnavailableError() {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_IDLE_BIT, false}});
}
};
TEST_F(DifUnavailableError, start) {
EXPECT_EQ(dif_aes_start(&aes_, &transaction_, &kKey, nullptr),
kDifUnavailable);
}
TEST_F(DifUnavailableError, end) {
EXPECT_EQ(dif_aes_end(&aes_), kDifUnavailable);
}
TEST_F(DifUnavailableError, LoadData) {
dif_aes_data_t data = {{0}};
EXPECT_EQ(dif_aes_load_data(&aes_, data), kDifUnavailable);
}
TEST_F(DifUnavailableError, ReadIV) {
dif_aes_iv_t iv = {{0}};
EXPECT_EQ(dif_aes_read_iv(&aes_, &iv), kDifUnavailable);
}
TEST_F(DifUnavailableError, ProcessData) {
dif_aes_data_t data[2] = {};
dif_aes_data_t out[2] = {};
EXPECT_EQ(dif_aes_process_data(&aes_, data, out, ARRAYSIZE(data)),
kDifUnavailable);
}
class DifError : public AesTestInitialized {
protected:
DifError() {}
};
TEST_F(DifError, ReadOutput) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {{AES_STATUS_OUTPUT_VALID_BIT, false}});
dif_aes_data_t data = {{0}};
EXPECT_EQ(dif_aes_read_output(&aes_, &data), kDifError);
}
} // namespace
} // namespace dif_aes_test