1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "bootloader_sha.h"
7 #include <stdbool.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <sys/param.h>
11
12 #include "esp32/rom/sha.h"
13 #include "soc/dport_reg.h"
14 #include "soc/hwcrypto_periph.h"
15
16 static uint32_t words_hashed;
17
18 // Words per SHA256 block
19 static const size_t BLOCK_WORDS = (64 / sizeof(uint32_t));
20 // Words in final SHA256 digest
21 static const size_t DIGEST_WORDS = (32 / sizeof(uint32_t));
22
bootloader_sha256_start(void)23 bootloader_sha256_handle_t bootloader_sha256_start(void)
24 {
25 // Enable SHA hardware
26 ets_sha_enable();
27 words_hashed = 0;
28 return (bootloader_sha256_handle_t)&words_hashed; // Meaningless non-NULL value
29 }
30
bootloader_sha256_data(bootloader_sha256_handle_t handle,const void * data,size_t data_len)31 void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
32 {
33 assert(handle != NULL);
34 assert(data_len % 4 == 0);
35
36 const uint32_t *w = (const uint32_t *)data;
37 size_t word_len = data_len / 4;
38 uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
39
40 while (word_len > 0) {
41 size_t block_count = words_hashed % BLOCK_WORDS;
42 size_t copy_words = (BLOCK_WORDS - block_count);
43
44 copy_words = MIN(word_len, copy_words);
45
46 // Wait for SHA engine idle
47 while (REG_READ(SHA_256_BUSY_REG) != 0) { }
48
49 // Copy to memory block
50 for (size_t i = 0; i < copy_words; i++) {
51 sha_text_reg[block_count + i] = __builtin_bswap32(w[i]);
52 }
53 asm volatile ("memw");
54
55 // Update counters
56 words_hashed += copy_words;
57 block_count += copy_words;
58 word_len -= copy_words;
59 w += copy_words;
60
61 // If we loaded a full block, run the SHA engine
62 if (block_count == BLOCK_WORDS) {
63 if (words_hashed == BLOCK_WORDS) {
64 REG_WRITE(SHA_256_START_REG, 1);
65 } else {
66 REG_WRITE(SHA_256_CONTINUE_REG, 1);
67 }
68 block_count = 0;
69 }
70 }
71 }
72
bootloader_sha256_finish(bootloader_sha256_handle_t handle,uint8_t * digest)73 void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest)
74 {
75 assert(handle != NULL);
76
77 if (digest == NULL) {
78 return; // We'd free resources here, but there are none to free
79 }
80
81 uint32_t data_words = words_hashed;
82
83 // Pad to a 55 byte long block loaded in the engine
84 // (leaving 1 byte 0x80 plus variable padding plus 8 bytes of length,
85 // to fill a 64 byte block.)
86 int block_bytes = (words_hashed % BLOCK_WORDS) * 4;
87 int pad_bytes = 55 - block_bytes;
88 if (pad_bytes < 0) {
89 pad_bytes += 64;
90 }
91 static const uint8_t padding[64] = { 0x80, 0, };
92
93 pad_bytes += 5; // 1 byte for 0x80 plus first 4 bytes of the 64-bit length
94 assert(pad_bytes % 4 == 0); // should be, as (block_bytes % 4 == 0)
95
96 bootloader_sha256_data(handle, padding, pad_bytes);
97
98 assert(words_hashed % BLOCK_WORDS == 60 / 4); // 32-bits left in block
99
100 // Calculate 32-bit length for final 32 bits of data
101 uint32_t bit_count = __builtin_bswap32( data_words * 32 );
102 bootloader_sha256_data(handle, &bit_count, sizeof(bit_count));
103
104 assert(words_hashed % BLOCK_WORDS == 0);
105
106 while (REG_READ(SHA_256_BUSY_REG) == 1) { }
107 REG_WRITE(SHA_256_LOAD_REG, 1);
108 while (REG_READ(SHA_256_BUSY_REG) == 1) { }
109
110 uint32_t *digest_words = (uint32_t *)digest;
111 uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
112 for (size_t i = 0; i < DIGEST_WORDS; i++) {
113 digest_words[i] = __builtin_bswap32(sha_text_reg[i]);
114 }
115 asm volatile ("memw");
116 }
117