Software APIs
aes_force_prng_reseed_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 
5 #include "hw/ip/aes/model/aes_modes.h"
8 #include "sw/device/lib/base/multibits.h"
11 #include "sw/device/lib/dif/dif_csrng_shared.h"
14 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
17 #include "sw/device/lib/testing/aes_testutils.h"
18 #include "sw/device/lib/testing/csrng_testutils.h"
19 #include "sw/device/lib/testing/entropy_testutils.h"
20 #include "sw/device/lib/testing/rv_core_ibex_testutils.h"
21 #include "sw/device/lib/testing/test_framework/check.h"
24 
26 
27 OTTF_DEFINE_TEST_CONFIG();
28 
29 static dif_aes_t aes;
31 enum {
32  kAesNumBlocks = 8,
33  // NumBytes in one block is 4x8 i.e. 32 bits in 1 block
34  kDifAesBlockNumBytes = 4,
35  kDisableEntropyAtStartEn = 1,
36 };
37 
38 static const uint8_t kKeyShare1[16] = {
39  0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
40  0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
41 };
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 static dif_edn_t edn0, edn1;
45 static dif_csrng_t csrng;
46 static dif_entropy_src_t entropy_src;
47 
48 // Function to disable entropy complex
49 status_t disable_entropy_complex(void) {
50  // Using entropy test utility to stop all EDN0, EDN1, CSRNG, and the Entropy
51  // Source
52  TRY(entropy_testutils_stop_all());
53  LOG_INFO("The entire entropy complex is stopped");
54  return OK_STATUS();
55 }
56 
57 // Function to enable entropy complex
58 status_t enable_entropy_complex(void) {
59  // Using entropy test utility to enable all EDN0, EDN1, CSRNG, and the
60  // Entropy Source
61  TRY(entropy_testutils_auto_mode_init());
62  LOG_INFO("The entire entropy complex is enabled");
63  return OK_STATUS();
64 }
65 
66 // Function to generate a new key based on provided index value
67 void generate_new_key(dif_aes_key_share_t *key, int index) {
68  uint8_t new_key_share0[sizeof(kAesModesKey128)];
69  // Generate new key share0 by XOR-ing base key with kKeyShare1*index
70  for (size_t i = 0; i < sizeof(kAesModesKey128); ++i) {
71  new_key_share0[i] = kAesModesKey128[i] ^ kKeyShare1[i] * (uint8_t)(index);
72  }
73  // Update the key shares
74  memcpy(key->share0, new_key_share0, sizeof(key->share0));
75  memcpy(key->share1, kKeyShare1, sizeof(key->share1));
76 }
77 
78 status_t execute_test(void) {
79  bool aes_idle = false;
80  bool input_ready = false;
81  bool output_valid = false;
82 
83  LOG_INFO(
84  "Testing aes_prng_reseed_test with number of blocks: %d (Block 0 to %d), "
85  "and disabling entropy at start enable"
86  ": %d",
87  kAesNumBlocks, kAesNumBlocks - 1, kDisableEntropyAtStartEn);
88  // Initialize AES
89  TRY(dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
90  TRY(dif_aes_reset(&aes));
91  // Initialize EDN0, EDN1, CSRNG and Entropy Source
92  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
93  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
95  &csrng));
96  TRY(dif_entropy_src_init(
98 
99  // Generate key with index 0
100  generate_new_key(&key, 0);
101 
102  // Prepare transaction
103  dif_aes_transaction_t transaction = {
104  .operation = kDifAesOperationEncrypt,
105  .mode = kDifAesModeEcb,
106  .key_len = kDifAesKey128,
107  .key_provider = kDifAesKeySoftwareProvided,
108  .mask_reseeding = kDifAesReseedPerBlock,
109  .manual_operation = kDifAesManualOperationManual,
110  .reseed_on_key_change = true,
111  .force_masks = true,
112  .ctrl_aux_lock = false,
113  };
114 
115  dif_aes_data_t plain_text[kAesNumBlocks];
116  dif_aes_data_t cipher_text[kAesNumBlocks];
117 
118  // Initialize plaintext data dynamically
119  // Create plaintext with random data
120  dif_rv_core_ibex_t rv_core_ibex;
121  TRY(dif_rv_core_ibex_init(
123  &rv_core_ibex));
124  for (uint32_t i = 0; i < ARRAYSIZE(plain_text); ++i) {
125  for (uint32_t j = 0; j < kDifAesBlockNumBytes; ++j) {
126  uint32_t rand;
127  TRY(rv_core_ibex_testutils_get_rnd_data(&rv_core_ibex, 2000, &rand));
128  plain_text[i].data[j] = rand;
129  }
130  }
131 
132  // Start the AES operation
133  // Wait for AES to be idle before starting encryption
134  aes_idle = false;
135  do {
136  TRY(dif_aes_get_status(&aes, kDifAesStatusIdle, &aes_idle));
137  } while (!aes_idle);
138 
139  TRY(dif_aes_start(&aes, &transaction, &key, NULL));
140 
141  // Disabling entropy complex
142  if (kDisableEntropyAtStartEn == 1) {
143  LOG_INFO(
144  "Disabling entropy complex to induce AES stall before starting AES");
145  CHECK_STATUS_OK(disable_entropy_complex());
146  busy_spin_micros(500);
147  }
148 
149  // Start encryption process
150  for (int i = 0; i < kAesNumBlocks; ++i) {
151  if (transaction.manual_operation == kDifAesManualOperationManual) {
152  // Wait for AES to be idle before starting encryption
154  }
155 
156  // Wait for input ready
157  input_ready = false;
158  do {
159  TRY(dif_aes_get_status(&aes, kDifAesStatusInputReady, &input_ready));
160  } while (!input_ready);
161 
162  // Load data
163  TRY(dif_aes_load_data(&aes, plain_text[i]));
164 
165  // Trigger AES reseed request, specific for manual operation case as per
166  // documentation
167  if (transaction.manual_operation == kDifAesManualOperationManual) {
169  }
170 
171  // Check for stall after entropy disabled
172  if (i == 0 && kDisableEntropyAtStartEn == 1) {
173  LOG_INFO(
174  "Checking AES status OutputValid status after stopping "
175  "EDN and CSRNG");
176  output_valid = false;
177  TRY(dif_aes_get_status(&aes, kDifAesStatusOutputValid, &output_valid));
178  CHECK(!output_valid,
179  "ERROR:AES encryption AES encryption generated output_valid after "
180  "stopping entropy indicating no stall!");
181  LOG_INFO(
182  "AES encryption is waiting for output_valid as expected at block "
183  "%d",
184  i);
185 
186  LOG_INFO("Enabling entropy complex at block %d", i);
187  CHECK_STATUS_OK(enable_entropy_complex());
188  busy_spin_micros(500);
189  }
190 
191  // Wait for the AES module to resume and produce output valid
192  output_valid = false;
193  do {
194  TRY(dif_aes_get_status(&aes, kDifAesStatusOutputValid, &output_valid));
195  } while (!output_valid);
196 
197  // Read output data
198  TRY(dif_aes_read_output(&aes, &cipher_text[i]));
199  }
200 
201  // Finish the AES encryption operation
202  LOG_INFO("End AES encryption operation");
203  TRY(dif_aes_end(&aes));
204 
205  // Wait for AES to be idle before starting decryption
206  aes_idle = false;
207  do {
208  TRY(dif_aes_get_status(&aes, kDifAesStatusIdle, &aes_idle));
209  } while (!aes_idle);
210  LOG_INFO("AES module is idle");
211 
212  return OK_STATUS();
213 }
214 
215 bool test_main(void) {
216  LOG_INFO("Entering AES aes_force_prng_reseed_test Test");
217 
218  return status_ok(execute_test());
219 }