[sw, dif, aes] Refactor dif_aes_start function
- Replace all the aes start functions for a single function.
- Add unit test for decrypt.
Signed-off-by: Douglas Reis <doreis@lowrisc.org>
diff --git a/sw/device/lib/dif/dif_aes.c b/sw/device/lib/dif/dif_aes.c
index e9f850d..b0bc5a6 100644
--- a/sw/device/lib/dif/dif_aes.c
+++ b/sw/device/lib/dif/dif_aes.c
@@ -152,10 +152,11 @@
return kDifOk;
}
-dif_result_t dif_aes_start_ecb(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key) {
- if (aes == NULL || transaction == NULL) {
+dif_result_t dif_aes_start(const dif_aes_t *aes,
+ const dif_aes_transaction_t *transaction,
+ dif_aes_key_share_t key, const dif_aes_iv_t *iv) {
+ if (aes == NULL || transaction == NULL ||
+ (iv == NULL && transaction->mode != kDifAesModeEcb)) {
return kDifBadArg;
}
@@ -174,114 +175,11 @@
aes_set_multireg(aes, &key.share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
AES_KEY_SHARE1_0_REG_OFFSET);
- return kDifOk;
-}
-
-dif_result_t dif_aes_start_cbc(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv) {
- if (aes == NULL || transaction == NULL) {
- return kDifBadArg;
+ if (transaction->mode != kDifAesModeEcb) {
+ aes_set_multireg(aes, &iv->iv[0], AES_IV_MULTIREG_COUNT,
+ AES_IV_0_REG_OFFSET);
}
- if (!aes_idle(aes)) {
- return kDifUnavailable;
- }
-
- dif_result_t result = configure(aes, transaction);
- if (result != kDifOk) {
- return result;
- }
-
- aes_set_multireg(aes, &key.share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
- AES_KEY_SHARE0_0_REG_OFFSET);
-
- aes_set_multireg(aes, &key.share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
- AES_KEY_SHARE1_0_REG_OFFSET);
-
- aes_set_multireg(aes, &iv.iv[0], AES_IV_MULTIREG_COUNT, AES_IV_0_REG_OFFSET);
-
- return kDifOk;
-}
-
-dif_result_t dif_aes_start_ctr(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv) {
- if (aes == NULL || transaction == NULL) {
- return kDifBadArg;
- }
-
- if (!aes_idle(aes)) {
- return kDifUnavailable;
- }
-
- dif_result_t result = configure(aes, transaction);
- if (result != kDifOk) {
- return result;
- }
-
- aes_set_multireg(aes, &key.share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
- AES_KEY_SHARE0_0_REG_OFFSET);
-
- aes_set_multireg(aes, &key.share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
- AES_KEY_SHARE1_0_REG_OFFSET);
-
- aes_set_multireg(aes, &iv.iv[0], AES_IV_MULTIREG_COUNT, AES_IV_0_REG_OFFSET);
-
- return kDifOk;
-}
-
-dif_result_t dif_aes_start_ofb(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv) {
- if (aes == NULL || transaction == NULL) {
- return kDifBadArg;
- }
-
- if (!aes_idle(aes)) {
- return kDifUnavailable;
- }
-
- dif_result_t result = configure(aes, transaction);
- if (result != kDifOk) {
- return result;
- }
-
- aes_set_multireg(aes, &key.share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
- AES_KEY_SHARE0_0_REG_OFFSET);
-
- aes_set_multireg(aes, &key.share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
- AES_KEY_SHARE1_0_REG_OFFSET);
-
- aes_set_multireg(aes, &iv.iv[0], AES_IV_MULTIREG_COUNT, AES_IV_0_REG_OFFSET);
-
- return kDifOk;
-}
-
-dif_result_t dif_aes_start_cfb(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv) {
- if (aes == NULL || transaction == NULL) {
- return kDifBadArg;
- }
-
- if (!aes_idle(aes)) {
- return kDifUnavailable;
- }
-
- dif_result_t result = configure(aes, transaction);
- if (result != kDifOk) {
- return result;
- }
-
- aes_set_multireg(aes, &key.share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
- AES_KEY_SHARE0_0_REG_OFFSET);
-
- aes_set_multireg(aes, &key.share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
- AES_KEY_SHARE1_0_REG_OFFSET);
-
- aes_set_multireg(aes, &iv.iv[0], AES_IV_MULTIREG_COUNT, AES_IV_0_REG_OFFSET);
-
return kDifOk;
}
diff --git a/sw/device/lib/dif/dif_aes.h b/sw/device/lib/dif/dif_aes.h
index e2231f9..df747d7 100644
--- a/sw/device/lib/dif/dif_aes.h
+++ b/sw/device/lib/dif/dif_aes.h
@@ -101,26 +101,71 @@
typedef enum dif_aes_mode {
/**
* The Electronic Codebook Mode.
+ * In ECB cipher mode the key must be changed for every new block of data.
+ * This is the only secure way to use ECB cipher mode.
+ *
+ * Note: The ECB cipher mode doesn't use the iv parameter of the
+ * `dif_aes_start` function.
+ *
+ * Note: it is discouraged to use this cipher mode, due to impractical amount
+ * of different keys required to encrypt/decrypt multi-block messages.
*/
kDifAesModeEcb = 1,
/**
* The Cipher Block Chaining Mode.
+ *
+ * In CBC cipher mode, the same key can be used for all messages, however
+ * new Initialisation Vector (IV) must be generated for any new message. The
+ * following condition must be true:
+ * The IV must be unpredictable (it must not be possible to predict the IV
+ * that will be associated to the plaintext in advance of the generation
+ * of the IV).
+ *
+ * With key length less than 256 bits, the excess portion of the `key` can be
+ * written with any data (preferably random).
*/
kDifAesModeCbc = (1 << 1),
/**
* The Cipher Feedback Mode.
+ *
+ * In CFB cipher mode, the same key can be used for all messages, however
+ * new Initialisation Vector (IV) must be generated for any new message. The
+ * following condition must be true:
+ * The IV must be unpredictable (it must not be possible to predict the IV
+ * that will be associated to the plaintext in advance of the generation
+ * of the IV).
+ *
+ * With key length less than 256 bits, the excess portion of the `key` can be
+ * written with any data (preferably random).
*/
kDifAesModeCfb = (1 << 2),
/**
* The Output Feedback Mode.
+ *
+ * In OFB cipher mode, the same key can be used for all messages, and the
+ * Initialization Vector (IV) need NOT be unpredictable. The following
+ * conditions must be true:
+ * OFB mode requires a unique initialization vector for every message that
+ * is ever encrypted under a given key, across all messages.
+ *
+ * With key length less than 256 bits, the excess portion of the `key` can be
+ * written with any data (preferably random).
*/
kDifAesModeOfb = (1 << 3),
/**
* The Counter Mode.
+ *
+ * In CTR cipher mode, the same key can be used for all messages, if the
+ * following condition is true:
+ * CTR mode requires a unique counter block for each plaintext block that
+ * is ever encrypted under a given key, across all messages.
+ *
+ * With key length less than 256 bits, the excess portion of the `key` can be
+ * written with any data (preferably random).
*/
kDifAesModeCtr = (1 << 4),
} dif_aes_mode_t;
@@ -200,134 +245,24 @@
dif_result_t dif_aes_reset(const dif_aes_t *aes);
/**
- * Begins an AES transaction in ECB mode.
- *
- * In ECB cipher mode the key must be changed for every new block of data. This
- * is the only secure way to use ECB cipher mode.
+ * Begins an AES transaction in the mode selected by the `transaction->mode`.
*
* Each call to this function should be sequenced with a call to
* `dif_aes_end()`.
*
- * Note: it is discouraged to use this cipher mode, due to inpractical amount
- * of different keys required to encrypt/decrypt multi-block messages.
- *
* The peripheral must be in IDLE state for this operation to take effect, and
* will return `kDifAesBusy` if this condition is not met.
*
* @param aes AES state data.
* @param transaction Configuration data.
+ * @param iv AES Initialisation Vector. The iv may not be used for some modes,
+ * see `dif_aes_mode_t` for more details.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
-dif_result_t dif_aes_start_ecb(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key);
-
-/**
- * Begins an AES transaction in CBC mode.
- *
- * In CBC cipher mode, the same key can be used for all messages, however
- * new Initialisation Vector (IV) must be generated for any new message. The
- * following condition must be true:
- * The IV must be unpredictable (it must not be possible to predict the IV
- * that will be associated to the plaintext in advance of the generation of
- * the IV).
- *
- * With key length less than 256 bits, the excess portion of the `key` can be
- * written with any data (preferably random).
- *
- * The peripheral must be in IDLE state for this operation to take effect, and
- * will return `kDifAesStartBusy` if this condition is not met.
- *
- * @param aes AES state data.
- * @param transaction Configuration data.
- * @param key Masked AES key.
- * @param iv AES Initialisation Vector.
- * @return The result of the operation.
- */
-OT_WARN_UNUSED_RESULT
-dif_result_t dif_aes_start_cbc(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv);
-
-/**
- * Begins an AES transaction in CTR mode.
- *
- * In CTR cipher mode, the same key can be used for all messages, if the
- * following condition is true:
- * CTR mode requires a unique counter block for each plaintext block that
- * is ever encrypted under a given key, across all messages.
- *
- * With key length less than 256 bits, the excess portion of the `key` can be
- * written with any data (preferably random).
- *
- * The peripheral must be in IDLE state for this operation to take effect, and
- * will return `kDifAesStartBusy` if this condition is not met.
- *
- * @param aes AES state data.
- * @param transaction Configuration data.
- * @param key Masked AES key.
- * @param iv AES Initial Counter Value.
- * @return The result of the operation.
- */
-OT_WARN_UNUSED_RESULT
-dif_result_t dif_aes_start_ctr(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv);
-
-/**
- * Begins an AES transaction in OFB mode.
- *
- * In OFB cipher mode, the same key can be used for all messages, and the
- * Initialization Vector (IV) need NOT be unpredictable. The following
- * conditions must be true:
- * OFB mode requires a unique initialization vector for every message that
- * is ever encrypted under a given key, across all messages.
- *
- * With key length less than 256 bits, the excess portion of the `key` can be
- * written with any data (preferably random).
- *
- * The peripheral must be in IDLE state for this operation to take effect, and
- * will return `kDifAesStartBusy` if this condition is not met.
- *
- * @param aes AES state data.
- * @param transaction Configuration data.
- * @param key Masked AES key.
- * @param iv AES Initialization vector.
- * @return The result of the operation.
- */
-OT_WARN_UNUSED_RESULT
-dif_result_t dif_aes_start_ofb(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv);
-
-/**
- * Begins an AES transaction in CFB mode.
- *
- * In CFB cipher mode, the same key can be used for all messages, however
- * new Initialisation Vector (IV) must be generated for any new message. The
- * following condition must be true:
- * The IV must be unpredictable (it must not be possible to predict the IV
- * that will be associated to the plaintext in advance of the generation of
- * the IV).
- *
- * With key length less than 256 bits, the excess portion of the `key` can be
- * written with any data (preferably random).
- *
- * The peripheral must be in IDLE state for this operation to take effect, and
- * will return `kDifAesStartBusy` if this condition is not met.
- *
- * @param aes AES state data.
- * @param transaction Configuration data.
- * @param key Masked AES key.
- * @param iv AES Initialization vector.
- * @return The result of the operation.
- */
-OT_WARN_UNUSED_RESULT
-dif_result_t dif_aes_start_cfb(const dif_aes_t *aes,
- const dif_aes_transaction_t *transaction,
- dif_aes_key_share_t key, dif_aes_iv_t iv);
-
+dif_result_t dif_aes_start(const dif_aes_t *aes,
+ const dif_aes_transaction_t *transaction,
+ dif_aes_key_share_t key, const dif_aes_iv_t *iv);
/**
* Ends an AES transaction.
*
diff --git a/sw/device/lib/dif/dif_aes_unittest.cc b/sw/device/lib/dif/dif_aes_unittest.cc
index d9db2f4..bf2a22a 100644
--- a/sw/device/lib/dif/dif_aes_unittest.cc
+++ b/sw/device/lib/dif/dif_aes_unittest.cc
@@ -39,6 +39,16 @@
EXPECT_WRITE32(offset, iv.iv[i]);
}
}
+ void setExpectedConfig(uint32_t key_len, uint32_t mode, uint32_t operation) {
+ for (int i = 0; i < 2; i++) {
+ EXPECT_WRITE32(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, false},
+ {AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, false}});
+ }
+ }
};
// Init tests
@@ -86,19 +96,12 @@
TEST_F(EcbTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
- for (int i = 0; i < 2; i++) {
- EXPECT_WRITE32(
- AES_CTRL_SHADOWED_REG_OFFSET,
- {{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, kDifAesKey128},
- {AES_CTRL_SHADOWED_MODE_OFFSET, kDifAesModeEcb},
- {AES_CTRL_SHADOWED_OPERATION_OFFSET, kDifAesOperationEncrypt},
- {AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, false},
- {AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, false}});
- }
-
+ setExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
+ AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB,
+ AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC);
setExpectedKey(kKey_, 8);
- EXPECT_EQ(dif_aes_start_ecb(&aes_, &transaction, kKey_), kDifOk);
+ EXPECT_EQ(dif_aes_start(&aes_, &transaction, kKey_, NULL), kDifOk);
}
class CbcTest : public AesTestInitialized {
@@ -108,20 +111,13 @@
TEST_F(CbcTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
- for (int i = 0; i < 2; i++) {
- EXPECT_WRITE32(
- AES_CTRL_SHADOWED_REG_OFFSET,
- {{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, kDifAesKey128},
- {AES_CTRL_SHADOWED_MODE_OFFSET, kDifAesModeCbc},
- {AES_CTRL_SHADOWED_OPERATION_OFFSET, kDifAesOperationEncrypt},
- {AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, false},
- {AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, false}});
- }
-
+ setExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
+ AES_CTRL_SHADOWED_MODE_VALUE_AES_CBC,
+ AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC);
setExpectedKey(kKey_, 8);
setExpectedIv(kIv_);
- EXPECT_EQ(dif_aes_start_cbc(&aes_, &transaction, kKey_, kIv_), kDifOk);
+ EXPECT_EQ(dif_aes_start(&aes_, &transaction, kKey_, &kIv_), kDifOk);
}
// CFB tests
@@ -132,20 +128,13 @@
TEST_F(CFBTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
- for (int i = 0; i < 2; i++) {
- EXPECT_WRITE32(
- AES_CTRL_SHADOWED_REG_OFFSET,
- {{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, kDifAesKey128},
- {AES_CTRL_SHADOWED_MODE_OFFSET, kDifAesModeCfb},
- {AES_CTRL_SHADOWED_OPERATION_OFFSET, kDifAesOperationEncrypt},
- {AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, false},
- {AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, false}});
- }
-
+ setExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
+ AES_CTRL_SHADOWED_MODE_VALUE_AES_CFB,
+ AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC);
setExpectedKey(kKey_, 8);
setExpectedIv(kIv_);
- EXPECT_EQ(dif_aes_start_cfb(&aes_, &transaction, kKey_, kIv_), kDifOk);
+ EXPECT_EQ(dif_aes_start(&aes_, &transaction, kKey_, &kIv_), kDifOk);
}
// OFB tests
@@ -156,20 +145,13 @@
TEST_F(OFBTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
- for (int i = 0; i < 2; i++) {
- EXPECT_WRITE32(
- AES_CTRL_SHADOWED_REG_OFFSET,
- {{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, kDifAesKey128},
- {AES_CTRL_SHADOWED_MODE_OFFSET, kDifAesModeOfb},
- {AES_CTRL_SHADOWED_OPERATION_OFFSET, kDifAesOperationEncrypt},
- {AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, false},
- {AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, false}});
- }
-
+ setExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
+ AES_CTRL_SHADOWED_MODE_VALUE_AES_OFB,
+ AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC);
setExpectedKey(kKey_, 8);
setExpectedIv(kIv_);
- EXPECT_EQ(dif_aes_start_ofb(&aes_, &transaction, kKey_, kIv_), kDifOk);
+ EXPECT_EQ(dif_aes_start(&aes_, &transaction, kKey_, &kIv_), kDifOk);
}
// CTR tests
@@ -180,19 +162,32 @@
TEST_F(CTRTest, start) {
EXPECT_READ32(AES_STATUS_REG_OFFSET, 1);
- for (int i = 0; i < 2; i++) {
- EXPECT_WRITE32(AES_CTRL_SHADOWED_REG_OFFSET,
- {{AES_CTRL_SHADOWED_KEY_LEN_OFFSET, kDifAesKey128},
- {AES_CTRL_SHADOWED_MODE_OFFSET, kDifAesModeCtr},
- {AES_CTRL_SHADOWED_OPERATION_OFFSET, kDifAesOperationEncrypt},
- {AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, false},
- {AES_CTRL_SHADOWED_FORCE_ZERO_MASKS_BIT, false}});
- }
-
+ setExpectedConfig(AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128,
+ AES_CTRL_SHADOWED_MODE_VALUE_AES_CTR,
+ AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC);
setExpectedKey(kKey_, 8);
setExpectedIv(kIv_);
- EXPECT_EQ(dif_aes_start_ctr(&aes_, &transaction, kKey_, kIv_), kDifOk);
+ EXPECT_EQ(dif_aes_start(&aes_, &transaction, kKey_, &kIv_), kDifOk);
+}
+
+// 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);
+ setExpectedKey(kKey_, 8);
+
+ EXPECT_EQ(dif_aes_start(&aes_, &transaction, kKey_, NULL), kDifOk);
}
} // namespace
diff --git a/sw/device/sca/aes_serial.c b/sw/device/sca/aes_serial.c
index a4d57e1..aee8a61 100644
--- a/sw/device/sca/aes_serial.c
+++ b/sw/device/sca/aes_serial.c
@@ -63,7 +63,7 @@
dif_aes_key_share_t key_shares;
memcpy(key_shares.share0, key, sizeof(key_shares.share0));
memset(key_shares.share1, 0, sizeof(key_shares.share1));
- SS_CHECK_DIF_OK(dif_aes_start_ecb(&aes, &transaction, key_shares));
+ SS_CHECK_DIF_OK(dif_aes_start(&aes, &transaction, key_shares, NULL));
}
/**
diff --git a/sw/device/tests/aes_smoketest.c b/sw/device/tests/aes_smoketest.c
index 26c7a27..4667a55 100644
--- a/sw/device/tests/aes_smoketest.c
+++ b/sw/device/tests/aes_smoketest.c
@@ -93,7 +93,7 @@
.key_len = kDifAesKey256,
.manual_operation = kDifAesManualOperationAuto,
};
- CHECK_DIF_OK(dif_aes_start_ecb(&aes, &transaction, key));
+ CHECK_DIF_OK(dif_aes_start(&aes, &transaction, key, NULL));
// "Convert" plain data byte arrays to `dif_aes_data_t`.
dif_aes_data_t in_data_plain;
@@ -124,7 +124,7 @@
// Setup ECB decryption transaction.
transaction.operation = kDifAesOperationDecrypt;
- CHECK_DIF_OK(dif_aes_start_ecb(&aes, &transaction, key));
+ CHECK_DIF_OK(dif_aes_start(&aes, &transaction, key, NULL));
// Load the previously produced cipher text to start the decryption operation.
while (!aes_input_ready(&aes)) {