Software APIs
dif_aes.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
6
7#include <stddef.h>
8
11
12#include "hw/top/aes_regs.h" // Generated.
13
14/*
15 * From: https://opentitan.org/book/hw/ip/aes/doc/registers.html,
16 * aes.CTRL.
17 */
18
19/**
20 * Waits for the given AES status flag to be set the given value.
21 *
22 * @param aes An aes DIF handle.
23 * @param flag Status flag to query.
24 * @param value The status flag value.
25 */
26#define AES_WAIT_FOR_STATUS(aes_, flag_, value_) \
27 while (mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET, \
28 (flag_)) != value_) { \
29 }
30
31static bool aes_idle(const dif_aes_t *aes) {
32 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
33 AES_STATUS_IDLE_BIT);
34}
35
36static bool aes_stalled(const dif_aes_t *aes) {
37 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
38 AES_STATUS_STALL_BIT);
39}
40
41static bool aes_output_lost(const dif_aes_t *aes) {
42 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
43 AES_STATUS_OUTPUT_LOST_BIT);
44}
45
46static bool aes_output_valid(const dif_aes_t *aes) {
47 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
48 AES_STATUS_OUTPUT_VALID_BIT);
49}
50
51static bool aes_input_ready(const dif_aes_t *aes) {
52 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
53 AES_STATUS_INPUT_READY_BIT);
54}
55
56static bool aes_alert_fatal(const dif_aes_t *aes) {
57 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
58 AES_STATUS_ALERT_FATAL_FAULT_BIT);
59}
60
61static bool aes_alert_recoverable(const dif_aes_t *aes) {
62 return mmio_region_get_bit32(aes->base_addr, AES_STATUS_REG_OFFSET,
63 AES_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_BIT);
64}
65
66static void aes_shadowed_write(mmio_region_t base, ptrdiff_t offset,
67 uint32_t value) {
68 mmio_region_write32(base, offset, value);
69 mmio_region_write32(base, offset, value);
70}
71
72static void aes_clear_internal_state(const dif_aes_t *aes) {
73 // Make sure AES is idle before clearing.
74 AES_WAIT_FOR_STATUS(aes, AES_STATUS_IDLE_BIT, true);
75
76 // It should be fine to clobber the Control register. Only
77 // `AES_CTRL_SHADOWED_MANUAL_OPERATION` bit must be set.
78 uint32_t ctrl_reg =
79 bitfield_bit32_write(0, AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, true);
80
81 aes_shadowed_write(aes->base_addr, AES_CTRL_SHADOWED_REG_OFFSET, ctrl_reg);
82
83 uint32_t trigger_reg =
84 bitfield_bit32_write(0, AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true);
85
86 trigger_reg =
87 bitfield_bit32_write(trigger_reg, AES_TRIGGER_DATA_OUT_CLEAR_BIT, true);
88
89 mmio_region_write32(aes->base_addr, AES_TRIGGER_REG_OFFSET, trigger_reg);
90
91 // Make sure AES is cleared before proceeding (may take multiple cycles).
92 AES_WAIT_FOR_STATUS(aes, AES_STATUS_IDLE_BIT, true);
93}
94
95/**
96 * Configures AES. Is used by every `dif_aes_start_<mode>` function.
97 *
98 * @param aes AES state data.
99 * @param transaction Configuration data, common across all Cipher modes.
100 * @return `dif_result_t`.
101 */
102static dif_result_t configure(const dif_aes_t *aes,
103 const dif_aes_transaction_t *transaction) {
104 uint32_t reg = bitfield_field32_write(0, AES_CTRL_SHADOWED_OPERATION_FIELD,
105 transaction->operation);
106
107 reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_MODE_FIELD,
108 transaction->mode);
109
110 reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_KEY_LEN_FIELD,
111 transaction->key_len);
112
113 reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_PRNG_RESEED_RATE_FIELD,
114 transaction->mask_reseeding);
115
116 bool flag = transaction->manual_operation == kDifAesManualOperationManual;
117 reg = bitfield_bit32_write(reg, AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, flag);
118
119 flag = transaction->key_provider == kDifAesKeySideload;
120 reg = bitfield_bit32_write(reg, AES_CTRL_SHADOWED_SIDELOAD_BIT, flag);
121
122 aes_shadowed_write(aes->base_addr, AES_CTRL_SHADOWED_REG_OFFSET, reg);
123
124 return kDifOk;
125}
126
127/**
128 * Configures the auxiliary options for AES.
129 *
130 * @param aes AES state data.
131 * @param transaction Configuration data, common across all Cipher modes.
132 * @return `dif_result_t`.
133 */
134static dif_result_t configure_aux(const dif_aes_t *aes,
135 const dif_aes_transaction_t *transaction) {
136 // Return an error in case the register is locked with different values.
137 uint32_t reg_val =
138 mmio_region_read32(aes->base_addr, AES_CTRL_AUX_REGWEN_REG_OFFSET);
139 if (!reg_val) {
140 reg_val =
141 mmio_region_read32(aes->base_addr, AES_CTRL_AUX_SHADOWED_REG_OFFSET);
142 if (bitfield_bit32_read(
143 reg_val, AES_CTRL_AUX_SHADOWED_KEY_TOUCH_FORCES_RESEED_BIT) !=
144 transaction->reseed_on_key_change ||
145 bitfield_bit32_read(reg_val, AES_CTRL_AUX_SHADOWED_FORCE_MASKS_BIT) !=
146 transaction->force_masks ||
147 bitfield_bit32_read(
148 reg_val, AES_CTRL_AUX_SHADOWED_KEEP_START_TRIGGER_HIGH_BIT) !=
149 transaction->keep_start_trigger_high) {
150 return kDifError;
151 }
152 return kDifOk;
153 }
154
155 reg_val =
156 bitfield_bit32_write(0, AES_CTRL_AUX_SHADOWED_KEY_TOUCH_FORCES_RESEED_BIT,
157 transaction->reseed_on_key_change);
158 reg_val = bitfield_bit32_write(reg_val, AES_CTRL_AUX_SHADOWED_FORCE_MASKS_BIT,
159 transaction->force_masks);
160 reg_val = bitfield_bit32_write(
161 reg_val, AES_CTRL_AUX_SHADOWED_KEEP_START_TRIGGER_HIGH_BIT,
162 transaction->keep_start_trigger_high);
163 aes_shadowed_write(aes->base_addr, AES_CTRL_AUX_SHADOWED_REG_OFFSET, reg_val);
164
165 reg_val = transaction->ctrl_aux_lock == false;
166 mmio_region_write32(aes->base_addr, AES_CTRL_AUX_REGWEN_REG_OFFSET, reg_val);
167
168 return kDifOk;
169}
170
171/**
172 * Sets all "sub-registers" of `aes.KEY`, `aes.IV` or `aes.DATA_IN` multiregs.
173 *
174 * @param aes AES state data.
175 * @param data Data to be written into multi-reg registers.
176 * @param regs_num Number of "sub-registers" in the multireg.
177 * @param reg0_offset Offset to the "sub-register 0" in the multireg.
178 */
179static void aes_set_multireg(const dif_aes_t *aes, const uint32_t *data,
180 size_t regs_num, ptrdiff_t reg0_offset) {
181 for (int i = 0; i < regs_num; ++i) {
182 ptrdiff_t offset = reg0_offset + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
183
184 mmio_region_write32(aes->base_addr, offset, data[i]);
185 }
186}
187
188static void aes_read_multireg(const dif_aes_t *aes, uint32_t *data,
189 size_t regs_num, ptrdiff_t reg0_offset) {
190 for (int i = 0; i < regs_num; ++i) {
191 ptrdiff_t offset = reg0_offset + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
192
193 data[i] = mmio_region_read32(aes->base_addr, offset);
194 }
195}
196
197dif_result_t dif_aes_reset(const dif_aes_t *aes) {
198 if (aes == NULL) {
199 return kDifBadArg;
200 }
201
202 aes_clear_internal_state(aes);
203
204 // Any values would do, illegal values chosen here.
205 uint32_t reg = bitfield_field32_write(0, AES_CTRL_SHADOWED_OPERATION_FIELD,
206 AES_CTRL_SHADOWED_OPERATION_MASK);
207
208 reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_MODE_FIELD,
209 AES_CTRL_SHADOWED_MODE_VALUE_AES_NONE);
210
211 reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_KEY_LEN_FIELD,
212 AES_CTRL_SHADOWED_KEY_LEN_MASK);
213
214 aes_shadowed_write(aes->base_addr, AES_CTRL_SHADOWED_REG_OFFSET, reg);
215
216 return kDifOk;
217}
218
219dif_result_t dif_aes_start(const dif_aes_t *aes,
220 const dif_aes_transaction_t *transaction,
221 const dif_aes_key_share_t *key,
222 const dif_aes_iv_t *iv) {
223 if (aes == NULL || transaction == NULL ||
224 (iv == NULL && transaction->mode != kDifAesModeEcb) ||
225 (key == NULL &&
226 transaction->key_provider == kDifAesKeySoftwareProvided)) {
227 return kDifBadArg;
228 }
229
230 if (!aes_idle(aes)) {
231 return kDifUnavailable;
232 }
233
234 dif_result_t result = configure(aes, transaction);
235 if (result != kDifOk) {
236 return result;
237 }
238
239 result = configure_aux(aes, transaction);
240 if (result != kDifOk) {
241 return result;
242 }
243
244 if (transaction->mode == kDifAesModeGcm) {
245 // Put AES-GCM into init mode.
246 DIF_RETURN_IF_ERROR(dif_aes_set_gcm_phase(
247 aes, AES_CTRL_GCM_SHADOWED_PHASE_VALUE_GCM_INIT, 16));
248 }
249
250 if (transaction->key_provider == kDifAesKeySoftwareProvided) {
251 aes_set_multireg(aes, &key->share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
252 AES_KEY_SHARE0_0_REG_OFFSET);
253
254 aes_set_multireg(aes, &key->share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
255 AES_KEY_SHARE1_0_REG_OFFSET);
256 }
257
258 if (transaction->mode != kDifAesModeEcb) {
259 // Make sure AES is idle before providing the IV. Depending on the
260 // configuration, updating the key might cause the AES to become non-idle
261 // and reseed the internal PRNGs.
262 AES_WAIT_FOR_STATUS(aes, AES_STATUS_IDLE_BIT, true);
263 aes_set_multireg(aes, &iv->iv[0], AES_IV_MULTIREG_COUNT,
264 AES_IV_0_REG_OFFSET);
265 }
266
267 return kDifOk;
268}
269
270dif_result_t dif_aes_end(const dif_aes_t *aes) {
271 if (aes == NULL) {
272 return kDifBadArg;
273 }
274
275 if (!aes_idle(aes)) {
276 return kDifUnavailable;
277 }
278
279 aes_clear_internal_state(aes);
280
281 return kDifOk;
282}
283
284dif_result_t dif_aes_load_data(const dif_aes_t *aes,
285 const dif_aes_data_t data) {
286 if (aes == NULL) {
287 return kDifBadArg;
288 }
289
290 if (!aes_input_ready(aes)) {
291 return kDifUnavailable;
292 }
293
294 aes_set_multireg(aes, &data.data[0], AES_DATA_IN_MULTIREG_COUNT,
295 AES_DATA_IN_0_REG_OFFSET);
296
297 return kDifOk;
298}
299
300dif_result_t dif_aes_read_output(const dif_aes_t *aes, dif_aes_data_t *data) {
301 if (aes == NULL || data == NULL) {
302 return kDifBadArg;
303 }
304
305 if (!aes_output_valid(aes)) {
306 return kDifError;
307 }
308
309 aes_read_multireg(aes, data->data, AES_DATA_OUT_MULTIREG_COUNT,
310 AES_DATA_OUT_0_REG_OFFSET);
311
312 return kDifOk;
313}
314
315dif_result_t dif_aes_set_gcm_phase(const dif_aes_t *aes, uint32_t phase,
316 size_t num_valid_bytes) {
317 if (aes == NULL) {
318 return kDifBadArg;
319 }
320
321 if (!aes_idle(aes)) {
322 return kDifUnavailable;
323 }
324
325 uint32_t reg = bitfield_field32_write(
326 0, AES_CTRL_GCM_SHADOWED_NUM_VALID_BYTES_FIELD, num_valid_bytes);
327 // Put AES-GCM into the given phase.
328 reg = bitfield_field32_write(reg, AES_CTRL_GCM_SHADOWED_PHASE_FIELD, phase);
329 aes_shadowed_write(aes->base_addr, AES_CTRL_GCM_SHADOWED_REG_OFFSET, reg);
330
331 return kDifOk;
332}
333
334dif_result_t dif_aes_load_gcm_tag_len(const dif_aes_t *aes, uint64_t len_ptx,
335 uint64_t len_aad) {
336 if (aes == NULL) {
337 return kDifBadArg;
338 }
339
340 // Ensure that the INPUT_READY bit in STATUS is 1.
341 if (!aes_input_ready(aes)) {
342 return kDifUnavailable;
343 }
344
345 // len_aad_ptx = len(aad) || len(ptx)
346 dif_aes_data_t len_aad_ptx;
347 len_aad_ptx.data[0] = __builtin_bswap32((uint32_t)(len_aad >> 32));
348 len_aad_ptx.data[1] = __builtin_bswap32((uint32_t)(len_aad & 0xFFFFFFFF));
349 len_aad_ptx.data[2] = __builtin_bswap32((uint32_t)(len_ptx >> 32));
350 len_aad_ptx.data[3] = __builtin_bswap32((uint32_t)(len_ptx & 0xFFFFFFFF));
351
352 aes_set_multireg(aes, &len_aad_ptx.data[0], AES_DATA_IN_MULTIREG_COUNT,
353 AES_DATA_IN_0_REG_OFFSET);
354
355 return kDifOk;
356}
357
358dif_result_t dif_aes_process_data(const dif_aes_t *aes,
359 const dif_aes_data_t *plain_text,
360 dif_aes_data_t *cipher_text,
361 size_t block_count) {
362 if (aes == NULL || plain_text == NULL || cipher_text == NULL ||
363 block_count == 0) {
364 return kDifBadArg;
365 }
366
367 // The algorithm below just makes sense for at least 2 blocks. Otherwise
368 // it is better to use the `load_data` and `read_output` functions.
369 if (block_count < 2) {
370 DIF_RETURN_IF_ERROR(dif_aes_load_data(aes, plain_text[0]));
371 return dif_aes_read_output(aes, cipher_text);
372 }
373
374 // Ensure that the INPUT_READY bit in STATUS is 1.
375 if (!aes_input_ready(aes)) {
376 return kDifUnavailable;
377 }
378
379 // Write Input Data Block 0 to the Input Data registers DATA_IN_0 - DATA_IN_3.
380 aes_set_multireg(aes, plain_text[0].data, AES_DATA_IN_MULTIREG_COUNT,
381 AES_DATA_IN_0_REG_OFFSET);
382
383 // Wait for the INPUT_READY bit in STATUS to become 1, i.e. wait for the AES
384 // unit to load Input Data Block 0 into the internal state register and start
385 // operation.
386 AES_WAIT_FOR_STATUS(aes, AES_STATUS_INPUT_READY_BIT, true);
387 // Then for every Data Block I=0,..,N-3, software must:
388 for (size_t i = 0; i < block_count; ++i) {
389 // Write Input Data Block I+1 into the Input Data register. There is no need
390 // to explicitly check INPUT_READY as in the same cycle OUTPUT_VALID becomes
391 // 1, the current input is loaded in (meaning INPUT_READY becomes 1 one
392 // cycle later).
393 if (i + 1 < block_count) {
394 aes_set_multireg(aes, plain_text[i + 1].data, AES_DATA_IN_MULTIREG_COUNT,
395 AES_DATA_IN_0_REG_OFFSET);
396 }
397
398 // Wait for the OUTPUT_VALID bit in STATUS to become 1, i.e., wait for the
399 // AES unit to finish encryption/decryption of Block I. The AES unit then
400 // directly starts processing the previously input block I+1.
401 AES_WAIT_FOR_STATUS(aes, AES_STATUS_OUTPUT_VALID_BIT, true);
402
403 // Read Output Data Block I from the Output Data registers DATA_OUT_0 -
404 // DATA_OUT_3. Each register must be read at least once.
405 aes_read_multireg(aes, cipher_text[i].data, AES_DATA_OUT_MULTIREG_COUNT,
406 AES_DATA_OUT_0_REG_OFFSET);
407 }
408
409 return kDifOk;
410}
411
413 if (aes == NULL) {
414 return kDifBadArg;
415 }
416
417 uint32_t reg = bitfield_bit32_write(0, trigger, true);
418 mmio_region_write32(aes->base_addr, AES_TRIGGER_REG_OFFSET, reg);
419
420 return kDifOk;
421}
422
423dif_result_t dif_aes_get_status(const dif_aes_t *aes, dif_aes_status_t flag,
424 bool *set) {
425 if (aes == NULL || set == NULL) {
426 return kDifBadArg;
427 }
428
429 switch (flag) {
431 *set = aes_idle(aes);
432 break;
434 *set = aes_stalled(aes);
435 break;
437 *set = aes_output_lost(aes);
438 break;
440 *set = aes_output_valid(aes);
441 break;
443 *set = aes_input_ready(aes);
444 break;
446 *set = aes_alert_fatal(aes);
447 break;
449 *set = aes_alert_recoverable(aes);
450 break;
451 default:
452 return kDifError;
453 }
454
455 return kDifOk;
456}
457
458dif_result_t dif_aes_read_iv(const dif_aes_t *aes, dif_aes_iv_t *iv) {
459 if (aes == NULL || iv == NULL) {
460 return kDifBadArg;
461 }
462
463 if (!aes_idle(aes)) {
464 return kDifUnavailable;
465 }
466
467 for (int i = 0; i < AES_IV_MULTIREG_COUNT; ++i) {
468 ptrdiff_t offset =
469 AES_IV_0_REG_OFFSET + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
470
471 iv->iv[i] = mmio_region_read32(aes->base_addr, offset);
472 }
473 return kDifOk;
474}
475
476dif_result_t dif_aes_load_iv(const dif_aes_t *aes, const dif_aes_iv_t iv) {
477 if (aes == NULL) {
478 return kDifBadArg;
479 }
480
481 if (!aes_idle(aes)) {
482 return kDifUnavailable;
483 }
484
485 aes_set_multireg(aes, &iv.iv[0], AES_IV_MULTIREG_COUNT, AES_IV_0_REG_OFFSET);
486
487 return kDifOk;
488}