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