1 /*
2 * ESP hardware accelerated SHA1/256/512 implementation
3 * based on mbedTLS FIPS-197 compliant version.
4 *
5 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6 * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd
7 * SPDX-License-Identifier: Apache-2.0
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License"); you may
10 * not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 */
22 /*
23 * The SHA-1 standard was published by NIST in 1993.
24 *
25 * http://www.itl.nist.gov/fipspubs/fip180-1.htm
26 */
27
28 #include <string.h>
29 #include <stdio.h>
30 #include <sys/lock.h>
31
32 #include "esp_log.h"
33 #include "esp_crypto_lock.h"
34 #include "esp_attr.h"
35 #include "soc/lldesc.h"
36 #include "soc/cache_memory.h"
37 #include "soc/periph_defs.h"
38
39 #include "freertos/FreeRTOS.h"
40 #include "freertos/semphr.h"
41
42 #include "driver/periph_ctrl.h"
43 #include "sys/param.h"
44
45 #include "sha/sha_dma.h"
46 #include "hal/sha_hal.h"
47 #include "soc/soc_caps.h"
48 #include "esp_sha_dma_priv.h"
49
50 #if CONFIG_IDF_TARGET_ESP32S2
51 #include "esp32s2/rom/cache.h"
52 #elif CONFIG_IDF_TARGET_ESP32S3
53 #include "esp32s3/rom/cache.h"
54 #elif CONFIG_IDF_TARGET_ESP32C3
55 #include "esp32s3/rom/cache.h"
56 #elif CONFIG_IDF_TARGET_ESP32H2
57 #include "esp32h2/rom/cache.h"
58 #endif
59
60 #if SOC_SHA_GDMA
61 #define SHA_LOCK() esp_crypto_sha_aes_lock_acquire()
62 #define SHA_RELEASE() esp_crypto_sha_aes_lock_release()
63 #elif SOC_SHA_CRYPTO_DMA
64 #define SHA_LOCK() esp_crypto_dma_lock_acquire()
65 #define SHA_RELEASE() esp_crypto_dma_lock_release()
66 #endif
67
68 const static char *TAG = "esp-sha";
69
70 /* These are static due to:
71 * * Must be in DMA capable memory, so stack is not a safe place to put them
72 * * To avoid having to malloc/free them for every DMA operation
73 */
74 static DRAM_ATTR lldesc_t s_dma_descr_input;
75 static DRAM_ATTR lldesc_t s_dma_descr_buf;
76
esp_sha_write_digest_state(esp_sha_type sha_type,void * digest_state)77 void esp_sha_write_digest_state(esp_sha_type sha_type, void *digest_state)
78 {
79 sha_hal_write_digest(sha_type, digest_state);
80 }
81
esp_sha_read_digest_state(esp_sha_type sha_type,void * digest_state)82 void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
83 {
84 sha_hal_read_digest(sha_type, digest_state);
85 }
86
87 /* Return block size (in bytes) for a given SHA type */
block_length(esp_sha_type type)88 inline static size_t block_length(esp_sha_type type)
89 {
90 switch (type) {
91 case SHA1:
92 case SHA2_224:
93 case SHA2_256:
94 return 64;
95 #if SOC_SHA_SUPPORT_SHA384
96 case SHA2_384:
97 #endif
98 #if SOC_SHA_SUPPORT_SHA512
99 case SHA2_512:
100 #endif
101 #if SOC_SHA_SUPPORT_SHA512_T
102 case SHA2_512224:
103 case SHA2_512256:
104 case SHA2_512T:
105 #endif
106 return 128;
107 default:
108 return 0;
109 }
110 }
111
112
113 /* Enable SHA peripheral and then lock it */
esp_sha_acquire_hardware()114 void esp_sha_acquire_hardware()
115 {
116 SHA_LOCK(); /* Released when releasing hw with esp_sha_release_hardware() */
117
118 /* Enable SHA and DMA hardware */
119 #if SOC_SHA_CRYPTO_DMA
120 periph_module_enable(PERIPH_SHA_DMA_MODULE);
121 #elif SOC_SHA_GDMA
122 periph_module_enable(PERIPH_SHA_MODULE);
123 #endif
124 }
125
126 /* Disable SHA peripheral block and then release it */
esp_sha_release_hardware()127 void esp_sha_release_hardware()
128 {
129 /* Disable SHA and DMA hardware */
130 #if SOC_SHA_CRYPTO_DMA
131 periph_module_disable(PERIPH_SHA_DMA_MODULE);
132 #elif SOC_SHA_GDMA
133 periph_module_disable(PERIPH_SHA_MODULE);
134 #endif
135
136 SHA_RELEASE();
137 }
138
139 #if SOC_SHA_SUPPORT_SHA512_T
140 /* The initial hash value for SHA512/t is generated according to the
141 algorithm described in the TRM, chapter SHA-Accelerator
142 */
esp_sha_512_t_init_hash(uint16_t t)143 int esp_sha_512_t_init_hash(uint16_t t)
144 {
145 uint32_t t_string = 0;
146 uint8_t t0, t1, t2, t_len;
147
148 if (t == 384) {
149 ESP_LOGE(TAG, "Invalid t for SHA512/t, t = %u,cannot be 384", t);
150 return -1;
151 }
152
153 if (t <= 9) {
154 t_string = (uint32_t)((1 << 23) | ((0x30 + t) << 24));
155 t_len = 0x48;
156 } else if (t <= 99) {
157 t0 = t % 10;
158 t1 = (t / 10) % 10;
159 t_string = (uint32_t)((1 << 15) | ((0x30 + t0) << 16) |
160 (((0x30 + t1) << 24)));
161 t_len = 0x50;
162 } else if (t <= 512) {
163 t0 = t % 10;
164 t1 = (t / 10) % 10;
165 t2 = t / 100;
166 t_string = (uint32_t)((1 << 7) | ((0x30 + t0) << 8) |
167 (((0x30 + t1) << 16) + ((0x30 + t2) << 24)));
168 t_len = 0x58;
169 } else {
170 ESP_LOGE(TAG, "Invalid t for SHA512/t, t = %u, must equal or less than 512", t);
171 return -1;
172 }
173
174 sha_hal_sha512_init_hash(t_string, t_len);
175
176 return 0;
177 }
178
179 #endif //SOC_SHA_SUPPORT_SHA512_T
180
181
182 /* Hash the input block by block, using non-DMA mode */
esp_sha_block_mode(esp_sha_type sha_type,const uint8_t * input,uint32_t ilen,const uint8_t * buf,uint32_t buf_len,bool is_first_block)183 static void esp_sha_block_mode(esp_sha_type sha_type, const uint8_t *input, uint32_t ilen,
184 const uint8_t *buf, uint32_t buf_len, bool is_first_block)
185 {
186 size_t blk_len = 0;
187 size_t blk_word_len = 0;
188 int num_block = 0;
189
190 blk_len = block_length(sha_type);
191 blk_word_len = blk_len / 4;
192 num_block = ilen / blk_len;
193
194 if (buf_len != 0) {
195 sha_hal_hash_block(sha_type, buf, blk_word_len, is_first_block);
196 is_first_block = false;
197 }
198
199 for (int i = 0; i < num_block; i++) {
200 sha_hal_hash_block(sha_type, input + blk_len * i, blk_word_len, is_first_block);
201 is_first_block = false;
202 }
203 }
204
205
206
207 static int esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
208 const void *buf, uint32_t buf_len, bool is_first_block);
209
210 /* Performs SHA on multiple blocks at a time using DMA
211 splits up into smaller operations for inputs that exceed a single DMA list
212 */
esp_sha_dma(esp_sha_type sha_type,const void * input,uint32_t ilen,const void * buf,uint32_t buf_len,bool is_first_block)213 int esp_sha_dma(esp_sha_type sha_type, const void *input, uint32_t ilen,
214 const void *buf, uint32_t buf_len, bool is_first_block)
215 {
216 int ret = 0;
217 unsigned char *dma_cap_buf = NULL;
218 int dma_op_num = ( ilen / (SOC_SHA_DMA_MAX_BUFFER_SIZE + 1) ) + 1;
219
220 if (buf_len > block_length(sha_type)) {
221 ESP_LOGE(TAG, "SHA DMA buf_len cannot exceed max size for a single block");
222 return -1;
223 }
224
225 /* DMA cannot access memory in flash, hash block by block instead of using DMA */
226 if (!esp_ptr_dma_ext_capable(input) && !esp_ptr_dma_capable(input) && (ilen != 0)) {
227 esp_sha_block_mode(sha_type, input, ilen, buf, buf_len, is_first_block);
228 return 0;
229 }
230
231 #if (CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE)
232 if (esp_ptr_external_ram(input)) {
233 Cache_WriteBack_Addr((uint32_t)input, ilen);
234 }
235 if (esp_ptr_external_ram(buf)) {
236 Cache_WriteBack_Addr((uint32_t)buf, buf_len);
237 }
238 #endif
239
240 /* Copy to internal buf if buf is in non DMA capable memory */
241 if (!esp_ptr_dma_ext_capable(buf) && !esp_ptr_dma_capable(buf) && (buf_len != 0)) {
242 dma_cap_buf = heap_caps_malloc(sizeof(unsigned char) * buf_len, MALLOC_CAP_8BIT|MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
243 if (dma_cap_buf == NULL) {
244 ESP_LOGE(TAG, "Failed to allocate buf memory");
245 ret = -1;
246 goto cleanup;
247 }
248 memcpy(dma_cap_buf, buf, buf_len);
249 buf = dma_cap_buf;
250 }
251
252
253 /* The max amount of blocks in a single hardware operation is 2^6 - 1 = 63
254 Thus we only do a single DMA input list + dma buf list,
255 which is max 3968/64 + 64/64 = 63 blocks */
256 for (int i = 0; i < dma_op_num; i++) {
257
258 int dma_chunk_len = MIN(ilen, SOC_SHA_DMA_MAX_BUFFER_SIZE);
259
260 ret = esp_sha_dma_process(sha_type, input, dma_chunk_len, buf, buf_len, is_first_block);
261
262 if (ret != 0) {
263 goto cleanup;
264 }
265
266 ilen -= dma_chunk_len;
267 input += dma_chunk_len;
268
269 // Only append buf to the first operation
270 buf_len = 0;
271 is_first_block = false;
272 }
273
274 cleanup:
275 free(dma_cap_buf);
276 return ret;
277 }
278
279
280 /* Performs SHA on multiple blocks at a time */
esp_sha_dma_process(esp_sha_type sha_type,const void * input,uint32_t ilen,const void * buf,uint32_t buf_len,bool is_first_block)281 static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
282 const void *buf, uint32_t buf_len, bool is_first_block)
283 {
284 int ret = 0;
285 lldesc_t *dma_descr_head;
286 size_t num_blks = (ilen + buf_len) / block_length(sha_type);
287
288 memset(&s_dma_descr_input, 0, sizeof(lldesc_t));
289 memset(&s_dma_descr_buf, 0, sizeof(lldesc_t));
290
291 /* DMA descriptor for Memory to DMA-SHA transfer */
292 if (ilen) {
293 s_dma_descr_input.length = ilen;
294 s_dma_descr_input.size = ilen;
295 s_dma_descr_input.owner = 1;
296 s_dma_descr_input.eof = 1;
297 s_dma_descr_input.buf = (uint8_t *)input;
298 dma_descr_head = &s_dma_descr_input;
299 }
300 /* Check after input to overide head if there is any buf*/
301 if (buf_len) {
302 s_dma_descr_buf.length = buf_len;
303 s_dma_descr_buf.size = buf_len;
304 s_dma_descr_buf.owner = 1;
305 s_dma_descr_buf.eof = 1;
306 s_dma_descr_buf.buf = (uint8_t *)buf;
307 dma_descr_head = &s_dma_descr_buf;
308 }
309
310 /* Link DMA lists */
311 if (buf_len && ilen) {
312 s_dma_descr_buf.eof = 0;
313 s_dma_descr_buf.empty = (uint32_t)(&s_dma_descr_input);
314 }
315
316 if (esp_sha_dma_start(dma_descr_head) != ESP_OK) {
317 ESP_LOGE(TAG, "esp_sha_dma_start failed, no DMA channel available");
318 return -1;
319 }
320
321 sha_hal_hash_dma(sha_type, num_blks, is_first_block);
322
323 sha_hal_wait_idle();
324
325 return ret;
326 }
327