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