1 /*
2  * Copyright (c) 2021-2024, The TrustedFirmware-M Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "cc3xx_hash.h"
9 
10 #include "cc3xx_dev.h"
11 #include "cc3xx_error.h"
12 #include "cc3xx_dma.h"
13 #include "cc3xx_engine_state.h"
14 #include "cc3xx_endian_helpers.h"
15 #include "cc3xx_stdlib.h"
16 
17 #include "fatal_error.h"
18 
19 #include <assert.h>
20 #include <stdint.h>
21 #include <stddef.h>
22 #include <string.h>
23 
24 #ifdef CC3XX_CONFIG_HASH_SHA256_ENABLE
25 static const uint32_t iv_sha256[8] = {
26     0x67e6096aU, 0x85ae67bbU, 0x72f36e3cU, 0x3af54fa5U,
27     0x7f520e51U, 0x8c68059bU, 0xabd9831fU, 0x19cde05bU,
28 };
29 #endif /* CC3XX_CONFIG_SHA256_ENABLE */
30 #ifdef CC3XX_CONFIG_HASH_SHA224_ENABLE
31 static const uint32_t iv_sha224[8] = {
32     0xD89E05C1U, 0x07D57C36U, 0x17DD7030U, 0x39590EF7U,
33     0x310BC0FFU, 0x11155868U, 0xA78FF964U, 0xA44FFABEU,
34 };
35 #endif /* CC3XX_CONFIG_HASH_SHA224_ENABLE */
36 #ifdef CC3XX_CONFIG_HASH_SHA1_ENABLE
37 static const uint32_t iv_sha1[5] = {
38     0x01234567U, 0x89ABCDEFU, 0xFEDCBA98U, 0x76543210U,
39     0xF0E1D2C3U,
40 };
41 #endif /* CC3XX_CONFIG_HASH_SHA1_ENABLE */
42 
set_hash_h(const uint32_t * buf,size_t length)43 static void set_hash_h(const uint32_t *buf, size_t length)
44 {
45     int32_t idx;
46 
47     /* The set of the hash_h register must be done in reverse order */
48     for (idx = (length / 4) - 1; idx >= 0; idx--) {
49         P_CC3XX->hash.hash_h[idx] = bswap_32(buf[idx]);
50     }
51 }
52 
get_hash_h(uint32_t * buf,size_t length)53 static void get_hash_h(uint32_t *buf, size_t length)
54 {
55     size_t idx;
56 
57     for (idx = 0; idx < (length / 4); idx++) {
58         buf[idx] = bswap_32(P_CC3XX->hash.hash_h[idx]);
59     }
60 }
61 
init_without_iv_set(cc3xx_hash_alg_t alg)62 static void init_without_iv_set(cc3xx_hash_alg_t alg)
63 {
64     /* Enable the hash engine clock */
65     P_CC3XX->misc.hash_clk_enable = 0x1U;
66 
67     /* Select hash engine */
68     cc3xx_lowlevel_set_engine(CC3XX_ENGINE_HASH);
69 
70     /* Select HASH mode, not MAC */
71     P_CC3XX->hash.hash_sel_aes_mac  = 0x0U;
72 
73     /* Enable padding */
74     P_CC3XX->hash.hash_pad_en = 0x1U;
75 
76     /* Disable auto-padding to allow multipart operations */
77     P_CC3XX->hash.auto_hw_padding = 0x0U;
78 
79     P_CC3XX->hash.hash_control = alg & 0b1111;
80 
81     cc3xx_lowlevel_dma_set_buffer_size(64);
82 }
83 
cc3xx_lowlevel_hash_init(cc3xx_hash_alg_t alg)84 cc3xx_err_t cc3xx_lowlevel_hash_init(cc3xx_hash_alg_t alg)
85 {
86     cc3xx_lowlevel_hash_uninit();
87 
88     const uint32_t *iv;
89     size_t iv_len;
90 
91     init_without_iv_set(alg);
92 
93     /* Set already processed length to 0 */
94     P_CC3XX->hash.hash_cur_len[0] = 0x0U;
95     P_CC3XX->hash.hash_cur_len[1] = 0x0U;
96 
97     switch (alg) {
98 #ifdef CC3XX_CONFIG_HASH_SHA224_ENABLE
99     case CC3XX_HASH_ALG_SHA224:
100         iv = iv_sha224;
101         iv_len = sizeof(iv_sha224);
102         break;
103 #endif /* CC3XX_CONFIG_HASH_SHA224_ENABLE */
104 #ifdef CC3XX_CONFIG_HASH_SHA256_ENABLE
105     case CC3XX_HASH_ALG_SHA256:
106         iv = iv_sha256;
107         iv_len = sizeof(iv_sha256);
108         break;
109 #endif /* CC3XX_CONFIG_HASH_SHA256_ENABLE */
110 #ifdef CC3XX_CONFIG_HASH_SHA1_ENABLE
111     case CC3XX_HASH_ALG_SHA1:
112         iv = iv_sha1;
113         iv_len = sizeof(iv_sha1);
114         break;
115 #endif /* CC3XX_CONFIG_HASH_SHA1_ENABLE */
116     default:
117         cc3xx_lowlevel_hash_uninit();
118         FATAL_ERR(CC3XX_ERR_NOT_IMPLEMENTED);
119         return CC3XX_ERR_NOT_IMPLEMENTED;
120     }
121 
122     set_hash_h(iv, iv_len);
123 
124     return CC3XX_ERR_SUCCESS;
125 }
126 
cc3xx_lowlevel_hash_uninit(void)127 void cc3xx_lowlevel_hash_uninit(void)
128 {
129     static const uint32_t zero_buf[9] = {0};
130     cc3xx_lowlevel_dma_uninit();
131 
132     set_hash_h(zero_buf, sizeof(zero_buf));
133 
134     /* Reset padding registers as required by the hardware */
135     P_CC3XX->hash.hash_pad_cfg = 0x0U;
136     P_CC3XX->hash.auto_hw_padding = 0x0U;
137 
138     /* Reset engine */
139     cc3xx_lowlevel_set_engine(CC3XX_ENGINE_NONE);
140 
141     /* Disable the hash engine clock */
142     P_CC3XX->misc.hash_clk_enable = 0x0U;
143 }
144 
cc3xx_lowlevel_hash_update(const uint8_t * buf,size_t length)145 cc3xx_err_t cc3xx_lowlevel_hash_update(const uint8_t *buf, size_t length)
146 {
147     return cc3xx_lowlevel_dma_buffered_input_data(buf, length, false);
148 }
149 
cc3xx_lowlevel_hash_get_state(struct cc3xx_hash_state_t * state)150 void cc3xx_lowlevel_hash_get_state(struct cc3xx_hash_state_t *state)
151 {
152     state->curr_len = P_CC3XX->hash.hash_cur_len[0];
153     state->curr_len |= (uint64_t)P_CC3XX->hash.hash_cur_len[1] << 32;
154     state->alg = P_CC3XX->hash.hash_control & 0b1111 ;
155 
156     get_hash_h(state->hash_h, sizeof(state->hash_h));
157     memcpy(&state->dma_state, &dma_state, sizeof(state->dma_state));
158 }
159 
cc3xx_lowlevel_hash_set_state(const struct cc3xx_hash_state_t * state)160 void cc3xx_lowlevel_hash_set_state(const struct cc3xx_hash_state_t *state)
161 {
162     init_without_iv_set(state->alg);
163     size_t hash_h_len = state->alg != CC3XX_HASH_ALG_SHA1 ? SHA256_OUTPUT_SIZE
164                                                           : SHA1_OUTPUT_SIZE;
165 
166     P_CC3XX->hash.hash_cur_len[0] = (uint32_t)state->curr_len;
167     P_CC3XX->hash.hash_cur_len[1] = (uint32_t)(state->curr_len >> 32);
168 
169     set_hash_h(state->hash_h, hash_h_len);
170     memcpy(&dma_state, &state->dma_state, sizeof(dma_state));
171 }
172 
cc3xx_lowlevel_hash_finish(uint32_t * res,size_t length)173 void cc3xx_lowlevel_hash_finish(uint32_t *res, size_t length)
174 {
175     /* Check alignment */
176     assert(((uintptr_t)res & 0b11) == 0);
177     /* Check size */
178     switch (P_CC3XX->hash.hash_control & 0b1111) {
179     case CC3XX_HASH_ALG_SHA256:
180         assert(length >= SHA256_OUTPUT_SIZE);
181         break;
182     case CC3XX_HASH_ALG_SHA224:
183         assert(length >= SHA224_OUTPUT_SIZE);
184         break;
185     case CC3XX_HASH_ALG_SHA1:
186         assert(length >= SHA1_OUTPUT_SIZE);
187         break;
188     }
189 
190     /* If any data has been input to the hash, the DMA block buf will be
191      * non-zero size.
192      */
193     if (dma_state.block_buf_size_in_use != 0) {
194         P_CC3XX->hash.auto_hw_padding = 0x1U;
195         cc3xx_lowlevel_dma_flush_buffer(false);
196     } else {
197         /* Special-case for hardware padding when the length is 0 */
198         P_CC3XX->hash.hash_pad_cfg = 0x4U;
199     }
200 
201     /* Wait until HASH engine is idle */
202     while (P_CC3XX->cc_ctl.hash_busy != 0) {}
203 
204     get_hash_h(res, length);
205 
206     cc3xx_lowlevel_hash_uninit();
207 }
208