blob: 33ef2542c6104b4a23a9508c7371a6a842bb98cc [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/testing/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 SetExpectedKey(const dif_aes_key_share_t &key, uint32_t key_size) {
for (uint32_t i = 0; i < key_size; ++i) {
ptrdiff_t offset = AES_KEY_SHARE0_0_REG_OFFSET + (i * sizeof(uint32_t));
EXPECT_WRITE32(offset, key.share0[i]);
}
for (uint32_t i = 0; i < key_size; ++i) {
ptrdiff_t offset = AES_KEY_SHARE1_0_REG_OFFSET + (i * sizeof(uint32_t));
EXPECT_WRITE32(offset, key.share1[i]);
}
}
void SetExpectedIv(const dif_aes_iv_t &iv, const uint32_t kIvSize = 4) {
for (uint32_t i = 0; i < kIvSize; ++i) {
ptrdiff_t offset = AES_IV_0_REG_OFFSET + (i * sizeof(uint32_t));
EXPECT_WRITE32(offset, iv.iv[i]);
}
}
void SetExpectedConfig(uint32_t key_len, uint32_t mode, uint32_t operation,
bool manual_op, bool force_zero_masks) {
EXPECT_WRITE32_SHADOWED(
AES_CTRL_SHADOWED_REG_OFFSET,
{{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, key_len},
{AES_CTRL_SHADOWED_MODE_OFFSET, mode},
{AES_CTRL_SHADOWED_OPERATION_OFFSET, operation},
{AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, manual_op},
{AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, force_zero_masks}});
}
};
// 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,
};
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);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction, kKey_, NULL));
}
class CbcTest : public AesTestInitialized {
protected:
CbcTest() { transaction.mode = kDifAesModeCbc; }
};
TEST_F(CbcTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_CBC,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
SetExpectedIv(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);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_CFB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
SetExpectedIv(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);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_OFB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
SetExpectedIv(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);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_CTR,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
SetExpectedIv(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);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_DEC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction, kKey_, NULL));
}
// Key size test.
class Key192Test : public AesTestInitialized {
protected:
Key192Test() { transaction.key_len = kDifAesKey192; }
};
TEST_F(Key192Test, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_192,
AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction, kKey_, NULL));
}
// Key size test.
class Key256Test : public AesTestInitialized {
protected:
Key256Test() { transaction.key_len = kDifAesKey256; }
};
TEST_F(Key256Test, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_256,
AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction, kKey_, NULL));
}
// Manual operation
class ManualOperationTest : public AesTestInitialized {
protected:
ManualOperationTest() {
transaction.manual_operation = kDifAesManualOperationManual;
}
};
TEST_F(ManualOperationTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/true,
/*force_zero_masks=*/false);
SetExpectedKey(kKey_, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction, kKey_, NULL));
}
// Zero masking
class ZeroMaskingTest : public AesTestInitialized {
protected:
ZeroMaskingTest() { transaction.masking = kDifAesMaskingForceZero; }
};
TEST_F(ZeroMaskingTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
SetExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC,
/*manual_op=*/false,
/*force_zero_masks=*/true);
SetExpectedKey(kKey_, 8);
EXPECT_DIF_OK(dif_aes_start(&aes_, &transaction, kKey_, NULL));
}
// 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 in
class Data : public AesTestInitialized {
protected:
const dif_aes_data_t data_ = {
.data = {0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A}};
};
TEST_F(Data, DataIn) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {
{AES_STATUS_INPUT_READY_BIT, true},
});
for (uint32_t i = 0; i < ARRAYSIZE(data_.data); i++) {
ptrdiff_t offset = AES_DATA_IN_0_REG_OFFSET + (i * sizeof(uint32_t));
EXPECT_WRITE32(offset, data_.data[i]);
}
EXPECT_DIF_OK(dif_aes_load_data(&aes_, data_));
}
TEST_F(Data, DataOut) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, {
{AES_STATUS_INPUT_READY_BIT, true},
{AES_STATUS_OUTPUT_VALID_BIT, true},
});
for (uint32_t i = 0; i < ARRAYSIZE(data_.data); ++i) {
ptrdiff_t offset = AES_DATA_OUT_0_REG_OFFSET + (i * sizeof(uint32_t));
EXPECT_READ32(offset, data_.data[i]);
}
dif_aes_data_t out;
EXPECT_DIF_OK(dif_aes_read_output(&aes_, &out));
EXPECT_THAT(out.data, ElementsAreArray(data_.data));
}
// Trigger
class Trigger : public AesTestInitialized {};
TEST_F(Trigger, Start) {
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET, {{AES_TRIGGER_START_BIT, true}});
EXPECT_DIF_OK(dif_aes_trigger(&aes_, kDifAesTriggerStart));
}
TEST_F(Trigger, 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(Trigger, DataOutClear) {
EXPECT_WRITE32(AES_TRIGGER_REG_OFFSET,
{
{AES_TRIGGER_DATA_OUT_CLEAR_BIT, true},
});
EXPECT_DIF_OK(dif_aes_trigger(&aes_, kDifAesTriggerDataOutClear));
}
TEST_F(Trigger, 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);
}
} // namespace
} // namespace dif_aes_test