Software APIs
aes_testutils.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 "sw/device/lib/testing/aes_testutils.h"
6 
7 #include "hw/ip/aes/model/aes_modes.h"
9 #include "sw/device/lib/testing/test_framework/check.h"
10 
11 #ifndef OPENTITAN_IS_ENGLISHBREAKFAST
12 #include "sw/device/lib/dif/dif_csrng_shared.h"
13 #include "sw/device/lib/testing/csrng_testutils.h"
14 
15 #include "csrng_regs.h" // Generated
16 #endif
17 
18 // `extern` declarations to give the inline functions in the
19 // corresponding header a link location.
20 
21 extern bool aes_testutils_get_status(dif_aes_t *aes, dif_aes_status_t flag);
22 
23 // The mask share, used to mask kKey. Note that the masking should not be done
24 // manually. Software is expected to get the key in two shares right from the
25 // beginning.
26 static const uint8_t kKeyShare1[] = {
27  0x0f, 0x1f, 0x2f, 0x3F, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf,
28  0xbf, 0xcf, 0xdf, 0xef, 0xff, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a,
29  0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
30 };
31 
33 
34 enum {
35  kAesTestutilsTimeout = (10 * 1000 * 1000),
36 };
37 
38 #ifndef OPENTITAN_IS_ENGLISHBREAKFAST
39 /**
40  * Constants for switching AES masking off.
41  */
42 enum {
43  kCsrngBlockLen = 4,
44  kCsrngKeyLen = 8,
45  kEdnSeedMaterialLen = 12,
46 };
47 
48 // CSRNG needs to constantly output these bits to EDN. If reseeded to an all-
49 // zero value the AES masking PRNG will output an all-zero vector. It will
50 // further keep this value if the CTRL_AUX_SHADOWED.FORCE_MASKS bit is set.
51 const uint32_t kAesMaskingPrngZeroOutputSeed[kCsrngBlockLen] = {
52  0x00000000, 0x000000000, 0x00000000, 0x00000000};
53 
54 // Seed material for instantiate command. The CTR_DRBG construction
55 // implemented by CSRNG produces
56 //
57 // key = 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
58 // 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
59 //
60 // V = 6d 9f 08 eb 2a 2e 27 7a - b4 89 84 cf f1 ab 9a 09
61 //
62 // from this seed material upon instantiate. The key is arbitrarily chosen.
63 // Encrypting V using this key then gives the required
64 // kAesMaskingPrngZeroOutputSeed above.
65 const uint32_t kEdnSeedMaterialInstantiate[kEdnSeedMaterialLen] = {
66  0x84adaf86, 0x652b7141, 0x1d880d0e, 0x1fff0b21, 0xa6ee8307, 0x1f57dfc8,
67  0x59757d79, 0xdeb6522e, 0xc8c67d84, 0xa16abefa, 0xc34030be, 0x530e88f8};
68 
69 // V and key after instantiate.
70 const uint32_t kCsrngVInstantiate[kCsrngBlockLen] = {0xf1ab9a08, 0xb48984cf,
71  0x2a2e277a, 0x6d9f08eb};
72 const uint32_t kCsrngKeyInstantiate[kCsrngKeyLen] = {
73  0x1c1d1e1f, 0x18191a1b, 0x14151617, 0x10111213,
74  0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203};
75 
76 // V and key after generate.
77 const uint32_t kCsrngVGenerate[kCsrngBlockLen] = {0x654600bd, 0xf0c32787,
78  0x3eb52114, 0x8a1e0dce};
79 const uint32_t kCsrngKeyGenerate[kCsrngKeyLen] = {
80  0xff6589b5, 0x4bb8e5f9, 0x62847098, 0x1e9f9cd1,
81  0x3c005fbd, 0x9a1b6e70, 0xe30eb080, 0x71dea927};
82 
83 // Seed material for reseed command. After one generate, this seed material
84 // will bring the key and V of CSRNG back to the state after instantiate.
85 // I.e., one can again run one generate to produce the seed required for AES
86 // (see kAesMaskingPrngZeroOutputSeed).
87 const uint32_t kEdnSeedMaterialReseed[kEdnSeedMaterialLen] = {
88  0x96994362, 0x7ef8f0b9, 0x5b5332dc, 0xd0df9b12, 0x96dfbaa9, 0xac0b5af7,
89  0xec2504be, 0xb00fb68c, 0xf37e0a7f, 0x88172eec, 0x4e4b5f58, 0xfec120c0};
90 
91 status_t aes_testutils_masking_prng_zero_output_seed(const dif_csrng_t *csrng,
92  const dif_edn_t *edn0) {
93  // Shutdown EDN0 and CSRNG
94  TRY(dif_edn_stop(edn0));
95  TRY(dif_csrng_stop(csrng));
96 
97  // Re-enable CSRNG
98  TRY(dif_csrng_configure(csrng));
99 
100  // Re-enable EDN0 and configure it to produce the seed that if loaded into AES
101  // causes the AES masking PRNG to output and all-zero output.
102  dif_edn_auto_params_t edn0_params = {
103  .instantiate_cmd =
104  {
105  .cmd = csrng_cmd_header_build(kCsrngAppCmdInstantiate,
107  kEdnSeedMaterialLen,
108  /*generate_len=*/0),
109  .seed_material =
110  {
111  .len = kEdnSeedMaterialLen,
112  },
113  },
114  .reseed_cmd =
115  {
116  .cmd = csrng_cmd_header_build(kCsrngAppCmdReseed,
118  kEdnSeedMaterialLen,
119  /*generate_len=*/0),
120  .seed_material =
121  {
122  .len = kEdnSeedMaterialLen,
123  },
124  },
125  .generate_cmd =
126  {
127  .cmd = csrng_cmd_header_build(kCsrngAppCmdGenerate,
129  /*cmd_len=*/0,
130  /*generate_len=*/1),
131  .seed_material =
132  {
133  .len = 0,
134  },
135  },
136  .reseed_interval = 1, // Reseed after every single generate.
137  };
139  kEdnSeedMaterialInstantiate, sizeof(kEdnSeedMaterialInstantiate));
140  memcpy(edn0_params.reseed_cmd.seed_material.data, kEdnSeedMaterialReseed,
141  sizeof(kEdnSeedMaterialReseed));
142  TRY(dif_edn_set_auto_mode(edn0, edn0_params));
143  return OK_STATUS();
144 }
145 
146 status_t aes_testutils_csrng_kat(const dif_csrng_t *csrng) {
147  // Instantiate CSRNG with seed material suitable for switching the AES masking
148  // off.
149  dif_csrng_seed_material_t seed_material_instantiate = {
150  .seed_material_len = 12,
151  };
152  memcpy(seed_material_instantiate.seed_material, kEdnSeedMaterialInstantiate,
153  sizeof(kEdnSeedMaterialInstantiate));
154  dif_csrng_internal_state_t expected_state_instantiate = {
155  .reseed_counter = 0,
156  .instantiated = true,
157  .fips_compliance = false,
158  };
159  memcpy(expected_state_instantiate.v, kCsrngVInstantiate,
160  sizeof(kCsrngVInstantiate));
161  memcpy(expected_state_instantiate.key, kCsrngKeyInstantiate,
162  sizeof(kCsrngKeyInstantiate));
163  TRY(csrng_testutils_kat_instantiate(csrng, false, &seed_material_instantiate,
164  &expected_state_instantiate));
165 
166  // Generate one block containing the required seed for the AES masking PRNG
167  // to output an all-zero vector.
168  dif_csrng_internal_state_t expected_state_generate = {
169  .reseed_counter = 1,
170  .instantiated = true,
171  .fips_compliance = false,
172  };
173  memcpy(expected_state_generate.v, kCsrngVGenerate, sizeof(kCsrngVGenerate));
174  memcpy(expected_state_generate.key, kCsrngKeyGenerate,
175  sizeof(kCsrngKeyGenerate));
176  TRY(csrng_testutils_kat_generate(csrng, 1, kCsrngBlockLen,
177  kAesMaskingPrngZeroOutputSeed,
178  &expected_state_generate));
179 
180  // Reseed the CSRNG instance to produce the required seed for the AES masking
181  // PRNG to output an all-zero vector upon the next generate command.
182  dif_csrng_seed_material_t seed_material_reseed = {
183  .seed_material_len = 12,
184  };
185  memcpy(seed_material_reseed.seed_material, kEdnSeedMaterialReseed,
186  sizeof(kEdnSeedMaterialReseed));
187  dif_csrng_internal_state_t expected_state_reseed = {
188  .reseed_counter = 0,
189  .instantiated = true,
190  .fips_compliance = false,
191  };
192  memcpy(expected_state_reseed.v, kCsrngVInstantiate,
193  sizeof(kCsrngVInstantiate));
194  memcpy(expected_state_reseed.key, kCsrngKeyInstantiate,
195  sizeof(kCsrngKeyInstantiate));
196  TRY(csrng_testutils_kat_reseed(csrng, &seed_material_reseed,
197  &expected_state_reseed));
198 
199  // Generate one block containing the required seed for the AES masking PRNG
200  // to output an all-zero vector.
201  TRY(csrng_testutils_kat_generate(csrng, 1, kCsrngBlockLen,
202  kAesMaskingPrngZeroOutputSeed,
203  &expected_state_generate));
204  return OK_STATUS();
205 }
206 #endif
207 
208 status_t aes_testutils_setup_encryption(dif_aes_transaction_t transaction,
209  dif_aes_t *aes) {
210  // Mask the key. Note that this should not be done manually. Software is
211  // expected to get the key in two shares right from the beginning.
212  uint8_t key_share0[sizeof(kAesModesKey256)];
213  for (int i = 0; i < sizeof(kAesModesKey256); ++i) {
214  key_share0[i] = kAesModesKey256[i] ^ kKeyShare1[i];
215  }
216 
217  // "Convert" key share byte arrays to `dif_aes_key_share_t`.
218  memcpy(key.share0, key_share0, sizeof(key.share0));
219  memcpy(key.share1, kKeyShare1, sizeof(key.share1));
220 
221  AES_TESTUTILS_WAIT_FOR_STATUS(aes, kDifAesStatusIdle, true,
222  kAesTestutilsTimeout);
223  CHECK_DIF_OK(dif_aes_start(aes, &transaction, &key, NULL));
224 
225  // "Convert" plain data byte arrays to `dif_aes_data_t`.
226  dif_aes_data_t in_data_plain;
227  memcpy(in_data_plain.data, kAesModesPlainText, sizeof(in_data_plain.data));
228 
229  // Load the plain text to trigger the encryption operation.
230  AES_TESTUTILS_WAIT_FOR_STATUS(aes, kDifAesStatusIdle, true,
231  kAesTestutilsTimeout);
232  AES_TESTUTILS_WAIT_FOR_STATUS(aes, kDifAesStatusInputReady, true,
233  kAesTestutilsTimeout);
234  CHECK_DIF_OK(dif_aes_load_data(aes, in_data_plain));
235 
236  return OK_STATUS();
237 }
238 
239 status_t aes_testutils_decrypt_ciphertext(dif_aes_transaction_t transaction,
240  dif_aes_t *aes) {
241  // Read out the produced cipher text.
242  dif_aes_data_t out_data;
243  CHECK_DIF_OK(dif_aes_read_output(aes, &out_data));
244 
245  // Finish the ECB encryption transaction.
246  CHECK_DIF_OK(dif_aes_end(aes));
247  CHECK_ARRAYS_EQ((uint8_t *)out_data.data, kAesModesCipherTextEcb256,
248  sizeof(out_data.data));
249 
250  // Setup ECB decryption transaction.
251  transaction.operation = kDifAesOperationDecrypt;
252  CHECK_DIF_OK(dif_aes_start(aes, &transaction, &key, NULL));
253 
254  // Load the previously produced cipher text to start the decryption operation.
255  AES_TESTUTILS_WAIT_FOR_STATUS(aes, kDifAesStatusInputReady, true,
256  kAesTestutilsTimeout);
257  CHECK_DIF_OK(dif_aes_load_data(aes, out_data));
258 
259  // Read out the produced plain text.
260  AES_TESTUTILS_WAIT_FOR_STATUS(aes, kDifAesStatusOutputValid, true,
261  kAesTestutilsTimeout);
262  CHECK_DIF_OK(dif_aes_read_output(aes, &out_data));
263 
264  // Finish the ECB encryption transaction.
265  CHECK_DIF_OK(dif_aes_end(aes));
266 
267  CHECK_ARRAYS_EQ((uint8_t *)out_data.data, kAesModesPlainText,
268  sizeof(out_data.data));
269  return OK_STATUS();
270 }