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 "aes_regs.h" // Generated.
13 
14 /*
15  * From: https://docs.opentitan.org/hw/ip/aes/doc/index.html#register-table,
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 
31 static 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 
36 static 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 
41 static 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 
46 static 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 
51 static 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 
56 static 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 
61 static 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 
66 static 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 
72 static 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  */
102 static 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  */
134 static 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);
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  return kDifError;
148  }
149  return kDifOk;
150  }
151 
152  reg_val =
153  bitfield_bit32_write(0, AES_CTRL_AUX_SHADOWED_KEY_TOUCH_FORCES_RESEED_BIT,
154  transaction->reseed_on_key_change);
155  reg_val = bitfield_bit32_write(reg_val, AES_CTRL_AUX_SHADOWED_FORCE_MASKS_BIT,
156  transaction->force_masks);
157  aes_shadowed_write(aes->base_addr, AES_CTRL_AUX_SHADOWED_REG_OFFSET, reg_val);
158 
159  reg_val = transaction->ctrl_aux_lock == false;
160  mmio_region_write32(aes->base_addr, AES_CTRL_AUX_REGWEN_REG_OFFSET, reg_val);
161 
162  return kDifOk;
163 }
164 
165 /**
166  * Sets all "sub-registers" of `aes.KEY`, `aes.IV` or `aes.DATA_IN` multiregs.
167  *
168  * @param aes AES state data.
169  * @param data Data to be written into multi-reg registers.
170  * @param regs_num Number of "sub-registers" in the multireg.
171  * @param reg0_offset Offset to the "sub-register 0" in the multireg.
172  */
173 static void aes_set_multireg(const dif_aes_t *aes, const uint32_t *data,
174  size_t regs_num, ptrdiff_t reg0_offset) {
175  for (int i = 0; i < regs_num; ++i) {
176  ptrdiff_t offset = reg0_offset + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
177 
178  mmio_region_write32(aes->base_addr, offset, data[i]);
179  }
180 }
181 
182 static void aes_read_multireg(const dif_aes_t *aes, uint32_t *data,
183  size_t regs_num, ptrdiff_t reg0_offset) {
184  for (int i = 0; i < regs_num; ++i) {
185  ptrdiff_t offset = reg0_offset + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
186 
187  data[i] = mmio_region_read32(aes->base_addr, offset);
188  }
189 }
190 
192  if (aes == NULL) {
193  return kDifBadArg;
194  }
195 
196  aes_clear_internal_state(aes);
197 
198  // Any values would do, illegal values chosen here.
199  uint32_t reg = bitfield_field32_write(0, AES_CTRL_SHADOWED_OPERATION_FIELD,
200  AES_CTRL_SHADOWED_OPERATION_MASK);
201 
202  reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_MODE_FIELD,
203  AES_CTRL_SHADOWED_MODE_VALUE_AES_NONE);
204 
205  reg = bitfield_field32_write(reg, AES_CTRL_SHADOWED_KEY_LEN_FIELD,
206  AES_CTRL_SHADOWED_KEY_LEN_MASK);
207 
208  aes_shadowed_write(aes->base_addr, AES_CTRL_SHADOWED_REG_OFFSET, reg);
209 
210  return kDifOk;
211 }
212 
214  const dif_aes_transaction_t *transaction,
215  const dif_aes_key_share_t *key,
216  const dif_aes_iv_t *iv) {
217  if (aes == NULL || transaction == NULL ||
218  (iv == NULL && transaction->mode != kDifAesModeEcb) ||
219  (key == NULL &&
220  transaction->key_provider == kDifAesKeySoftwareProvided)) {
221  return kDifBadArg;
222  }
223 
224  if (!aes_idle(aes)) {
225  return kDifUnavailable;
226  }
227 
228  dif_result_t result = configure(aes, transaction);
229  if (result != kDifOk) {
230  return result;
231  }
232 
233  result = configure_aux(aes, transaction);
234  if (result != kDifOk) {
235  return result;
236  }
237 
238  if (transaction->key_provider == kDifAesKeySoftwareProvided) {
239  aes_set_multireg(aes, &key->share0[0], AES_KEY_SHARE0_MULTIREG_COUNT,
240  AES_KEY_SHARE0_0_REG_OFFSET);
241 
242  aes_set_multireg(aes, &key->share1[0], AES_KEY_SHARE1_MULTIREG_COUNT,
243  AES_KEY_SHARE1_0_REG_OFFSET);
244  }
245 
246  if (transaction->mode != kDifAesModeEcb) {
247  // Make sure AES is idle before providing the IV. Depending on the
248  // configuration, updating the key might cause the AES to become non-idle
249  // and reseed the internal PRNGs.
250  AES_WAIT_FOR_STATUS(aes, AES_STATUS_IDLE_BIT, true);
251  aes_set_multireg(aes, &iv->iv[0], AES_IV_MULTIREG_COUNT,
252  AES_IV_0_REG_OFFSET);
253  }
254 
255  return kDifOk;
256 }
257 
259  if (aes == NULL) {
260  return kDifBadArg;
261  }
262 
263  if (!aes_idle(aes)) {
264  return kDifUnavailable;
265  }
266 
267  aes_clear_internal_state(aes);
268 
269  return kDifOk;
270 }
271 
273  const dif_aes_data_t data) {
274  if (aes == NULL) {
275  return kDifBadArg;
276  }
277 
278  if (!aes_input_ready(aes)) {
279  return kDifUnavailable;
280  }
281 
282  aes_set_multireg(aes, &data.data[0], AES_DATA_IN_MULTIREG_COUNT,
283  AES_DATA_IN_0_REG_OFFSET);
284 
285  return kDifOk;
286 }
287 
289  if (aes == NULL || data == NULL) {
290  return kDifBadArg;
291  }
292 
293  if (!aes_output_valid(aes)) {
294  return kDifError;
295  }
296 
297  aes_read_multireg(aes, data->data, AES_DATA_OUT_MULTIREG_COUNT,
298  AES_DATA_OUT_0_REG_OFFSET);
299 
300  return kDifOk;
301 }
302 
304  const dif_aes_data_t *plain_text,
305  dif_aes_data_t *cipher_text,
306  size_t block_count) {
307  if (aes == NULL || plain_text == NULL || cipher_text == NULL ||
308  block_count == 0) {
309  return kDifBadArg;
310  }
311 
312  // The algorithm below just makes sense for at least 2 blocks. Otherwise
313  // it is better to use the `load_data` and `read_output` functions.
314  if (block_count < 2) {
315  DIF_RETURN_IF_ERROR(dif_aes_load_data(aes, plain_text[0]));
316  return dif_aes_read_output(aes, cipher_text);
317  }
318 
319  // Ensure that the INPUT_READY bit in STATUS is 1.
320  if (!aes_input_ready(aes)) {
321  return kDifUnavailable;
322  }
323 
324  // Write Input Data Block 0 to the Input Data registers DATA_IN_0 - DATA_IN_3.
325  aes_set_multireg(aes, plain_text[0].data, AES_DATA_IN_MULTIREG_COUNT,
326  AES_DATA_IN_0_REG_OFFSET);
327 
328  // Wait for the INPUT_READY bit in STATUS to become 1, i.e. wait for the AES
329  // unit to load Input Data Block 0 into the internal state register and start
330  // operation.
331  AES_WAIT_FOR_STATUS(aes, AES_STATUS_INPUT_READY_BIT, true);
332  // Then for every Data Block I=0,..,N-3, software must:
333  for (size_t i = 0; i < block_count; ++i) {
334  // Write Input Data Block I+1 into the Input Data register. There is no need
335  // to explicitly check INPUT_READY as in the same cycle OUTPUT_VALID becomes
336  // 1, the current input is loaded in (meaning INPUT_READY becomes 1 one
337  // cycle later).
338  if (i + 1 < block_count) {
339  aes_set_multireg(aes, plain_text[i + 1].data, AES_DATA_IN_MULTIREG_COUNT,
340  AES_DATA_IN_0_REG_OFFSET);
341  }
342 
343  // Wait for the OUTPUT_VALID bit in STATUS to become 1, i.e., wait for the
344  // AES unit to finish encryption/decryption of Block I. The AES unit then
345  // directly starts processing the previously input block I+1.
346  AES_WAIT_FOR_STATUS(aes, AES_STATUS_OUTPUT_VALID_BIT, true);
347 
348  // Read Output Data Block I from the Output Data registers DATA_OUT_0 -
349  // DATA_OUT_3. Each register must be read at least once.
350  aes_read_multireg(aes, cipher_text[i].data, AES_DATA_OUT_MULTIREG_COUNT,
351  AES_DATA_OUT_0_REG_OFFSET);
352  }
353 
354  return kDifOk;
355 }
356 
358  if (aes == NULL) {
359  return kDifBadArg;
360  }
361 
362  uint32_t reg = bitfield_bit32_write(0, trigger, true);
363  mmio_region_write32(aes->base_addr, AES_TRIGGER_REG_OFFSET, reg);
364 
365  return kDifOk;
366 }
367 
369  bool *set) {
370  if (aes == NULL || set == NULL) {
371  return kDifBadArg;
372  }
373 
374  switch (flag) {
375  case kDifAesStatusIdle:
376  *set = aes_idle(aes);
377  break;
378  case kDifAesStatusStall:
379  *set = aes_stalled(aes);
380  break;
382  *set = aes_output_lost(aes);
383  break;
385  *set = aes_output_valid(aes);
386  break;
388  *set = aes_input_ready(aes);
389  break;
391  *set = aes_alert_fatal(aes);
392  break;
394  *set = aes_alert_recoverable(aes);
395  break;
396  default:
397  return kDifError;
398  }
399 
400  return kDifOk;
401 }
402 
404  if (aes == NULL || iv == NULL) {
405  return kDifBadArg;
406  }
407 
408  if (!aes_idle(aes)) {
409  return kDifUnavailable;
410  }
411 
412  for (int i = 0; i < AES_IV_MULTIREG_COUNT; ++i) {
413  ptrdiff_t offset =
414  AES_IV_0_REG_OFFSET + (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
415 
416  iv->iv[i] = mmio_region_read32(aes->base_addr, offset);
417  }
418  return kDifOk;
419 }