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(&reg_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(&reg_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