1 /*
2 * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #pragma once
8
9 #include <stdbool.h>
10 #include <string.h>
11 #include "soc/hwcrypto_reg.h"
12 #include "hal/aes_types.h"
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18
19 /**
20 * @brief State of AES accelerator, busy, idle or done
21 *
22 */
23 typedef enum {
24 ESP_AES_STATE_IDLE = 0, /* AES accelerator is idle */
25 ESP_AES_STATE_BUSY, /* Transform in progress */
26 ESP_AES_STATE_DONE, /* Transform completed */
27 } esp_aes_state_t;
28
29
30 /**
31 * @brief Write the encryption/decryption key to hardware
32 *
33 * @param key Key to be written to the AES hardware
34 * @param key_word_len Number of words in the key
35 *
36 * @return Number of bytes written to hardware, used for fault injection check
37 */
aes_ll_write_key(const uint8_t * key,size_t key_word_len)38 static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len)
39 {
40 /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */
41 volatile uint8_t key_in_hardware = 0;
42 /* Memcpy to avoid potential unaligned access */
43 uint32_t key_word;
44 for (int i = 0; i < key_word_len; i++) {
45 memcpy(&key_word, key + 4 * i, 4);
46 REG_WRITE(AES_KEY_BASE + i * 4, key_word);
47 key_in_hardware += 4;
48 }
49 return key_in_hardware;
50 }
51
52 /**
53 * @brief Sets the mode
54 *
55 * @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0
56 * @param key_bytes Number of bytes in the key
57 */
aes_ll_set_mode(int mode,uint8_t key_bytes)58 static inline void aes_ll_set_mode(int mode, uint8_t key_bytes)
59 {
60 const uint32_t MODE_DECRYPT_BIT = 4;
61 unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
62
63 /* See TRM for the mapping between keylength and mode bit */
64 REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2));
65 }
66
67 /**
68 * @brief Writes message block to AES hardware
69 *
70 * @param input Block to be written
71 */
aes_ll_write_block(const void * input)72 static inline void aes_ll_write_block(const void *input)
73 {
74 uint32_t input_word;
75
76 for (int i = 0; i < AES_BLOCK_WORDS; i++) {
77 memcpy(&input_word, (uint8_t*)input + 4 * i, 4);
78 REG_WRITE(AES_TEXT_IN_BASE + i * 4, input_word);
79 }
80 }
81
82 /**
83 * @brief Read the AES block
84 *
85 * @param output the output of the transform, length = AES_BLOCK_BYTES
86 */
aes_ll_read_block(void * output)87 static inline void aes_ll_read_block(void *output)
88 {
89 uint32_t output_word;
90 const size_t REG_WIDTH = sizeof(uint32_t);
91
92 for (size_t i = 0; i < AES_BLOCK_WORDS; i++) {
93 output_word = REG_READ(AES_TEXT_OUT_BASE + (i * REG_WIDTH));
94 /* Memcpy to avoid potential unaligned access */
95 memcpy( (uint8_t*)output + i * 4, &output_word, sizeof(output_word));
96 }
97 }
98
99
100 /**
101 * @brief Starts block transform
102 *
103 */
aes_ll_start_transform(void)104 static inline void aes_ll_start_transform(void)
105 {
106 REG_WRITE(AES_TRIGGER_REG, 1);
107 }
108
109 /**
110 * @brief Continue a previous started transform
111 *
112 * @note Only used when doing GCM
113 */
aes_ll_cont_transform(void)114 static inline void aes_ll_cont_transform(void)
115 {
116 REG_WRITE(AES_CONTINUE_REG, 1);
117 }
118
119 /**
120 * @brief Read state of AES accelerator
121 *
122 * @return esp_aes_state_t
123 */
aes_ll_get_state(void)124 static inline esp_aes_state_t aes_ll_get_state(void)
125 {
126 return REG_READ(AES_STATE_REG);
127 }
128
129
130 /**
131 * @brief Set mode of operation
132 *
133 * @note Only used for DMA transforms
134 *
135 * @param mode
136 */
aes_ll_set_block_mode(esp_aes_mode_t mode)137 static inline void aes_ll_set_block_mode(esp_aes_mode_t mode)
138 {
139 REG_WRITE(AES_BLOCK_MODE_REG, mode);
140 }
141
142 /**
143 * @brief Set AES-CTR counter to INC32
144 *
145 * @note Only affects AES-CTR mode
146 *
147 */
aes_ll_set_inc(void)148 static inline void aes_ll_set_inc(void)
149 {
150 REG_WRITE(AES_INC_SEL_REG, 0);
151 }
152
153 /**
154 * @brief Release the DMA
155 *
156 */
aes_ll_dma_exit(void)157 static inline void aes_ll_dma_exit(void)
158 {
159 REG_WRITE(AES_DMA_EXIT_REG, 0);
160 }
161
162 /**
163 * @brief Sets the number of blocks to be transformed
164 *
165 * @note Only used for DMA transforms
166 *
167 * @param num_blocks Number of blocks to transform
168 */
aes_ll_set_num_blocks(size_t num_blocks)169 static inline void aes_ll_set_num_blocks(size_t num_blocks)
170 {
171 REG_WRITE(AES_BLOCK_NUM_REG, num_blocks);
172 }
173
174 /*
175 * Write IV to hardware iv registers
176 */
aes_ll_set_iv(const uint8_t * iv)177 static inline void aes_ll_set_iv(const uint8_t *iv)
178 {
179 uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE);
180 uint32_t iv_word;
181
182 for (int i = 0; i < IV_WORDS; i++ ) {
183 /* Memcpy to avoid potential unaligned access */
184 memcpy(&iv_word, iv + 4 * i, sizeof(iv_word));
185 REG_WRITE(®_addr_buf[i], iv_word);
186 }
187 }
188
189 /*
190 * Read IV from hardware iv registers
191 */
aes_ll_read_iv(uint8_t * iv)192 static inline void aes_ll_read_iv(uint8_t *iv)
193 {
194 uint32_t iv_word;
195 const size_t REG_WIDTH = sizeof(uint32_t);
196
197 for (size_t i = 0; i < IV_WORDS; i++) {
198 iv_word = REG_READ(AES_IV_BASE + (i * REG_WIDTH));
199 /* Memcpy to avoid potential unaligned access */
200 memcpy(iv + i * 4, &iv_word, sizeof(iv_word));
201 }
202 }
203
204 /**
205 * @brief Enable or disable DMA mode
206 *
207 * @param enable true to enable, false to disable.
208 */
aes_ll_dma_enable(bool enable)209 static inline void aes_ll_dma_enable(bool enable)
210 {
211 REG_WRITE(AES_DMA_ENABLE_REG, enable);
212 }
213
214 /**
215 * @brief Enable or disable transform completed interrupt
216 *
217 * @param enable true to enable, false to disable.
218 */
aes_ll_interrupt_enable(bool enable)219 static inline void aes_ll_interrupt_enable(bool enable)
220 {
221 REG_WRITE(AES_INT_ENA_REG, enable);
222 }
223
224 /**
225 * @brief Clears the interrupt
226 *
227 */
aes_ll_interrupt_clear(void)228 static inline void aes_ll_interrupt_clear(void)
229 {
230 REG_WRITE(AES_INT_CLEAR_REG, 1);
231 }
232
233 /**
234 * @brief Reads the AES-GCM hash sub-key H
235 *
236 * @param gcm_hash hash value
237 */
aes_ll_gcm_read_hash(uint8_t * gcm_hash)238 static inline void aes_ll_gcm_read_hash(uint8_t *gcm_hash)
239 {
240 const size_t REG_WIDTH = sizeof(uint32_t);
241 uint32_t hash_word;
242
243 for (size_t i = 0; i < AES_BLOCK_WORDS; i++) {
244 hash_word = REG_READ(AES_H_BASE + (i * REG_WIDTH));
245 /* Memcpy to avoid potential unaligned access */
246 memcpy(gcm_hash + i * 4, &hash_word, sizeof(hash_word));
247 }
248 }
249
250 /**
251 * @brief Sets the number of Additional Authenticated Data (AAD) blocks
252 *
253 * @note Only affects AES-GCM
254 *
255 * @param aad_num_blocks the number of Additional Authenticated Data (AAD) blocks
256 */
aes_ll_gcm_set_aad_num_blocks(size_t aad_num_blocks)257 static inline void aes_ll_gcm_set_aad_num_blocks(size_t aad_num_blocks)
258 {
259 REG_WRITE(AES_AAD_BLOCK_NUM_REG, aad_num_blocks);
260 }
261
262 /**
263 * @brief Sets the J0 value, for more information see the GCM subchapter in the TRM
264 *
265 * @note Only affects AES-GCM
266 *
267 * @param j0 J0 value
268 */
aes_ll_gcm_set_j0(const uint8_t * j0)269 static inline void aes_ll_gcm_set_j0(const uint8_t *j0)
270 {
271 uint32_t *reg_addr_buf = (uint32_t *)(AES_J_BASE);
272 uint32_t j0_word;
273
274 for (int i = 0; i < AES_BLOCK_WORDS; i++ ) {
275 /* Memcpy to avoid potential unaligned access */
276 memcpy(&j0_word, j0 + 4 * i, sizeof(j0_word));
277 REG_WRITE(®_addr_buf[i], j0_word);
278 }
279 }
280
281 /**
282 * @brief Sets the number of effective bits of incomplete blocks in plaintext/cipertext.
283 *
284 * @note Only affects AES-GCM
285 *
286 * @param num_valid_bits the number of effective bits of incomplete blocks in plaintext/cipertext.
287 */
aes_ll_gcm_set_num_valid_bit(size_t num_valid_bits)288 static inline void aes_ll_gcm_set_num_valid_bit(size_t num_valid_bits)
289 {
290 REG_WRITE(AES_BIT_VALID_NUM_REG, num_valid_bits);
291 }
292
293 /**
294 * @brief Read the tag after a AES-GCM transform
295 *
296 * @param tag Pointer to where to store the result with length TAG_WORDS
297 */
aes_ll_gcm_read_tag(uint8_t * tag)298 static inline void aes_ll_gcm_read_tag(uint8_t *tag)
299 {
300 uint32_t tag_word;
301 const size_t REG_WIDTH = sizeof(uint32_t);
302
303 for (size_t i = 0; i < TAG_WORDS; i++) {
304 tag_word = REG_READ(AES_T_BASE + (i * REG_WIDTH));
305 /* Memcpy to avoid potential unaligned access */
306 memcpy(tag + i * 4, &tag_word, sizeof(tag_word));
307 }
308 }
309
310 #ifdef __cplusplus
311 }
312 #endif
313