1 /*--------------------------------------------------------------------------*/
2 /* Copyright 2020-2021 NXP */
3 /* */
4 /* NXP Confidential. This software is owned or controlled by NXP and may */
5 /* only be used strictly in accordance with the applicable license terms. */
6 /* By expressly accepting such terms or by downloading, installing, */
7 /* activating and/or otherwise using the software, you are agreeing that */
8 /* you have read, and that you agree to comply with and are bound by, such */
9 /* license terms. If you do not agree to be bound by the applicable license */
10 /* terms, then you may not retain, install, activate or otherwise use the */
11 /* software. */
12 /*--------------------------------------------------------------------------*/
13
14 /**
15 * @file mcuxClCss_Rng.c
16 * @brief CSSv2 implementation for random number generation.
17 * This file implements the functions declared in mcuxClCss_Rng.h.
18 */
19
20
21 #include <mcuxClCss_Rng.h> // Implement mcuxClCss interface "Rng"
22 #include <mcuxClMemory.h>
23 #include <mcuxCsslFlowProtection.h>
24 #include <toolchain.h>
25 #include <mcuxClCss.h>
26 #include <internal/mcuxClCss_Internal.h>
27
28 #define RANDOM_BIT_ARRAY_SIZE 4U
29
30 #define DRBG_TEST_MODE_INSTANTIATE ((uint32_t)0U)
31 #define DRBG_TEST_MODE_EXTRACT ((uint32_t)1U)
32 #define DRBG_TEST_MODE_AES_ECB ((uint32_t)3U)
33 #define DRBG_TEST_MODE_AES_CTR ((uint32_t)2U)
34
35
36
37 // Command name change -- should move to top level platform header
38 #ifndef ID_CFG_CSS_CMD_RND_REQ
39 #define ID_CFG_CSS_CMD_RND_REQ ID_CFG_CSS_CMD_DRBG_REQ
40 #endif
41
42 // Utility code of mcuxClCss implementation for PRNG access
43
44 /**
45 * Gets a pseudo-random 32-bit integer from the CSS PRNG.
46 */
css_getPRNGWord(void)47 static inline uint32_t css_getPRNGWord(
48 void)
49 {
50 return IP_CSS->CSS_PRNG_DATOUT_b.PRNG_DATOUT;
51 }
52
53 // Implementation of mcuxClCss interface "Rng"
54
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgRequest_Async)55 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgRequest_Async)
56 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgRequest_Async(
57 uint8_t * pOutput,
58 size_t outputLength)
59 {
60 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgRequest_Async);
61
62 MCUXCLCSS_INPUT_PARAM_CHECK_PROTECTED(mcuxClCss_Rng_DrbgRequest_Async, (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MIN_SIZE > outputLength) ||
63 (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MAX_SIZE < outputLength) ||
64 (0U != outputLength % 4U));
65
66 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
67 if (MCUXCLCSS_ISBUSY)
68 {
69 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgRequest_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
70 }
71
72 MCUXCLCSS_SETCSSOUTPUT(pOutput, outputLength);
73
74 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_RND_REQ, 0U, CSS_CMD_LITTLE_ENDIAN);
75
76 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgRequest_Async, MCUXCLCSS_STATUS_OK_WAIT);
77 }
78
79
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestInstantiate_Async)80 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestInstantiate_Async)
81 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestInstantiate_Async(
82 uint8_t const * pEntropy)
83 {
84 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestInstantiate_Async);
85
86 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
87 if (MCUXCLCSS_ISBUSY)
88 {
89 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestInstantiate_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
90 }
91
92 MCUXCLCSS_SETCSSINPUT0_FIXEDSIZE(pEntropy);
93
94 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_INSTANTIATE, CSS_CMD_LITTLE_ENDIAN);
95
96 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestInstantiate_Async, MCUXCLCSS_STATUS_OK_WAIT);
97 }
98
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestExtract_Async)99 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestExtract_Async)
100 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestExtract_Async(
101 uint8_t * pOutput,
102 size_t outputLength)
103 {
104 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestExtract_Async);
105
106 MCUXCLCSS_INPUT_PARAM_CHECK_PROTECTED(mcuxClCss_Rng_DrbgTestExtract_Async, (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MIN_SIZE > outputLength) ||
107 (MCUXCLCSS_RNG_DRBG_TEST_EXTRACT_OUTPUT_MAX_SIZE < outputLength) ||
108 (0U != outputLength % 4U));
109
110 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
111 if (MCUXCLCSS_ISBUSY)
112 {
113 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestExtract_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
114 }
115
116 MCUXCLCSS_SETCSSOUTPUT(pOutput, outputLength);
117
118 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_EXTRACT, CSS_CMD_LITTLE_ENDIAN);
119
120 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestExtract_Async, MCUXCLCSS_STATUS_OK_WAIT);
121 }
122
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesEcb_Async)123 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesEcb_Async)
124 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestAesEcb_Async(
125 uint8_t const * pDataKey,
126 uint8_t * pOutput)
127 {
128 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestAesEcb_Async);
129
130 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
131 if (MCUXCLCSS_ISBUSY)
132 {
133 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesEcb_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
134 }
135
136 MCUXCLCSS_SETCSSINPUT1_FIXEDSIZE(pDataKey);
137 MCUXCLCSS_SETCSSOUTPUT_FIXEDSIZE(pOutput);
138
139 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_AES_ECB, CSS_CMD_LITTLE_ENDIAN);
140
141 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesEcb_Async, MCUXCLCSS_STATUS_OK_WAIT);
142 }
143
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesCtr_Async)144 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_DrbgTestAesCtr_Async)
145 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_DrbgTestAesCtr_Async(
146 uint8_t const * pData,
147 size_t dataLength,
148 uint8_t const * pIvKey,
149 uint8_t * pOutput)
150 {
151 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_DrbgTestAesCtr_Async);
152
153 MCUXCLCSS_INPUT_PARAM_CHECK_PROTECTED(mcuxClCss_Rng_DrbgTestAesCtr_Async, (0U != (dataLength % 16U)) || (0U == dataLength));
154
155 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
156 if (MCUXCLCSS_ISBUSY)
157 {
158 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesCtr_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
159 }
160
161 MCUXCLCSS_SETCSSINPUT0(pData, dataLength);
162 MCUXCLCSS_SETCSSINPUT1_FIXEDSIZE(pIvKey);
163 MCUXCLCSS_SETCSSOUTPUT_FIXEDSIZE(pOutput);
164
165 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DRBG_TEST, DRBG_TEST_MODE_AES_CTR, CSS_CMD_LITTLE_ENDIAN);
166
167 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_DrbgTestAesCtr_Async, MCUXCLCSS_STATUS_OK_WAIT);
168 }
169
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigLoad_Async)170 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigLoad_Async)
171 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_Dtrng_ConfigLoad_Async(
172 uint8_t const * pInput)
173 {
174 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_Dtrng_ConfigLoad_Async);
175
176 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
177 if (MCUXCLCSS_ISBUSY)
178 {
179 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigLoad_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
180 }
181
182 MCUXCLCSS_SETCSSINPUT0_FIXEDSIZE(pInput);
183 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DTRNG_CFG_LOAD, 0U, CSS_CMD_LITTLE_ENDIAN);
184
185 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigLoad_Async, MCUXCLCSS_STATUS_OK_WAIT);
186 }
187
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async)188 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async)
189 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async(
190 uint8_t const * pInput,
191 uint8_t * pOutput)
192 {
193 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async);
194
195 /* CSS SFRs are not cached => Tell SW to wait for CSS to come back from BUSY state before modifying the SFRs */
196 if (MCUXCLCSS_ISBUSY)
197 {
198 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async, MCUXCLCSS_STATUS_SW_CANNOT_INTERRUPT);
199 }
200
201 MCUXCLCSS_SETCSSINPUT0_FIXEDSIZE(pInput);
202 MCUXCLCSS_SETCSSOUTPUT_FIXEDSIZE(pOutput);
203 MCUXCLCSS_STARTCOMMAND(ID_CFG_CSS_CMD_DTRNG_EVAL, 0U, CSS_CMD_LITTLE_ENDIAN);
204
205 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Rng_Dtrng_ConfigEvaluate_Async, MCUXCLCSS_STATUS_OK_WAIT);
206 }
207
208
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandomWord)209 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandomWord)
210 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Prng_GetRandomWord(
211 uint32_t * pWord)
212 {
213 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Prng_GetRandomWord);
214
215 *pWord = css_getPRNGWord();
216
217 /* check if enough entropy is available */
218 if (1U == IP_CSS->CSS_ERR_STATUS_b.PRNG_ERR)
219 {
220 /* clear CSS error flags */
221 (void) mcuxClCss_ResetErrorFlags(); /* always returns MCUXCLCSS_STATUS_OK. */
222
223 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandomWord, MCUXCLCSS_STATUS_HW_PRNG);
224 }
225
226 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandomWord, MCUXCLCSS_STATUS_OK);
227 }
228
MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandom)229 MCUX_CSSL_FP_FUNCTION_DEF(mcuxClCss_Prng_GetRandom)
230 MCUXCLCSS_API mcuxClCss_Status_Protected_t mcuxClCss_Prng_GetRandom(
231 uint8_t * pOutput,
232 size_t outputLength)
233 {
234 MCUX_CSSL_FP_FUNCTION_ENTRY(mcuxClCss_Prng_GetRandom);
235
236 uint8_t * bytePtr = pOutput;
237 uint8_t * const pOutputEnd = pOutput + outputLength;
238
239 /* Fetch one word of PRNG and fill the leading "not word aligned" bytes */
240 if (0u != ((uint32_t) bytePtr & 0x03u))
241 {
242 uint32_t randomWord = css_getPRNGWord();
243 do
244 {
245 *bytePtr = (uint8_t) (randomWord & 0xFFu);
246 bytePtr += 1u;
247 randomWord >>= 8u;
248 } while ((0u != ((uint32_t) bytePtr & 0x03u)) && (pOutputEnd > bytePtr));
249 }
250
251 /* Fill the specified buffer wordwise */
252 uint8_t * const pOutputWordEnd = (uint8_t*) ((uint32_t) pOutputEnd & 0xFFFFFFFCu);
253 while (pOutputWordEnd > bytePtr)
254 {
255 mcuxClMemory_StoreLittleEndian32(bytePtr, css_getPRNGWord());
256 bytePtr += 4;
257 }
258
259 /* Fetch one word of PRNG and fill the remaining "less than one word" bytes */
260 if (pOutputEnd > bytePtr)
261 {
262 uint32_t randomWord = css_getPRNGWord();
263 do
264 {
265 *bytePtr = (uint8_t) (randomWord & 0xFFu);
266 bytePtr += 1u;
267 randomWord >>= 8u;
268 } while (pOutputEnd > bytePtr);
269 }
270
271 /* check if enough entropy is available */
272 if (1U == IP_CSS->CSS_ERR_STATUS_b.PRNG_ERR)
273 {
274 /* clear CSS error flags */
275 (void) mcuxClCss_ResetErrorFlags(); /* always returns MCUXCLCSS_STATUS_OK. */
276
277 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandom, MCUXCLCSS_STATUS_HW_PRNG);
278 }
279
280 MCUX_CSSL_FP_FUNCTION_EXIT(mcuxClCss_Prng_GetRandom, MCUXCLCSS_STATUS_OK);
281 }
282