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 // Wait for the IDLE bit in STATUS to become 1, i.e. wait for the AES
245 // unit handle any triggers resulting from writing the main control register.
246 AES_WAIT_FOR_STATUS(aes, AES_STATUS_IDLE_BIT, true);
247
248 if (transaction->mode == kDifAesModeGcm) {
249 // Put AES-GCM into init mode.
250 DIF_RETURN_IF_ERROR(dif_aes_set_gcm_phase(
251 aes, AES_CTRL_GCM_SHADOWED_PHASE_VALUE_GCM_INIT, 16));
252 }
253
254 if (transaction->key_provider == kDifAesKeySoftwareProvided) {
255 aes_set_multireg(aes, &key->share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
256 AES_KEY_SHARE0_0_REG_OFFSET);
257
258 aes_set_multireg(aes, &key->share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
259 AES_KEY_SHARE1_0_REG_OFFSET);
260 }
261
262 if (transaction->mode != kDifAesModeEcb) {
263 // Make sure AES is idle before providing the IV. Depending on the
264 // configuration, updating the key might cause the AES to become non-idle
265 // and reseed the internal PRNGs.
266 AES_WAIT_FOR_STATUS(aes, AES_STATUS_IDLE_BIT, true);
267 aes_set_multireg(aes, &iv->iv[0], AES_IV_MULTIREG_COUNT,
268 AES_IV_0_REG_OFFSET);
269 }
270
271 return kDifOk;
272}
273
274dif_result_t dif_aes_end(const dif_aes_t *aes) {
275 if (aes == NULL) {
276 return kDifBadArg;
277 }
278
279 if (!aes_idle(aes)) {
280 return kDifUnavailable;
281 }
282
283 aes_clear_internal_state(aes);
284
285 return kDifOk;
286}
287
288dif_result_t dif_aes_load_data(const dif_aes_t *aes,
289 const dif_aes_data_t data) {
290 if (aes == NULL) {
291 return kDifBadArg;
292 }
293
294 if (!aes_input_ready(aes)) {
295 return kDifUnavailable;
296 }
297
298 aes_set_multireg(aes, &data.data[0], AES_DATA_IN_MULTIREG_COUNT,
299 AES_DATA_IN_0_REG_OFFSET);
300
301 return kDifOk;
302}
303
304dif_result_t dif_aes_read_output(const dif_aes_t *aes, dif_aes_data_t *data) {
305 if (aes == NULL || data == NULL) {
306 return kDifBadArg;
307 }
308
309 if (!aes_output_valid(aes)) {
310 return kDifError;
311 }
312
313 aes_read_multireg(aes, data->data, AES_DATA_OUT_MULTIREG_COUNT,
314 AES_DATA_OUT_0_REG_OFFSET);
315
316 return kDifOk;
317}
318
319dif_result_t dif_aes_set_gcm_phase(const dif_aes_t *aes, uint32_t phase,
320 size_t num_valid_bytes) {
321 if (aes == NULL) {
322 return kDifBadArg;
323 }
324
325 if (!aes_idle(aes)) {
326 return kDifUnavailable;
327 }
328
329 uint32_t reg = bitfield_field32_write(
330 0, AES_CTRL_GCM_SHADOWED_NUM_VALID_BYTES_FIELD, num_valid_bytes);
331 // Put AES-GCM into the given phase.
332 reg = bitfield_field32_write(reg, AES_CTRL_GCM_SHADOWED_PHASE_FIELD, phase);
333 aes_shadowed_write(aes->base_addr, AES_CTRL_GCM_SHADOWED_REG_OFFSET, reg);
334
335 return kDifOk;
336}
337
338dif_result_t dif_aes_load_gcm_tag_len(const dif_aes_t *aes, uint64_t len_ptx,
339 uint64_t len_aad) {
340 if (aes == NULL) {
341 return kDifBadArg;
342 }
343
344 // Ensure that the INPUT_READY bit in STATUS is 1.
345 if (!aes_input_ready(aes)) {
346 return kDifUnavailable;
347 }
348
349 // len_aad_ptx = len(aad) || len(ptx)
350 dif_aes_data_t len_aad_ptx;
351 len_aad_ptx.data[0] = __builtin_bswap32((uint32_t)(len_aad >> 32));
352 len_aad_ptx.data[1] = __builtin_bswap32((uint32_t)(len_aad & 0xFFFFFFFF));
353 len_aad_ptx.data[2] = __builtin_bswap32((uint32_t)(len_ptx >> 32));
354 len_aad_ptx.data[3] = __builtin_bswap32((uint32_t)(len_ptx & 0xFFFFFFFF));
355
356 aes_set_multireg(aes, &len_aad_ptx.data[0], AES_DATA_IN_MULTIREG_COUNT,
357 AES_DATA_IN_0_REG_OFFSET);
358
359 return kDifOk;
360}
361
362dif_result_t dif_aes_process_data(const dif_aes_t *aes,
363 const dif_aes_data_t *plain_text,
364 dif_aes_data_t *cipher_text,
365 size_t block_count) {
366 if (aes == NULL || plain_text == NULL || cipher_text == NULL ||
367 block_count == 0) {
368 return kDifBadArg;
369 }
370
371 // The algorithm below just makes sense for at least 2 blocks. Otherwise
372 // it is better to use the `load_data` and `read_output` functions.
373 if (block_count < 2) {
374 DIF_RETURN_IF_ERROR(dif_aes_load_data(aes, plain_text[0]));
375 return dif_aes_read_output(aes, cipher_text);
376 }
377
378 // Ensure that the INPUT_READY bit in STATUS is 1.
379 if (!aes_input_ready(aes)) {
380 return kDifUnavailable;
381 }
382
383 // Write Input Data Block 0 to the Input Data registers DATA_IN_0 - DATA_IN_3.
384 aes_set_multireg(aes, plain_text[0].data, AES_DATA_IN_MULTIREG_COUNT,
385 AES_DATA_IN_0_REG_OFFSET);
386
387 // Wait for the INPUT_READY bit in STATUS to become 1, i.e. wait for the AES
388 // unit to load Input Data Block 0 into the internal state register and start
389 // operation.
390 AES_WAIT_FOR_STATUS(aes, AES_STATUS_INPUT_READY_BIT, true);
391 // Then for every Data Block I=0,..,N-3, software must:
392 for (size_t i = 0; i < block_count; ++i) {
393 // Write Input Data Block I+1 into the Input Data register. There is no need
394 // to explicitly check INPUT_READY as in the same cycle OUTPUT_VALID becomes
395 // 1, the current input is loaded in (meaning INPUT_READY becomes 1 one
396 // cycle later).
397 if (i + 1 < block_count) {
398 aes_set_multireg(aes, plain_text[i + 1].data, AES_DATA_IN_MULTIREG_COUNT,
399 AES_DATA_IN_0_REG_OFFSET);
400 }
401
402 // Wait for the OUTPUT_VALID bit in STATUS to become 1, i.e., wait for the
403 // AES unit to finish encryption/decryption of Block I. The AES unit then
404 // directly starts processing the previously input block I+1.
405 AES_WAIT_FOR_STATUS(aes, AES_STATUS_OUTPUT_VALID_BIT, true);
406
407 // Read Output Data Block I from the Output Data registers DATA_OUT_0 -
408 // DATA_OUT_3. Each register must be read at least once.
409 aes_read_multireg(aes, cipher_text[i].data, AES_DATA_OUT_MULTIREG_COUNT,
410 AES_DATA_OUT_0_REG_OFFSET);
411 }
412
413 return kDifOk;
414}
415
417 if (aes == NULL) {
418 return kDifBadArg;
419 }
420
421 uint32_t reg = bitfield_bit32_write(0, trigger, true);
422 mmio_region_write32(aes->base_addr, AES_TRIGGER_REG_OFFSET, reg);
423
424 return kDifOk;
425}
426
427dif_result_t dif_aes_get_status(const dif_aes_t *aes, dif_aes_status_t flag,
428 bool *set) {
429 if (aes == NULL || set == NULL) {
430 return kDifBadArg;
431 }
432
433 switch (flag) {
435 *set = aes_idle(aes);
436 break;
438 *set = aes_stalled(aes);
439 break;
441 *set = aes_output_lost(aes);
442 break;
444 *set = aes_output_valid(aes);
445 break;
447 *set = aes_input_ready(aes);
448 break;
450 *set = aes_alert_fatal(aes);
451 break;
453 *set = aes_alert_recoverable(aes);
454 break;
455 default:
456 return kDifError;
457 }
458
459 return kDifOk;
460}
461
462dif_result_t dif_aes_read_iv(const dif_aes_t *aes, dif_aes_iv_t *iv) {
463 if (aes == NULL || iv == NULL) {
464 return kDifBadArg;
465 }
466
467 if (!aes_idle(aes)) {
468 return kDifUnavailable;
469 }
470
471 for (int i = 0; i < AES_IV_MULTIREG_COUNT; ++i) {
472 ptrdiff_t offset =
473 AES_IV_0_REG_OFFSET + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
474
475 iv->iv[i] = mmio_region_read32(aes->base_addr, offset);
476 }
477 return kDifOk;
478}
479
480dif_result_t dif_aes_load_iv(const dif_aes_t *aes, const dif_aes_iv_t iv) {
481 if (aes == NULL) {
482 return kDifBadArg;
483 }
484
485 if (!aes_idle(aes)) {
486 return kDifUnavailable;
487 }
488
489 aes_set_multireg(aes, &iv.iv[0], AES_IV_MULTIREG_COUNT, AES_IV_0_REG_OFFSET);
490
491 return kDifOk;
492}