[crypto, test] Add a few tests for AES-GCM encryption.
These tests do not constitute a full test suite, but should be enough to
catch major errors.
Signed-off-by: Jade Philipoom <jadep@google.com>
diff --git a/sw/device/tests/crypto/BUILD b/sw/device/tests/crypto/BUILD
index 928545d..15889cf 100644
--- a/sw/device/tests/crypto/BUILD
+++ b/sw/device/tests/crypto/BUILD
@@ -2,13 +2,30 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-load("//rules:opentitan_test.bzl", "opentitan_functest", "verilator_params")
+load("//rules:opentitan_test.bzl", "cw310_params", "opentitan_functest", "verilator_params")
load("//rules:autogen.bzl", "autogen_cryptotest_header")
load("@ot_python_deps//:requirements.bzl", "requirement")
package(default_visibility = ["//visibility:public"])
opentitan_functest(
+ name = "aes_gcm_functest",
+ srcs = ["aes_gcm_functest.c"],
+ cw310 = cw310_params(
+ timeout = "long",
+ ),
+ verilator = verilator_params(
+ timeout = "long",
+ ),
+ deps = [
+ "//sw/device/lib/crypto/aes_gcm",
+ "//sw/device/lib/runtime:log",
+ "//sw/device/lib/testing/test_framework:check",
+ "//sw/device/lib/testing/test_framework:ottf_main",
+ ],
+)
+
+opentitan_functest(
name = "ecdsa_p256_functest",
srcs = ["ecdsa_p256_functest.c"],
verilator = verilator_params(
diff --git a/sw/device/tests/crypto/aes_gcm_functest.c b/sw/device/tests/crypto/aes_gcm_functest.c
new file mode 100644
index 0000000..37ce9c0
--- /dev/null
+++ b/sw/device/tests/crypto/aes_gcm_functest.c
@@ -0,0 +1,184 @@
+// 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/macros.h"
+#include "sw/device/lib/crypto/aes_gcm/aes_gcm.h"
+#include "sw/device/lib/crypto/drivers/aes.h"
+#include "sw/device/lib/runtime/ibex.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"
+
+typedef struct aes_gcm_test {
+ // Key length.
+ aes_key_len_t key_len;
+ // IV and length (in bytes). If IV length is < 16 then the last bytes are
+ // ignored.
+ size_t iv_len;
+ uint8_t iv[16];
+ // Plaintext and length (in bytes). If the length is not a multiple of 4,
+ // then the most significant bytes of the last word are ignored.
+ size_t plaintext_len;
+ uint8_t *plaintext;
+ // Authenticated data and length (in bytes). If the length is not a multiple
+ // of 4, then the most significant bytes of the last word are ignored.
+ size_t aad_len;
+ uint8_t *aad;
+ // Expected authentication tag.
+ uint8_t expected_tag[16];
+ // Expected ciphertext (same length as plaintext).
+ uint8_t *expected_ciphertext;
+} aes_gcm_test_t;
+
+/**
+ * Randomly-generated 128-bit key for testing.
+ */
+static const uint32_t kKey128[4] = {
+ // Key = f80a6e67211c873793a99d899c31c2e7
+ 0x676e0af8, 0x37871c21, 0x899da993, 0xe7c2319c};
+
+/**
+ * Randomly-generated 256-bit key for testing.
+ */
+static const uint32_t kKey256[8] = {
+ // Key = 76592790eaf6630e670ce5784ff23a1806a1ea76b0977b1542374769247cc4ce
+ 0x90275976, 0x0e63f6ea, 0x78e50c67, 0x183af24f,
+ 0x76eaa106, 0x157b97b0, 0x69473742, 0xcec47c24};
+
+/**
+ * Authenticated data for testing.
+ */
+static const uint32_t kAadLen = 18;
+static uint8_t kAad[20] = {
+ // aad = 'authenticated data'
+ // = 61757468656e746963617465642064617461
+ 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61};
+
+/**
+ * Plaintext for testing.
+ */
+static const uint32_t kPlaintextLen = 32;
+static uint8_t kPlaintext[32] = {
+ // plaintext = 'authenticated and encrypted data'
+ // =
+ // 61757468656e7469636174656420616e6420656e637279707465642064617461
+ 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
+ 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61};
+
+/**
+ * Expected ciphertext for the 256-bit key.
+ */
+static uint8_t kCiphertext256[32] = {
+ // Ciphertext =
+ // 4e6d3a963b076ba0945d29aa836f29b0fa06cdd575aab8233f1df93e80163371
+ 0x4e, 0x6d, 0x3a, 0x96, 0x3b, 0x07, 0x6b, 0xa0, 0x94, 0x5d, 0x29,
+ 0xaa, 0x83, 0x6f, 0x29, 0xb0, 0xfa, 0x06, 0xcd, 0xd5, 0x75, 0xaa,
+ 0xb8, 0x23, 0x3f, 0x1d, 0xf9, 0x3e, 0x80, 0x16, 0x33, 0x71};
+
+static const aes_gcm_test_t kAesGcmTestvectors[3] = {
+ // Empty input, empty aad, 96-bit IV, 128-bit key
+ {
+ .key_len = kAesKeyLen128,
+ .iv_len = 12,
+ .iv =
+ {// IV = 22294cae82d82e44427dfcc3
+ 0x22, 0x29, 0x4c, 0xae, 0x82, 0xd8, 0x2e, 0x44, 0x42, 0x7d, 0xfc,
+ 0xc3},
+ .plaintext_len = 0,
+ .plaintext = NULL,
+ .aad_len = 0,
+ .aad = NULL,
+ .expected_tag =
+ {// Tag = b7aa223a6c75a0976633ce79d9fddf06
+ 0xb7, 0xaa, 0x22, 0x3a, 0x6c, 0x75, 0xa0, 0x97, 0x66, 0x33, 0xce,
+ 0x79, 0xd9, 0xfd, 0xdf, 0x06},
+ .expected_ciphertext = NULL,
+ },
+
+ // Empty input, empty aad, 128-bit IV, 128-bit key
+ {
+ .key_len = kAesKeyLen128,
+ .iv_len = 16,
+ .iv =
+ {// IV = 22294cae82d82e44427dfcc33bacdbec
+ 0x22, 0x29, 0x4c, 0xae, 0x82, 0xd8, 0x2e, 0x44, 0x42, 0x7d, 0xfc,
+ 0xc3, 0x3b, 0xac, 0xdb, 0xec},
+ .plaintext_len = 0,
+ .plaintext = NULL,
+ .aad_len = 0,
+ .aad = NULL,
+ .expected_tag =
+ {// Tag = 4c59f0d420d9eb8669c40ad23b5419ba
+ 0x4c, 0x59, 0xf0, 0xd4, 0x20, 0xd9, 0xeb, 0x86, 0x69, 0xc4, 0x0a,
+ 0xd2, 0x3b, 0x54, 0x19, 0xba},
+ .expected_ciphertext = NULL,
+ },
+
+ // 128-bit IV, 256-bit key, real message and aad
+ {
+ .key_len = kAesKeyLen256,
+ .iv_len = 16,
+ .iv =
+ {// IV = c58aded2e1bbecba8b16a5757e5475bd
+ 0xc5, 0x8a, 0xde, 0xd2, 0xe1, 0xbb, 0xec, 0xba, 0x8b, 0x16, 0xa5,
+ 0x75, 0x7e, 0x54, 0x75, 0xbd},
+ .plaintext_len = kPlaintextLen,
+ .plaintext = kPlaintext,
+ .aad_len = kAadLen,
+ .aad = kAad,
+ .expected_tag =
+ {// Tag = 324895b3d2f656e4fa2f8ce056137061
+ 0x32, 0x48, 0x95, 0xb3, 0xd2, 0xf6, 0x56, 0xe4, 0xfa, 0x2f, 0x8c,
+ 0xe0, 0x56, 0x13, 0x70, 0x61},
+ .expected_ciphertext = kCiphertext256,
+ },
+};
+
+OTTF_DEFINE_TEST_CONFIG();
+bool test_main(void) {
+ for (size_t i = 0; i < ARRAYSIZE(kAesGcmTestvectors); i++) {
+ LOG_INFO("Starting AES-GCM test %d of %d...", i + 1,
+ ARRAYSIZE(kAesGcmTestvectors));
+ const aes_gcm_test_t test = kAesGcmTestvectors[i];
+
+ // Construct key shares by setting first share to full key and second share
+ // to 0. (Note: this is not a secure construction! But it makes debugging
+ // tests easier because there is only one thing to print.)
+ const uint32_t *key_shares[2];
+ const uint32_t share1[8] = {0};
+ key_shares[1] = share1;
+ if (test.key_len == kAesKeyLen128) {
+ key_shares[0] = kKey128;
+ } else if (test.key_len == kAesKeyLen256) {
+ key_shares[0] = kKey256;
+ } else {
+ LOG_ERROR("No key available for key length.");
+ return false;
+ }
+
+ // Call AES-GCM encrypt.
+ uint8_t actual_ciphertext[test.plaintext_len];
+ uint8_t actual_tag[16];
+ uint64_t start = ibex_mcycle_read();
+ aes_error_t err = aes_gcm_encrypt(
+ test.key_len, key_shares, test.iv_len, test.iv, test.plaintext_len,
+ test.plaintext, test.aad_len, test.aad, actual_ciphertext, actual_tag);
+ uint64_t end = ibex_mcycle_read();
+ uint32_t cycles = end - start;
+ LOG_INFO("aes_gcm_encrypt() took %u cycles", cycles);
+ CHECK(err == kAesOk, "AES-GCM encryption returned an error: %08x", err);
+
+ CHECK_ARRAYS_EQ(actual_tag, test.expected_tag, sizeof(test.expected_tag));
+ if (test.plaintext_len > 0) {
+ CHECK_ARRAYS_EQ(actual_ciphertext, test.expected_ciphertext,
+ test.plaintext_len);
+ }
+
+ LOG_INFO("Finished AES-GCM test %d.", i + 1);
+ }
+
+ return true;
+}