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