[crypto] Add functest for the AES driver
Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/lib/crypto/drivers/BUILD b/sw/device/lib/crypto/drivers/BUILD
index a07d559..2d73407 100644
--- a/sw/device/lib/crypto/drivers/BUILD
+++ b/sw/device/lib/crypto/drivers/BUILD
@@ -5,6 +5,7 @@
package(default_visibility = ["//visibility:public"])
load("//rules:opentitan.bzl", "OPENTITAN_CPU")
+load("//rules:opentitan_test.bzl", "opentitan_functest")
cc_library(
name = "aes",
@@ -16,7 +17,18 @@
"//sw/device/lib/base:abs_mmio",
"//sw/device/lib/base:bitfield",
"//sw/device/lib/base:macros",
+ ],
+)
+
+opentitan_functest(
+ name = "aes_test",
+ srcs = ["aes_test.c"],
+ deps = [
+ ":aes",
+ "//sw/device/lib/base:macros",
"//sw/device/lib/base:memory",
+ "//sw/device/lib/testing/test_framework:check",
+ "//sw/device/lib/testing/test_framework:ottf_main",
],
)
diff --git a/sw/device/lib/crypto/drivers/aes_test.c b/sw/device/lib/crypto/drivers/aes_test.c
new file mode 100644
index 0000000..c446eb0
--- /dev/null
+++ b/sw/device/lib/crypto/drivers/aes_test.c
@@ -0,0 +1,97 @@
+// 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/crypto/drivers/aes.h"
+
+#include "sw/device/lib/base/memory.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+static const char kSecretKey[] = "Secret test key.";
+
+static const char kPlaintext[] =
+ "Muchos años después, frente al pelotón de fusilamiento, el coronel "
+ "Aureliano Buendía había de recordar aquella tarde remota en que su "
+ "padre lo llevó a conocer el hielo.";
+
+// AES-CTR encrypted using all zeroes IV.
+static const uint32_t kCiphertext[] = {
+ 0x141cf4f1, 0xdcbf3c9b, 0x41c1e909, 0x0202d9f7, 0x27000325, 0x882033f3,
+ 0xd77b0a50, 0x92425836, 0x72733658, 0x3f80eeef, 0x250086fe, 0x1f015d22,
+ 0x7054e010, 0xaef95ca9, 0xb446fd50, 0x6bef787d, 0x564e1dcc, 0xe3650cc0,
+ 0xa75a3298, 0xa0e7a3b8, 0x7d91ca73, 0x034ea236, 0x6cc76e1c, 0xb6b333ab,
+ 0x4989dfa4, 0x41a7e22b, 0x5d41f04f, 0x7b49b3c6, 0x127e7daa, 0x081306e0,
+ 0x60d9450c, 0xc7e08a02, 0x353f0dc2, 0x59e33d60, 0x35900057, 0xec8901d5,
+ 0xb28a4979, 0x52340cc1, 0x95ca3392, 0xfc4d8a32, 0x981cd522, 0x7dab4b1e,
+ 0xc3352eb6, 0x008ee548, 0x00000000, 0x00000000,
+};
+
+const test_config_t kTestConfig;
+bool test_main(void) {
+ // This is a weak share intended to exercise correct configuration of the
+ // hardware; in general, the key should be generated by either generating
+ // two shares and setting key = a ^ b, or generating a mask and setting
+ // a = key ^ mask, b = mask.
+ uint32_t share0[4];
+ uint32_t share1[4];
+ memcpy(share0, kSecretKey, ARRAYSIZE(kSecretKey));
+ for (int i = 0; i < ARRAYSIZE(share0); ++i) {
+ if (i % 2 == 0) {
+ share0[i] = ~share0[i];
+ share1[i] = -1;
+ } else {
+ share1[i] = ~share0[i];
+ share0[i] = -1;
+ }
+ }
+
+ LOG_INFO("Configuring the AES hardware.");
+ CHECK(aes_begin((aes_params_t){
+ .encrypt = true,
+ .mode = kAesCipherModeCtr,
+ .key_len = kAesKeyLen128,
+ .key = {share0, share1},
+ .iv = {0},
+ }) == kAesOk);
+
+ // NOTE: ARRAYSIZE(kPlaintext) is not a multiple of the block size!
+ uint32_t ciphertext[ARRAYSIZE(kCiphertext)] = {0};
+ char *cipherptr = (char *)&ciphertext[0];
+ for (size_t i = 0;; i += sizeof(aes_block_t)) {
+ LOG_INFO("Processing block %d.", i / sizeof(aes_block_t));
+ size_t bytes_left = ARRAYSIZE(kPlaintext) - i;
+ size_t len = sizeof(aes_block_t);
+ if (len > bytes_left) {
+ len = bytes_left;
+ }
+ size_t bytes_left_prev = ARRAYSIZE(kPlaintext) - i + sizeof(aes_block_t);
+ size_t len_prev = sizeof(aes_block_t);
+ if (len_prev > bytes_left_prev) {
+ len_prev = bytes_left_prev;
+ }
+ LOG_INFO("Block len: %d/%d.", len, len_prev);
+
+ aes_block_t in = {0};
+ aes_block_t out = {0};
+ if (i == 0) {
+ memcpy(&in, &kPlaintext[i], len);
+ CHECK(aes_update(NULL, &in) == kAesOk);
+ } else if (i >= ARRAYSIZE(kPlaintext)) {
+ CHECK(aes_update(&out, NULL) == kAesOk);
+ memcpy(cipherptr + i - sizeof(out), &out, len_prev);
+ break;
+ } else {
+ memcpy(&in, &kPlaintext[i], len);
+ CHECK(aes_update(&out, &in) == kAesOk);
+ memcpy(cipherptr + i - sizeof(out), &out, len_prev);
+ }
+ }
+ CHECK_BUFFER_EQ(ciphertext, kCiphertext, ARRAYSIZE(kCiphertext));
+
+ LOG_INFO("Cleaning up.");
+ CHECK(aes_end() == kAesOk);
+
+ return true;
+}