Skip to content

Commit b75edc8

Browse files
committed
esp32s2 SHA: fallback to hashing block by block for non DMA memory
Also adds unit test for SHA with input buffer in flash Closes IDF-1529
1 parent fbd64af commit b75edc8

File tree

3 files changed

+142
-48
lines changed

3 files changed

+142
-48
lines changed

components/idf_test/include/esp32s2/idf_performance_target.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#define IDF_PERFORMANCE_MIN_SHA256_THROUGHPUT_MBSEC 90.0
88
// esp_sha() time to process 32KB of input data from RAM
99
#define IDF_PERFORMANCE_MAX_TIME_SHA1_32KB 900
10-
#define IDF_PERFORMANCE_MAX_TIME_SHA512_32KB 800
10+
#define IDF_PERFORMANCE_MAX_TIME_SHA512_32KB 900
1111

1212
#define IDF_PERFORMANCE_MAX_RSA_2048KEY_PUBLIC_OP 13500
1313
#define IDF_PERFORMANCE_MAX_RSA_2048KEY_PRIVATE_OP 130000

components/mbedtls/port/esp32s2/sha.c

Lines changed: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
*/
5555
#define SHA_DMA_MAX_BYTES 3968
5656

57+
/* The longest length of a single block is for SHA512 = 128 byte */
58+
#define SHA_MAX_BLK_LEN 128
59+
5760
const static char *TAG = "esp-sha";
5861

5962
/* Return block size (in bytes) for a given SHA type */
@@ -196,6 +199,59 @@ int esp_sha_512_t_init_hash(uint16_t t)
196199
return 0;
197200
}
198201

202+
static void esp_sha_fill_text_block(esp_sha_type sha_type, const void *input)
203+
{
204+
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
205+
uint32_t *data_words = NULL;
206+
207+
/* Fill the data block */
208+
data_words = (uint32_t *)(input);
209+
for (int i = 0; i < block_length(sha_type) / 4; i++) {
210+
reg_addr_buf[i] = (data_words[i]);
211+
}
212+
asm volatile ("memw");
213+
}
214+
215+
/* Hash a single SHA block */
216+
static void esp_sha_block(esp_sha_type sha_type, const void *input, bool is_first_block)
217+
{
218+
esp_sha_fill_text_block(sha_type, input);
219+
220+
esp_sha_wait_idle();
221+
/* Start hashing */
222+
if (is_first_block) {
223+
REG_WRITE(SHA_START_REG, 1);
224+
} else {
225+
REG_WRITE(SHA_CONTINUE_REG, 1);
226+
}
227+
}
228+
229+
/* Hash the input block by block, using non-DMA mode */
230+
static void esp_sha_block_mode(esp_sha_type sha_type, const uint8_t *input, uint32_t ilen,
231+
const uint8_t *buf, uint32_t buf_len, bool is_first_block)
232+
{
233+
size_t blk_len = 0;
234+
int num_block = 0;
235+
236+
blk_len = block_length(sha_type);
237+
238+
REG_WRITE(SHA_MODE_REG, sha_type);
239+
num_block = ilen / blk_len;
240+
241+
if (buf_len != 0) {
242+
esp_sha_block(sha_type, buf, is_first_block);
243+
is_first_block = false;
244+
}
245+
246+
for (int i = 0; i < num_block; i++) {
247+
esp_sha_block(sha_type, input + blk_len*i, is_first_block);
248+
is_first_block = false;
249+
}
250+
251+
esp_sha_wait_idle();
252+
}
253+
254+
199255

200256
static int esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
201257
const void *buf, uint32_t buf_len, bool is_first_block);
@@ -207,87 +263,65 @@ int esp_sha_dma(esp_sha_type sha_type, const void *input, uint32_t ilen,
207263
const void *buf, uint32_t buf_len, bool is_first_block)
208264
{
209265
int ret = 0;
210-
const void *dma_input;
211-
unsigned char *non_icache_input = NULL;
212-
unsigned char *non_icache_buf = NULL;
213-
int dma_op_num;
214-
size_t dma_max_chunk_len = SHA_DMA_MAX_BYTES;
266+
unsigned char *dma_cap_buf = NULL;
267+
int dma_op_num = ( ilen / (SHA_DMA_MAX_BYTES + 1) ) + 1;
215268

216-
if (buf_len > 128) {
269+
if (buf_len > block_length(sha_type)) {
217270
ESP_LOGE(TAG, "SHA DMA buf_len cannot exceed max size for a single block");
218271
return -1;
219272
}
220273

221-
#if (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
222-
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(buf)) {
223-
Cache_WriteBack_All();
274+
/* DMA cannot access memory in the iCache range, hash block by block instead of using DMA */
275+
if (!esp_ptr_dma_ext_capable(input) && !esp_ptr_dma_capable(input) && (ilen != 0)) {
276+
esp_sha_block_mode(sha_type, input, ilen, buf, buf_len, is_first_block);
277+
return 0;
278+
}
279+
280+
#if (CONFIG_ESP32S2_SPIRAM_SUPPORT)
281+
if (esp_ptr_external_ram(input)) {
282+
Cache_WriteBack_Addr((uint32_t)input, ilen);
283+
}
284+
if (esp_ptr_external_ram(buf)) {
285+
Cache_WriteBack_Addr((uint32_t)buf, buf_len);
224286
}
225287
#endif
226288

289+
/* Copy to internal buf if buf is in non DMA capable memory */
227290
if (!esp_ptr_dma_ext_capable(buf) && !esp_ptr_dma_capable(buf) && (buf_len != 0)) {
228-
non_icache_buf = heap_caps_malloc(sizeof(unsigned char) * buf_len, MALLOC_CAP_DMA);
229-
if (non_icache_buf == NULL) {
291+
dma_cap_buf = heap_caps_malloc(sizeof(unsigned char) * buf_len, MALLOC_CAP_DMA);
292+
if (dma_cap_buf == NULL) {
230293
ESP_LOGE(TAG, "Failed to allocate buf memory");
231-
ret = ESP_ERR_NO_MEM;
294+
ret = -1;
232295
goto cleanup;
233296
}
234-
memcpy(non_icache_buf, buf, buf_len);
235-
buf = non_icache_buf;
236-
}
237-
238-
/* DMA cannot access memory in the iCache range, copy data to temporary buffers before transfer */
239-
if (!esp_ptr_dma_ext_capable(input) && !esp_ptr_dma_capable(input) && (ilen != 0)) {
240-
non_icache_input = heap_caps_malloc(sizeof(unsigned char) * MIN(ilen, dma_max_chunk_len), MALLOC_CAP_DMA);
241-
242-
if (non_icache_input == NULL) {
243-
/* Allocate biggest available heap */
244-
size_t max_alloc_len = heap_caps_get_largest_free_block(MALLOC_CAP_DMA);
245-
dma_max_chunk_len = max_alloc_len - max_alloc_len % block_length(sha_type);
246-
non_icache_input = heap_caps_malloc(sizeof(unsigned char) * MIN(ilen, dma_max_chunk_len), MALLOC_CAP_DMA);
247-
248-
if (non_icache_input == NULL) {
249-
ESP_LOGE(TAG, "Failed to allocate input memory");
250-
ret = ESP_ERR_NO_MEM;
251-
goto cleanup;
252-
}
253-
}
297+
memcpy(dma_cap_buf, buf, buf_len);
298+
buf = dma_cap_buf;
254299
}
255300

256301

257302
/* The max amount of blocks in a single hardware operation is 2^6 - 1 = 63
258303
Thus we only do a single DMA input list + dma buf list,
259304
which is max 3968/64 + 64/64 = 63 blocks */
260-
dma_op_num = ( ilen / (dma_max_chunk_len + 1) ) + 1;
261305
for (int i = 0; i < dma_op_num; i++) {
262-
int dma_chunk_len = MIN(ilen, dma_max_chunk_len);
263306

307+
int dma_chunk_len = MIN(ilen, SHA_DMA_MAX_BYTES);
264308

265-
/* Input depends on if it's a temp alloc buffer or supplied by user */
266-
if (non_icache_input != NULL) {
267-
memcpy(non_icache_input, input, dma_chunk_len);
268-
dma_input = non_icache_input;
269-
} else {
270-
dma_input = input;
271-
}
272-
273-
ret = esp_sha_dma_process(sha_type, dma_input, dma_chunk_len, buf, buf_len, is_first_block);
274-
309+
ret = esp_sha_dma_process(sha_type, input, dma_chunk_len, buf, buf_len, is_first_block);
275310

276311
if (ret != 0) {
277312
goto cleanup;
278313
}
279314

280-
is_first_block = false;
281315
ilen -= dma_chunk_len;
282316
input += dma_chunk_len;
283317

284318
// Only append buf to the first operation
285319
buf_len = 0;
320+
is_first_block = false;
286321
}
287322

288323
cleanup:
289-
free(non_icache_input);
290-
free(non_icache_buf);
324+
free(dma_cap_buf);
291325
return ret;
292326
}
293327

components/mbedtls/test/test_mbedtls_sha.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,66 @@ TEST_CASE("mbedtls SHA session passed between tasks", "[mbedtls]")
305305
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, param.result, 32, "SHA256 result from other task");
306306
}
307307

308+
309+
310+
311+
/* Random input generated and hashed using python:
312+
313+
import hashlib
314+
import os, binascii
315+
316+
input = bytearray(os.urandom(150))
317+
arr = ''
318+
for idx, b in enumerate(input):
319+
if idx % 8 == 0:
320+
arr += '\n'
321+
arr += "{}, ".format(hex(b))
322+
digest = hashlib.sha256(input).hexdigest()
323+
324+
*/
325+
const uint8_t test_vector[] = {
326+
0xe4, 0x1a, 0x1a, 0x30, 0x71, 0xd3, 0x94, 0xb0,
327+
0xc3, 0x7e, 0x99, 0x9f, 0x1a, 0xde, 0x4a, 0x36,
328+
0xb1, 0x1, 0x81, 0x2b, 0x41, 0x91, 0x11, 0x7f,
329+
0xd8, 0xe1, 0xd5, 0xe5, 0x52, 0x6d, 0x92, 0xee,
330+
0x6c, 0xf7, 0x70, 0xea, 0x3a, 0xb, 0xc9, 0x97,
331+
0xc0, 0x12, 0x6f, 0x10, 0x5b, 0x90, 0xd8, 0x52,
332+
0x91, 0x69, 0xea, 0xc4, 0x1f, 0xc, 0xcf, 0xc6,
333+
0xf0, 0x43, 0xc6, 0xa3, 0x1f, 0x46, 0x3c, 0x3d,
334+
0x25, 0xe5, 0xa8, 0x27, 0x86, 0x85, 0x32, 0x3f,
335+
0x33, 0xd8, 0x40, 0xc4, 0x41, 0xf6, 0x4b, 0x12,
336+
0xd8, 0x5e, 0x4, 0x27, 0x42, 0x90, 0x73, 0x4,
337+
0x8, 0x42, 0xd1, 0x64, 0xd, 0x84, 0x3, 0x1,
338+
0x76, 0x88, 0xe4, 0x95, 0xdf, 0xe7, 0x62, 0xb4,
339+
0xb3, 0xb2, 0x7e, 0x6d, 0x78, 0xca, 0x79, 0x82,
340+
0xcc, 0xba, 0x22, 0xd2, 0x90, 0x2e, 0xe3, 0xa8,
341+
0x2a, 0x53, 0x3a, 0xb1, 0x9a, 0x7f, 0xb7, 0x8b,
342+
0xfa, 0x32, 0x47, 0xc1, 0x5c, 0x6, 0x4f, 0x7b,
343+
0xcd, 0xb3, 0xf4, 0xf1, 0xd0, 0xb5, 0xbf, 0xfb,
344+
0x7c, 0xc3, 0xa5, 0xb2, 0xc4, 0xd4,
345+
};
346+
347+
const uint8_t test_vector_digest[] = {
348+
0xff, 0x1c, 0x60, 0xcb, 0x21, 0xf0, 0x63, 0x68,
349+
0xb9, 0xfc, 0xfe, 0xad, 0x3e, 0xb0, 0x2e, 0xd1,
350+
0xf9, 0x08, 0x82, 0x82, 0x83, 0x06, 0xc1, 0x8a,
351+
0x98, 0x5d, 0x36, 0xc0, 0xb7, 0xeb, 0x35, 0xe0,
352+
};
353+
354+
TEST_CASE("mbedtls SHA, input in flash", "[mbedtls]")
355+
{
356+
mbedtls_sha256_context sha256_ctx;
357+
unsigned char sha256[32];
358+
359+
mbedtls_sha256_init(&sha256_ctx);
360+
361+
TEST_ASSERT_EQUAL(0, mbedtls_sha256_starts_ret(&sha256_ctx, false));
362+
TEST_ASSERT_EQUAL(0, mbedtls_sha256_update_ret(&sha256_ctx, test_vector, sizeof(test_vector)));
363+
TEST_ASSERT_EQUAL(0, mbedtls_sha256_finish_ret(&sha256_ctx, sha256));
364+
365+
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(test_vector_digest, sha256, 32, "SHA256 calculation");
366+
}
367+
308368
/* ESP32 do not have SHA512/t functions */
309369
#if !DISABLED_FOR_TARGETS(ESP32)
310370

0 commit comments

Comments
 (0)