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 <stdbool.h>
11 #include "cc3xx_pka.h"
12 #include "cc3xx_endian_helpers.h"
13 #include "cc3xx_drbg_ctr.h"
14 #include "cc3xx_rng.h"
15 #include "cc3xx_stdlib.h"
16 
long_inc_int(uint32_t * acc,size_t acc_size,bool is_increment)17 static void long_inc_int(uint32_t *acc, size_t acc_size, bool is_increment)
18 {
19     cc3xx_pka_reg_id_t r0;
20     assert(acc_size == CC3XX_DRBG_CTR_BLOCKLEN);
21 
22     /* Accumulation happen only on 128 bit accumulators */
23     cc3xx_lowlevel_pka_init(CC3XX_DRBG_CTR_BLOCKLEN);
24 
25     /* Allocate a register among those not in use, given configured size */
26     r0 = cc3xx_lowlevel_pka_allocate_reg();
27 
28     /* Initialize the accumulator register with the current value of acc */
29     cc3xx_lowlevel_pka_write_reg(r0, (const uint32_t *)acc, CC3XX_DRBG_CTR_BLOCKLEN);
30 
31     /* Perform the actual operation */
32     cc3xx_lowlevel_pka_add_si(r0, is_increment ? 1 : -1, r0);
33 
34     /* Read back the accumulator register */
35     cc3xx_lowlevel_pka_read_reg(r0, acc, CC3XX_DRBG_CTR_BLOCKLEN);
36 
37     /* Uninit the engine */
38     cc3xx_lowlevel_pka_uninit();
39 }
40 
long_inc(uint32_t * acc,size_t acc_size)41 static inline void long_inc(uint32_t *acc, size_t acc_size)
42 {
43     long_inc_int(acc, acc_size, true);
44 }
45 
long_dec(uint32_t * acc,size_t acc_size)46 static inline void long_dec(uint32_t *acc, size_t acc_size)
47 {
48     long_inc_int(acc, acc_size, false);
49 }
50 
51 /**
52  * @brief Produces seedlen bits of data through the underlying block
53  *        cipher (AES) set in CTR mode, and uses the produced data to update
54  *        the values of (Key, V) to be used as a state
55  *
56  * @param state    A pointer to a state structure
57  * @param data     provided data for the update process
58  * @param data_len Length of the update operation
59  *
60  * @return cc3xx_err_t
61  */
cc3xx_drbg_ctr_update(struct cc3xx_drbg_ctr_state_t * state,const uint8_t * data,const size_t data_len)62 static cc3xx_err_t cc3xx_drbg_ctr_update(
63     struct cc3xx_drbg_ctr_state_t *state,
64     const uint8_t *data, const size_t data_len)
65 {
66     cc3xx_err_t err;
67 
68     assert(data_len <= CC3XX_DRBG_CTR_SEEDLEN);
69 
70     long_inc((uint32_t *)state->block_v, sizeof(state->block_v));
71 
72     err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT,
73                                   CC3XX_AES_MODE_CTR,
74                                   CC3XX_AES_KEY_ID_USER_KEY,
75                                   (const uint32_t *)state->key_k, CC3XX_AES_KEYSIZE_128,
76                                   (const uint32_t *)state->block_v, sizeof(state->block_v));
77     if (err != CC3XX_ERR_SUCCESS) {
78         return err;
79     }
80 
81     cc3xx_lowlevel_aes_set_output_buffer((uint8_t *)state->key_k, CC3XX_DRBG_CTR_SEEDLEN);
82 
83     err = cc3xx_lowlevel_aes_update(data, data_len);
84     if (err != CC3XX_ERR_SUCCESS) {
85         return err;
86     }
87 
88     /* allow for the update() to happen on less than 256 bit of data */
89     if (data_len < CC3XX_DRBG_CTR_SEEDLEN) {
90         uint8_t all_zeros[CC3XX_DRBG_CTR_SEEDLEN - data_len];
91         memset(all_zeros, 0, sizeof(all_zeros));
92         err = cc3xx_lowlevel_aes_update(all_zeros, sizeof(all_zeros));
93         if (err != CC3XX_ERR_SUCCESS) {
94             return err;
95         }
96     }
97 
98     err = cc3xx_lowlevel_aes_finish(NULL, NULL);
99     if (err != CC3XX_ERR_SUCCESS) {
100         return err;
101     }
102 
103     return err;
104 }
105 
cc3xx_lowlevel_drbg_ctr_init(struct cc3xx_drbg_ctr_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)106 cc3xx_err_t cc3xx_lowlevel_drbg_ctr_init(
107     struct cc3xx_drbg_ctr_state_t *state,
108     const uint8_t *entropy, size_t entropy_len,
109     const uint8_t *nonce, size_t nonce_len,
110     const uint8_t *personalization, size_t personalization_len)
111 {
112     cc3xx_err_t err;
113     uint32_t personalized_entropy[CC3XX_DRBG_CTR_SEEDLEN_WORDS];
114     uint8_t *seed_material = (uint8_t *)entropy;
115     size_t idx;
116 
117     /* The entropy must be equal to 256 bit. The spec allows for a lower
118      * amout of entropy to be passed during instantiation, then using a
119      * derivation function at this point to reach 256 bit. But this implementation
120      * focuses on lower complexity hence the derivation function is not used
121      */
122     assert(entropy_len == CC3XX_DRBG_CTR_SEEDLEN);
123 
124     /* This implementation does not use a derivation function, hence the nonce
125      * is not used during the instantiation procedure
126      */
127     (void)nonce;
128     (void)nonce_len;
129 
130     if (personalization != NULL) {
131 
132         /* If present and less than 256 bit, it's equivalent to be zero padded */
133         assert(personalization_len <= CC3XX_DRBG_CTR_SEEDLEN);
134 
135 #ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
136         cc3xx_dpa_hardened_word_copy(personalized_entropy,
137                                      (uint32_t *)entropy,
138                                      CC3XX_DRBG_CTR_SEEDLEN_WORDS);
139 #else
140         memcpy(personalized_entropy, entropy, CC3XX_DRBG_CTR_SEEDLEN);
141 #endif
142         for (idx = 0; idx < personalization_len; idx++) {
143             ((uint8_t *)personalized_entropy)[idx] ^= personalization[idx];
144         }
145         seed_material = (uint8_t *)personalized_entropy;
146     }
147 
148     memset(state, 0, sizeof(struct cc3xx_drbg_ctr_state_t));
149 
150     err = cc3xx_drbg_ctr_update(state, seed_material, CC3XX_DRBG_CTR_SEEDLEN);
151     if (err != CC3XX_ERR_SUCCESS) {
152         goto out;
153     }
154 
155     state->reseed_counter = 1;
156 
157 out:
158     if (personalization != NULL) {
159         /* Make sure the seed material on the stack gets overwritten with random values */
160         cc3xx_secure_erase_buffer(personalized_entropy, CC3XX_DRBG_CTR_SEEDLEN_WORDS);
161     }
162 
163     return err;
164 }
165 
cc3xx_lowlevel_drbg_ctr_generate(struct cc3xx_drbg_ctr_state_t * state,size_t len_bits,uint8_t * returned_bits,const uint8_t * additional_input,size_t additional_input_len)166 cc3xx_err_t cc3xx_lowlevel_drbg_ctr_generate(
167     struct cc3xx_drbg_ctr_state_t *state,
168     size_t len_bits, uint8_t *returned_bits,
169     const uint8_t *additional_input, size_t additional_input_len)
170 {
171     cc3xx_err_t err;
172     const uint8_t all_zeros[CC3XX_DRBG_CTR_SEEDLEN] = {0};
173     const uint8_t *p_additional_input = all_zeros;
174     size_t produced_bits = 0;
175     size_t num_whole_blocks = (len_bits/8)/CC3XX_DRBG_CTR_SEEDLEN;
176     struct cc3xx_aes_state_t aes_state;
177     size_t idx;
178 
179     if (state->reseed_counter == UINT32_MAX) {
180         /* When we reach 2^32 invocations we must reseed */
181         return CC3XX_ERR_DRBG_RESEED_REQUIRED;
182     }
183 
184     /* The implementation constraints the output length to be byte aligned to
185      * reduce complexity
186      */
187     assert(len_bits != 0);
188     assert((len_bits % 8) == 0);
189 
190     if (additional_input != NULL) {
191 
192         assert(additional_input_len <= CC3XX_DRBG_CTR_SEEDLEN);
193 
194         err = cc3xx_drbg_ctr_update(state, additional_input, additional_input_len);
195         if (err != CC3XX_ERR_SUCCESS) {
196             return err;
197         }
198         p_additional_input = additional_input;
199     }
200 
201     long_inc((uint32_t *)state->block_v, sizeof(state->block_v));
202 
203     err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_ENCRYPT,
204                                   CC3XX_AES_MODE_CTR,
205                                   CC3XX_AES_KEY_ID_USER_KEY,
206                                   (const uint32_t *)state->key_k, CC3XX_AES_KEYSIZE_128,
207                                   (const uint32_t *)state->block_v, sizeof(state->block_v));
208     if (err != CC3XX_ERR_SUCCESS) {
209         return err;
210     }
211 
212     cc3xx_lowlevel_aes_set_output_buffer(returned_bits, len_bits/8); /* length is in bytes */
213 
214     for (idx = 0; idx < num_whole_blocks; idx++) {
215         err = cc3xx_lowlevel_aes_update(all_zeros, sizeof(all_zeros));
216         if (err != CC3XX_ERR_SUCCESS) {
217             return err;
218         }
219 
220         produced_bits += (CC3XX_DRBG_CTR_SEEDLEN * 8);
221     }
222 
223     /* Deal with a partial block */
224     if ((len_bits - produced_bits) != 0) {
225         /* Produce the last block */
226         err = cc3xx_lowlevel_aes_update(all_zeros, (len_bits - produced_bits)/8); /* in bytes */
227         if (err != CC3XX_ERR_SUCCESS) {
228             return err;
229         }
230     }
231 
232     /* We need to get the value of the counter back from the AES subsystem
233      * as it's required in update()
234      */
235     cc3xx_lowlevel_aes_get_state(&aes_state);
236 
237     err = cc3xx_lowlevel_aes_finish(NULL, NULL);
238     if (err != CC3XX_ERR_SUCCESS) {
239         return err;
240     }
241 
242 #ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
243     cc3xx_dpa_hardened_word_copy((uint32_t *)state->block_v,
244                                  aes_state.ctr,
245                                  CC3XX_DRBG_CTR_BLOCKLEN_WORDS);
246 #else
247     memcpy(state->block_v, aes_state.ctr, sizeof(state->block_v));
248 #endif
249     long_dec((uint32_t *)state->block_v, sizeof(state->block_v));
250 
251     /* Update for back tracking resistance */
252     err = cc3xx_drbg_ctr_update(state, p_additional_input, CC3XX_DRBG_CTR_SEEDLEN);
253     if (err != CC3XX_ERR_SUCCESS) {
254         return err;
255     }
256 
257     state->reseed_counter++;
258 
259     return err;
260 }
261 
cc3xx_lowlevel_drbg_ctr_reseed(struct cc3xx_drbg_ctr_state_t * state,const uint8_t * entropy,size_t entropy_len,const uint8_t * additional_input,size_t additional_input_len)262 cc3xx_err_t cc3xx_lowlevel_drbg_ctr_reseed(
263     struct cc3xx_drbg_ctr_state_t *state,
264     const uint8_t *entropy, size_t entropy_len,
265     const uint8_t *additional_input, size_t additional_input_len)
266 {
267     cc3xx_err_t err;
268     uint32_t personalized_entropy[CC3XX_DRBG_CTR_SEEDLEN_WORDS];
269     uint8_t *seed_material = (uint8_t *)entropy;
270     size_t idx;
271 
272     assert(entropy_len == CC3XX_DRBG_CTR_SEEDLEN);
273 
274     if (additional_input != NULL) {
275         assert(additional_input_len <= CC3XX_DRBG_CTR_SEEDLEN);
276 #ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
277         cc3xx_dpa_hardened_word_copy(personalized_entropy,
278                                      (uint32_t *)entropy,
279                                      CC3XX_DRBG_CTR_SEEDLEN_WORDS);
280 #else
281         memcpy(personalized_entropy, entropy, entropy_len);
282 #endif
283         for (idx = 0; idx < additional_input_len; idx++) {
284             ((uint8_t *)personalized_entropy)[idx] ^= additional_input[idx];
285         }
286         seed_material = (uint8_t *)personalized_entropy;
287     }
288 
289     err = cc3xx_drbg_ctr_update(state, seed_material, entropy_len);
290     if (err != CC3XX_ERR_SUCCESS) {
291         goto out;
292     }
293 
294     state->reseed_counter = 1;
295 
296 out:
297     if (additional_input != NULL) {
298         /* Make sure the seed material on the stack gets overwritten with random values */
299         cc3xx_secure_erase_buffer(personalized_entropy, CC3XX_DRBG_CTR_SEEDLEN_WORDS);
300     }
301 
302     return err;
303 }
304 
cc3xx_lowlevel_drbg_ctr_uninit(struct cc3xx_drbg_ctr_state_t * state)305 cc3xx_err_t cc3xx_lowlevel_drbg_ctr_uninit(struct cc3xx_drbg_ctr_state_t *state)
306 {
307     /* Secure erase only the sensitive material*/
308     cc3xx_secure_erase_buffer((uint32_t *)state, CC3XX_DRBG_CTR_SEEDLEN_WORDS);
309 
310     memset(state, 0, sizeof(struct cc3xx_drbg_ctr_state_t));
311 
312     return CC3XX_ERR_SUCCESS;
313 }
314