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
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
21extern 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.
26static 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
34enum {
35 kAesTestutilsTimeout = (10 * 1000 * 1000),
36};
37
38#ifndef OPENTITAN_IS_ENGLISHBREAKFAST
39/**
40 * Constants for switching AES masking off.
41 */
42enum {
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.
51const 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.
65const 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.
70const uint32_t kCsrngVInstantiate[kCsrngBlockLen] = {0xf1ab9a08, 0xb48984cf,
71 0x2a2e277a, 0x6d9f08eb};
72const uint32_t kCsrngKeyInstantiate[kCsrngKeyLen] = {
73 0x1c1d1e1f, 0x18191a1b, 0x14151617, 0x10111213,
74 0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203};
75
76// V and key after generate.
77const uint32_t kCsrngVGenerate[kCsrngBlockLen] = {0x654600bd, 0xf0c32787,
78 0x3eb52114, 0x8a1e0dce};
79const 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).
87const uint32_t kEdnSeedMaterialReseed[kEdnSeedMaterialLen] = {
88 0x96994362, 0x7ef8f0b9, 0x5b5332dc, 0xd0df9b12, 0x96dfbaa9, 0xac0b5af7,
89 0xec2504be, 0xb00fb68c, 0xf37e0a7f, 0x88172eec, 0x4e4b5f58, 0xfec120c0};
90
91status_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 };
138 memcpy(edn0_params.instantiate_cmd.seed_material.data,
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
146status_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
208status_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
239status_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}