1 /*
2 * Copyright (c) 2023, The TrustedFirmware-M Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <assert.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include "cc3xx_hash.h"
11 #include "cc3xx_drbg_hash.h"
12 #include "cc3xx_endian_helpers.h"
13 #include "cc3xx_pka.h"
14 #include "cc3xx_stdlib.h"
15
16 /**
17 * @brief Ceiling of a / b
18 */
19 #define CEIL(a, b) ((a) + (b) - 1)/(b)
20
21 /** \note Throughout the file sizeof(state_v) and sizeof(constant_c) are
22 * decreased by 1 byte because they have been defined with 1 byte
23 * more in the \ref struct cc3xx_drbg_hash_state_t to be 4 bytes
24 * aligned
25 */
26
long_acc(uint8_t * acc,const uint8_t * val,size_t acc_size,size_t val_size)27 static void long_acc(uint8_t *acc, const uint8_t *val, size_t acc_size, size_t val_size)
28 {
29 /* Need to convert BE -> LE -> BE again if PKA is configured for LE */
30 cc3xx_pka_reg_id_t r0, r1;
31 assert(acc_size == CC3XX_DRBG_HASH_SEEDLEN);
32
33 /* Accumulation happen only on 440 bit accumulators */
34 cc3xx_lowlevel_pka_init(CC3XX_DRBG_HASH_SEEDLEN);
35
36 /* Allocate a register among those not in use, given configured size */
37 r0 = cc3xx_lowlevel_pka_allocate_reg();
38
39 /* Initialize the accumulator register with the current value of acc */
40 cc3xx_lowlevel_pka_write_reg(r0, (const uint32_t *)acc, CC3XX_DRBG_HASH_SEEDLEN);
41
42 /* Request another register for the value to accumulate */
43 r1 = cc3xx_lowlevel_pka_allocate_reg();
44
45 /* Write the value to accumulate into the register */
46 cc3xx_lowlevel_pka_write_reg(r1, (const uint32_t *)val, val_size);
47
48 /* Perform the actual operation */
49 cc3xx_lowlevel_pka_add(r0, r1, r0);
50
51 /* Read back the accumulator register */
52 cc3xx_lowlevel_pka_read_reg(r0, (uint32_t *)acc, CC3XX_DRBG_HASH_SEEDLEN);
53
54 /* Uninit the engine */
55 cc3xx_lowlevel_pka_uninit();
56 }
57
58 /* Hardcode support for SHA-256 based HMAC only */
59 static const cc3xx_hash_alg_t alg = CC3XX_HASH_ALG_SHA256;
60
61 /**
62 * @brief Hash derivation function as specified by NIST SP 800-90 Section 10.3.1
63 *
64 * @param hash_inputs_num Total number of the hash_inputs being passed to the update function
65 * @param hash_inputs An array of three buffer pointers that can be used in the derivation process
66 * @param hash_inputs_len An array of three size_t values that contain the size of each buffer passed
67 * @param out Buffer containing the output of the derivation function
68 * @param out_len_bits Size in bits of the buffer containing the result of the derivation operation
69 * @return cc3xx_err_t
70 */
hash_df(size_t hash_inputs_num,const uint8_t ** hash_inputs,const size_t * hash_inputs_len,uint8_t * out,size_t out_len_bits)71 static cc3xx_err_t hash_df(
72 size_t hash_inputs_num,
73 const uint8_t **hash_inputs,
74 const size_t *hash_inputs_len,
75 uint8_t *out,
76 size_t out_len_bits)
77 {
78 /* The number of full SHA-256 hashes output (256 bit) that we need to cover the requested
79 * output of out_len_bits = 440 bit, i.e. the CC3XX_DRBG_HASH_SEEDLEN
80 */
81 const size_t num_hash = 2;
82 cc3xx_err_t err;
83 uint8_t counter_out_len_bits[5] = {0x01, 0x00, 0x00, 0x01, 0xB8}; /* 0x01 || out_len_bits */
84 size_t idx;
85 size_t hash_input_idx;
86 uint32_t temp[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
87
88 /* Number of bits to return must be fixed to 440 for the implementation, i.e. 0x1B8 */
89 assert(out_len_bits == CC3XX_DRBG_HASH_SEEDLEN * 8);
90
91 for (idx = 0; idx < num_hash; idx++) {
92
93 err = cc3xx_lowlevel_hash_init(alg);
94 if (err != CC3XX_ERR_SUCCESS) {
95 return err;
96 }
97
98 err = cc3xx_lowlevel_hash_update(counter_out_len_bits, sizeof(counter_out_len_bits));
99 if (err != CC3XX_ERR_SUCCESS) {
100 return err;
101 }
102
103 for (hash_input_idx = 0; hash_input_idx < hash_inputs_num && hash_inputs_len[hash_input_idx] != 0; hash_input_idx++) {
104 err = cc3xx_lowlevel_hash_update(hash_inputs[hash_input_idx], hash_inputs_len[hash_input_idx]);
105 if (err != CC3XX_ERR_SUCCESS) {
106 return err;
107 }
108 }
109
110 cc3xx_lowlevel_hash_finish((idx != num_hash - 1) ? (uint32_t *)out : temp, SHA256_OUTPUT_SIZE);
111
112 if (idx != num_hash - 1) {
113 out += SHA256_OUTPUT_SIZE;
114 }
115 counter_out_len_bits[0]++;
116 }
117
118 memcpy(out, temp, CC3XX_DRBG_HASH_SEEDLEN - SHA256_OUTPUT_SIZE);
119
120 return err;
121 }
122
cc3xx_lowlevel_drbg_hash_init(struct cc3xx_drbg_hash_state_t * state,const uint8_t * entropy,size_t entropy_len,const uint8_t * nonce,size_t nonce_len,const uint8_t * personalization,size_t personalization_len)123 cc3xx_err_t cc3xx_lowlevel_drbg_hash_init(
124 struct cc3xx_drbg_hash_state_t *state,
125 const uint8_t *entropy, size_t entropy_len,
126 const uint8_t *nonce, size_t nonce_len,
127 const uint8_t *personalization, size_t personalization_len)
128 {
129 cc3xx_err_t err;
130 uint8_t byte0 = 0x0;
131 const uint8_t *data[3] = {entropy, nonce, personalization};
132 size_t data_len[3] = {entropy_len, nonce_len, personalization_len};
133
134 err = hash_df(3, data, data_len, state->value_v, CC3XX_DRBG_HASH_SEEDLEN * 8);
135 if (err != CC3XX_ERR_SUCCESS) {
136 return err;
137 }
138
139 data[0] = &byte0;
140 data[1] = state->value_v;
141 data_len[0] = sizeof(byte0);
142 data_len[1] = sizeof(state->value_v) - 1;
143
144 err = hash_df(2, data, data_len, state->constant_c, CC3XX_DRBG_HASH_SEEDLEN * 8);
145 if (err != CC3XX_ERR_SUCCESS) {
146 return err;
147 }
148
149 state->reseed_counter = 1;
150
151 return err;
152 }
153
154 /**
155 * @brief Hash based generation process as specified by NIST SP 800-90 Section 10.1.1.4
156 *
157 * @param block_v block_v containing the seed to be used by the hashgen process
158 * @param out_len_bits Number of bits requested to be generated, byte aligned
159 * @param returned_bits Buffer containing the bits generated using the hash based process
160 * @return cc3xx_err_t
161 */
hash_gen_process(uint8_t * block_v,size_t out_len_bits,uint8_t * returned_bits)162 static cc3xx_err_t hash_gen_process(uint8_t *block_v, size_t out_len_bits, uint8_t *returned_bits)
163 {
164 cc3xx_err_t err;
165 size_t idx;
166 size_t gen_num_m = CEIL(out_len_bits, SHA256_OUTPUT_SIZE * 8); /* Number of hash generations */
167 uint32_t data[(CC3XX_DRBG_HASH_SEEDLEN + 1) / sizeof(uint32_t)];
168 uint32_t partial_last_block[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
169 #ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
170 size_t num_words_to_copy = sizeof(data) / sizeof(uint32_t);
171 cc3xx_dpa_hardened_word_copy((uint32_t *)data, (uint32_t *)block_v, num_words_to_copy);
172 #else
173 memcpy(data, block_v, CC3XX_DRBG_HASH_SEEDLEN);
174 #endif
175
176 for (idx = 0; idx < gen_num_m; idx++) {
177 const uint8_t byte1 = 0x1;
178 uint32_t *p_output_buf = NULL;
179
180 err = cc3xx_lowlevel_hash_init(alg);
181 if (err != CC3XX_ERR_SUCCESS) {
182 return err;
183 }
184
185 err = cc3xx_lowlevel_hash_update((uint8_t *)data, CC3XX_DRBG_HASH_SEEDLEN);
186 if (err!= CC3XX_ERR_SUCCESS) {
187 return err;
188 }
189
190 if (idx != gen_num_m - 1) {
191 p_output_buf = (uint32_t *)returned_bits;
192 } else {
193 /* We need to discriminate the case where the last generation is for a whole
194 * block or a partial block
195 */
196 if (out_len_bits % (SHA256_OUTPUT_SIZE * 8)) {
197 p_output_buf = partial_last_block;
198 } else {
199 p_output_buf = (uint32_t *)returned_bits;
200 }
201 }
202
203 cc3xx_lowlevel_hash_finish(p_output_buf, SHA256_OUTPUT_SIZE);
204
205 long_acc((uint8_t *)data, &byte1, CC3XX_DRBG_HASH_SEEDLEN, sizeof(byte1));
206
207 returned_bits += SHA256_OUTPUT_SIZE;
208 }
209
210 returned_bits -= SHA256_OUTPUT_SIZE;
211
212 if (out_len_bits % (SHA256_OUTPUT_SIZE * 8)) {
213 memcpy(returned_bits, partial_last_block, out_len_bits % (SHA256_OUTPUT_SIZE * 8));
214 }
215
216 return err;
217 }
218
cc3xx_lowlevel_drbg_hash_generate(struct cc3xx_drbg_hash_state_t * state,size_t len_bits,uint8_t * returned_bits,const uint8_t * additional_input,size_t additional_input_len)219 cc3xx_err_t cc3xx_lowlevel_drbg_hash_generate(
220 struct cc3xx_drbg_hash_state_t *state,
221 size_t len_bits, uint8_t *returned_bits,
222 const uint8_t *additional_input, size_t additional_input_len)
223 {
224 cc3xx_err_t err;
225 const uint8_t byte3 = 0x03;
226 uint8_t reseed_counter[4];
227 uint32_t hash_output_buffer[SHA256_OUTPUT_SIZE / sizeof(uint32_t)];
228 /* The reseed counter must be treated as a BE number, so use a local
229 * buffer to format it as a big endian number for the long addition
230 */
231 uint32_t *p_reseed_counter = (uint32_t *) reseed_counter;
232
233 if (state->reseed_counter == UINT32_MAX) {
234 /* When we reach 2^32 invocations we must reseed */
235 return CC3XX_ERR_DRBG_RESEED_REQUIRED;
236 }
237
238 /* The implementation constraints the output length to be byte aligned to
239 * reduce complexity
240 */
241 assert(len_bits != 0);
242 assert((len_bits % 8) == 0);
243
244 if (additional_input_len && additional_input != NULL) {
245 const uint8_t byte2 = 0x02;
246
247 err = cc3xx_lowlevel_hash_init(alg);
248 if (err != CC3XX_ERR_SUCCESS) {
249 return err;
250 }
251 err = cc3xx_lowlevel_hash_update(&byte2, sizeof(byte2));
252 if (err != CC3XX_ERR_SUCCESS) {
253 return err;
254 }
255 err = cc3xx_lowlevel_hash_update(state->value_v, sizeof(state->value_v) - 1);
256 if (err != CC3XX_ERR_SUCCESS) {
257 return err;
258 }
259 err = cc3xx_lowlevel_hash_update(additional_input, additional_input_len);
260 if (err != CC3XX_ERR_SUCCESS) {
261 return err;
262 }
263
264 cc3xx_lowlevel_hash_finish(hash_output_buffer, SHA256_OUTPUT_SIZE);
265 long_acc(state->value_v, (uint8_t *)hash_output_buffer,
266 sizeof(state->value_v) - 1, sizeof(hash_output_buffer));
267 }
268
269 err = hash_gen_process(state->value_v, len_bits, returned_bits);
270 if (err != CC3XX_ERR_SUCCESS) {
271 return err;
272 }
273
274 err = cc3xx_lowlevel_hash_init(alg);
275 if (err != CC3XX_ERR_SUCCESS) {
276 return err;
277 }
278 err = cc3xx_lowlevel_hash_update(&byte3, sizeof(byte3));
279 if (err != CC3XX_ERR_SUCCESS) {
280 return err;
281 }
282 err = cc3xx_lowlevel_hash_update(state->value_v, sizeof(state->value_v) - 1);
283 if (err != CC3XX_ERR_SUCCESS) {
284 return err;
285 }
286
287 cc3xx_lowlevel_hash_finish(hash_output_buffer, SHA256_OUTPUT_SIZE);
288
289 /* V = V + H + C + reseed_counter */
290 long_acc(state->value_v, (uint8_t *)hash_output_buffer,
291 sizeof(state->value_v) - 1, sizeof(hash_output_buffer));
292 long_acc(state->value_v, state->constant_c,
293 sizeof(state->value_v) - 1, sizeof(state->constant_c) - 1);
294
295 *p_reseed_counter = bswap_32(state->reseed_counter);
296 long_acc(state->value_v, reseed_counter,
297 sizeof(state->value_v) - 1, sizeof(reseed_counter));
298
299 state->reseed_counter++;
300
301 return err;
302 }
303
cc3xx_lowlevel_drbg_hash_reseed(struct cc3xx_drbg_hash_state_t * state,const uint8_t * entropy,size_t entropy_len,const uint8_t * additional_input,size_t additional_input_len)304 cc3xx_err_t cc3xx_lowlevel_drbg_hash_reseed(
305 struct cc3xx_drbg_hash_state_t *state,
306 const uint8_t *entropy, size_t entropy_len,
307 const uint8_t *additional_input, size_t additional_input_len)
308 {
309 cc3xx_err_t err;
310 const uint8_t byte0 = 0x0;
311 /* temporary buffer for (byte1 || V). Note that hash_df does not work in-place */
312 uint8_t temp[1 + sizeof(state->value_v) - 1] = {0x01};
313 const uint8_t *data[3] = {temp, entropy, additional_input};
314 size_t data_len[3] = {sizeof(temp), entropy_len, additional_input_len};
315
316 /* temp concatenates 0x01 || V */
317 memcpy(&temp[1], state->value_v, sizeof(state->value_v) - 1);
318
319 err = hash_df(3, data, data_len, state->value_v, CC3XX_DRBG_HASH_SEEDLEN * 8);
320 if (err != CC3XX_ERR_SUCCESS) {
321 return err;
322 }
323
324 data[0] = &byte0;
325 data[1] = state->value_v;
326 data_len[0] = sizeof(byte0);
327 data_len[1] = sizeof(state->value_v) - 1;
328
329 err = hash_df(2, data, data_len, state->constant_c, CC3XX_DRBG_HASH_SEEDLEN * 8);
330 if (err != CC3XX_ERR_SUCCESS) {
331 return err;
332 }
333
334 state->reseed_counter = 1;
335
336 return err;
337 }
338
cc3xx_lowlevel_drbg_hash_uninit(struct cc3xx_drbg_hash_state_t * state)339 cc3xx_err_t cc3xx_lowlevel_drbg_hash_uninit(struct cc3xx_drbg_hash_state_t *state)
340 {
341 cc3xx_secure_erase_buffer((uint32_t *)state, sizeof(struct cc3xx_drbg_hash_state_t)/4);
342 return CC3XX_ERR_SUCCESS;
343 }
344