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