Software APIs
keymgr_sideload_aes_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
11 #include "sw/device/lib/testing/aes_testutils.h"
12 #include "sw/device/lib/testing/keymgr_testutils.h"
13 #include "sw/device/lib/testing/kmac_testutils.h"
14 #include "sw/device/lib/testing/test_framework/check.h"
16 
18 #include "kmac_regs.h" // Generated.
19 
20 #define TIMEOUT (1000 * 1000)
21 
22 // Plaintext 16B block matching that input `00112233445566778899aabbccddeeff` to
23 // the AES C model. Refer to `hw/ip/aes/rtl/aes_cipher_core.sv` for mapping
24 // plaintext input to the hardware input.
25 static const uint32_t kPlainText[] = {
26  0x33221100, // word 0.
27  0x77665544, // word 1.
28  0xbbaa9988, // word 2.
29  0xffeeddcc, // word 3.
30 };
31 
32 // Expected AES cipher result will be computed at the SV side and overwritten to
33 // this constant.
34 static volatile const uint8_t kAESDigest[16] = {0};
35 
36 static dif_keymgr_t keymgr;
37 static dif_kmac_t kmac;
38 
39 OTTF_DEFINE_TEST_CONFIG();
40 
41 /**
42  * Initializes all DIF handles for each peripheral used in this test.
43  */
44 static void init_peripheral_handles(void) {
45  CHECK_DIF_OK(
46  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
47  CHECK_DIF_OK(dif_keymgr_init(
49 }
50 
51 status_t aes_crypt(dif_aes_t aes, dif_aes_data_t in_data,
52  enum dif_aes_operation crypt_op, dif_aes_data_t *out_data) {
53  // Setup ECB encryption/decryption transaction using sideload key.
54  dif_aes_transaction_t transaction = {
55  .operation = crypt_op,
56  .mode = kDifAesModeEcb,
57  .key_len = kDifAesKey256,
58  .key_provider = kDifAesKeySideload,
59  .mask_reseeding = kDifAesReseedPer64Block,
60  .manual_operation = kDifAesManualOperationManual,
61  .reseed_on_key_change = false,
62  .ctrl_aux_lock = false,
63  };
64 
65  if (crypt_op == kDifAesOperationEncrypt) {
66  LOG_INFO("Encrypting with 256-bit AES sideload key in ECB mode.");
67  } else if (crypt_op == kDifAesOperationDecrypt) {
68  LOG_INFO("Decrypting with 256-bit AES sideload key in ECB mode.");
69  }
70 
71  CHECK_DIF_OK(dif_aes_start(&aes, &transaction, NULL, NULL));
72  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusInputReady, true, TIMEOUT);
73  CHECK_DIF_OK(dif_aes_load_data(&aes, in_data));
74 
75  // Trigger the AES encryption and wait for it to complete.
76  CHECK_DIF_OK(dif_aes_trigger(&aes, kDifAesTriggerStart));
77  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusOutputValid, true, TIMEOUT);
78 
79  CHECK_DIF_OK(dif_aes_read_output(&aes, out_data));
80 
81  // Finish the ECB encryption or decryption transaction.
82  LOG_INFO("Finished operation with AES sideloaded key.");
83  CHECK_DIF_OK(dif_aes_end(&aes));
84  return OK_STATUS();
85 }
86 
87 void aes_test(void) {
88  // Generate sideload key for AES interface at current keymgr state.
89  dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams;
90  sideload_params.dest = kDifKeymgrVersionedKeyDestAes;
91 
92  // Get the maximum key version supported by the keymgr in its current state.
93  uint32_t max_key_version;
94  CHECK_STATUS_OK(
95  keymgr_testutils_max_key_version_get(&keymgr, &max_key_version));
96 
97  if (sideload_params.version > max_key_version) {
98  LOG_INFO("Key version %d is greater than the maximum key version %d",
99  sideload_params.version, max_key_version);
100  LOG_INFO("Setting key version to the maximum key version %d",
101  max_key_version);
102  sideload_params.version = max_key_version;
103  }
104 
105  const char *state_name;
106  CHECK_STATUS_OK(keymgr_testutils_state_string_get(&keymgr, &state_name));
107 
108  CHECK_STATUS_OK(
109  keymgr_testutils_generate_versioned_key(&keymgr, sideload_params));
110  LOG_INFO("Keymgr generated HW output for Aes at %s State", state_name);
111 
112  // Initialize AES.
113  dif_aes_t aes;
114  CHECK_DIF_OK(
116  CHECK_DIF_OK(dif_aes_reset(&aes));
117 
118  dif_aes_data_t in_data_plain;
119  dif_aes_data_t out_data_cipher;
120  memcpy(in_data_plain.data, kPlainText, sizeof(kPlainText));
121 
122  // Encrypt using sideload key.
123  CHECK_STATUS_OK(
124  aes_crypt(aes, in_data_plain, kDifAesOperationEncrypt, &out_data_cipher));
125  // Verify that the ciphertext is different from the plaintext.
126  CHECK_ARRAYS_NE(out_data_cipher.data, kPlainText, ARRAYSIZE(kPlainText));
127 
128  // Only if running test in DV simulation: compare ciphertext generated
129  // with the HW core vs. that generated by the reference C model.
130  if (kDeviceType == kDeviceSimDV) {
131  LOG_INFO("AES Plaintext (HW Core): 0x%08x%08x%08x%08x",
132  in_data_plain.data[0], in_data_plain.data[1],
133  in_data_plain.data[2], in_data_plain.data[3]);
134  LOG_INFO("AES Ciphertext (HW Core): 0x%08x%08x%08x%08x",
135  out_data_cipher.data[3], out_data_cipher.data[2],
136  out_data_cipher.data[1], out_data_cipher.data[0]);
137  LOG_INFO(
138  "AES Expected Ciphertext (from C model): "
139  "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
140  kAESDigest[15], kAESDigest[14], kAESDigest[13], kAESDigest[12],
141  kAESDigest[11], kAESDigest[10], kAESDigest[9], kAESDigest[8],
142  kAESDigest[7], kAESDigest[6], kAESDigest[5], kAESDigest[4],
143  kAESDigest[3], kAESDigest[2], kAESDigest[1], kAESDigest[0]);
144  CHECK_ARRAYS_EQ(out_data_cipher.data, (uint32_t *)kAESDigest,
145  ARRAYSIZE(out_data_cipher.data));
146  }
147 
148  // Decrypt using sideload key.
149  dif_aes_data_t out_data_plain;
150  CHECK_STATUS_OK(aes_crypt(aes, out_data_cipher, kDifAesOperationDecrypt,
151  &out_data_plain));
152  CHECK_ARRAYS_EQ(out_data_plain.data, kPlainText, ARRAYSIZE(kPlainText));
153 
154  // Clear the key in the keymgr and decrypt the ciphertext again.
155  LOG_INFO("Clearing the sideloaded key.");
156  CHECK_DIF_OK(
158 
159  // Disable "clear the key" toggle, so that the sideload key port is stable.
160  // Otherwise, the sideload port is continuously overwritten by fresh
161  // randomness every clock cycle.
162  CHECK_DIF_OK(
164 
165  // Decrypt again after clearing the sideload key and verify that output is not
166  // the same as previous.
167  CHECK_STATUS_OK(aes_crypt(aes, out_data_cipher, kDifAesOperationDecrypt,
168  &out_data_plain));
169  CHECK_ARRAYS_NE(out_data_plain.data, kPlainText, ARRAYSIZE(kPlainText));
170 
171  // Generate the same key again and check that encryption result is identical
172  // as the first.
173  CHECK_STATUS_OK(
174  keymgr_testutils_generate_versioned_key(&keymgr, sideload_params));
175  LOG_INFO("Keymgr generated HW output for Aes at %s State", state_name);
176 
177  dif_aes_data_t out_data_second_cipher;
178  CHECK_STATUS_OK(aes_crypt(aes, in_data_plain, kDifAesOperationEncrypt,
179  &out_data_second_cipher));
180 
181  // Verify that the ciphertext is identical to the first one generated.
182  CHECK_ARRAYS_EQ(out_data_cipher.data, out_data_second_cipher.data,
183  ARRAYSIZE(out_data_cipher.data));
184 }
185 
186 bool test_main(void) {
187  init_peripheral_handles();
188 
189  // Configure the keymgr to generate an AES key.
190  CHECK_STATUS_OK(keymgr_testutils_initialize(&keymgr, &kmac));
191 
192  // Run the AES test.
193  aes_test();
194 
195  return true;
196 }