1/*
2 * Copyright 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017, 2019, 2023-2026 NXP
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6/*! *********************************************************************************=
7 * \file
8 * This file is the source file for the RNG (Random Number Generator) Interface.
9 * Its supports various RNG implementations including hardware RNG, ELE S200,
10 * and software-based.
11 * An alternate PSA implementation exists.
12 ********************************************************************************** */
13#include <stdalign.h>
14#include <stdint.h>
15#include "fwk_config.h"
16#include "RNG_Interface.h"
17#include "FunctionLib.h"
18#include "fsl_common.h" /* includes fsl_device_registers.h */
19#include "fsl_os_abstraction.h"
20#include "fwk_platform_rng.h"
21#if defined(gPlatformHasNbu_d) || defined(gPlatformIsNbu_d)
22#include "fwk_platform_ics.h"
23#endif
24
25#if defined(gRngEnableAutoReseed_d) && (gRngEnableAutoReseed_d > 0)
26#include "fwk_workq.h"
27#endif
28
29#ifndef gRngUseSecLib_d
30#define gRngUseSecLib_d 1
31#endif
32
33#if (gRngUseSecLib_d == 1)
34#include "SecLib.h"
35#else
36/* If the PRNG is using a Lehmer linear congruential generator, no cryptographic method is used, neither SHA256, nor
37 HMAC or AES-CTR. In this case the implementation avoids the dependency on the SecLib. Using the S200 TRNG, still
38 pulls this dependency. Seeding the PRNG requires a proper entropy collection. The NBU uses the S200 EdgeLock TRNG
39 service indirectly via RPMSG for seeding purposes.
40 */
41#define gRngUseLehmerGen_c 1
42#endif
43
44#if defined(CPU_MCXW345CHNA)
45#define TRNG0 TRNG
46#define TRNG0_IRQn TRNG_IRQn
47#endif
48
49#if defined gRngUseSecureSubSystem_d && (gRngUseSecureSubSystem_d != 0)
50#include "sss_crypto.h"
51#else
52#if ((defined(FSL_FEATURE_SOC_TRNG_COUNT)) && (FSL_FEATURE_SOC_TRNG_COUNT > 0U))
53#include "fsl_trng.h"
54#elif ((defined(FSL_FEATURE_SOC_RNG_COUNT)) && (FSL_FEATURE_SOC_RNG_COUNT > 0U))
55#include "fsl_rnga.h"
56#elif defined(gRngUseRngAdapter_c) && (gRngUseRngAdapter_c > 0)
57#include "fsl_adapter_rng.h"
58#endif
59#endif
60#if defined(gRngSeedStorageAddr_d) || defined(gRngSeedHwParamStorage_d)
61#include "HWParameter.h"
62#endif
63
64/*! *********************************************************************************
65*************************************************************************************
66* Private macros
67*************************************************************************************
68********************************************************************************** */
69
70#ifndef gRNG_UsePhyRngForInitialSeed_d
71#define gRNG_UsePhyRngForInitialSeed_d 0
72#endif
73
74#define mPRNG_NoOfBits_c (256U)
75#define mPRNG_NoOfBytes_c (mPRNG_NoOfBits_c / 8U)
76#define mPRNG_NoOfLongWords_c (mPRNG_NoOfBits_c / 32U)
77
78#ifndef RAISE_ERROR
79#define RAISE_ERROR(_X_, _VAL_) \
80 { \
81 _X_ = _VAL_; \
82 break; \
83 }
84#endif
85
86#if (defined(gRngUseSecLib_d) && (gRngUseSecLib_d > 0))
87extern secResultType_t SecLibMutexCreate(void);
88
89/* Share mutex with SecLib if RNG involves crypto, or Secure subsystem */
90#define RNG_MUTEX_CREATE() SecLibMutexCreate()
91#define RNG_MUTEX_LOCK() (void)SecLibMutexLock()
92#define RNG_MUTEX_UNLOCK() (void)SecLibMutexUnlock()
93
94#else /* gRngUseSecLib_d */
95
96#define RNG_MUTEX_CREATE() gSecSuccess_c
97#define RNG_MUTEX_LOCK()
98#define RNG_MUTEX_UNLOCK()
99
100#endif /* gRngUseSecLib_d */
101
102#if ((defined(FSL_FEATURE_SOC_TRNG_COUNT)) && (FSL_FEATURE_SOC_TRNG_COUNT > 0U))
103#if (defined(RW610_SERIES) || defined(RW612_SERIES))
104#define TRNG0 TRNG
105#define TRNG0_IRQn TRNG_IRQn
106#endif
107#endif
108
109typedef struct rng_ctx_t
110{
111 bool_t Initialized;
112 bool_t mPrngIsSeeded;
113 bool_t needReseed;
114 alignas(4) uint32_t PrngSeed[mPRNG_NoOfLongWords_c];
115 uint32_t mPRNG_Requests;
116} RNG_context_t;
117
118/*! *********************************************************************************
119*************************************************************************************
120* Public prototypes
121*************************************************************************************
122********************************************************************************** */
123#if ((!defined(FSL_FEATURE_SOC_TRNG_COUNT)) || (FSL_FEATURE_SOC_TRNG_COUNT == 0U)) && \
124 ((!defined(FSL_FEATURE_SOC_RNG_COUNT)) || (FSL_FEATURE_SOC_RNG_COUNT == 0U)) && (gRNG_UsePhyRngForInitialSeed_d)
125extern void PhyGetRandomNo(uint32_t *pRandomNo);
126#endif
127/*! *********************************************************************************
128*************************************************************************************
129* Private prototypes
130*************************************************************************************
131********************************************************************************** */
132#if (defined gRngUseLehmerGen_c && (gRngUseLehmerGen_c > 0))
133static uint32_t RNG_LCG(uint32_t prev_state);
134#endif
135
136#if ((defined(FSL_FEATURE_SOC_TRNG_COUNT)) && (FSL_FEATURE_SOC_TRNG_COUNT > 0U))
137static void TRNG_GoToSleep(void);
138#endif
139
140static int RNG_Specific_Init(uint32_t *pSeed);
141static int RNG_Specific_GetRandomData(uint8_t *pOut, uint16_t outBytes);
142
143#if defined(gRngSeedHwParamStorage_d) || defined(gRngSeedStorageAddr_d)
144static uint32_t Rng_read_seed_from_flash(void);
145static void Rng_save_seed_to_flash(uint32_t seed);
146#endif
147
148static int RNG_GetPseudoRandomDataWithContext(void *ctx_data, unsigned char *output, size_t len);
149
150#if defined(gRngEnableAutoReseed_d) && (gRngEnableAutoReseed_d > 0)
151static void RNG_seed_needed_handler(fwk_work_t *work);
152#endif
153
154/*! *********************************************************************************
155*************************************************************************************
156* Private memory declarations
157*************************************************************************************
158********************************************************************************** */
159
160static RNG_context_t rng_ctx = {
161 .Initialized = FALSE,
162 .mPrngIsSeeded = FALSE,
163 .needReseed = FALSE,
164 .PrngSeed[0 ... mPRNG_NoOfLongWords_c - 1] = 0U,
165 .mPRNG_Requests = gRngMaxRequests_d,
166};
167
168#if defined(gRngEnableAutoReseed_d) && (gRngEnableAutoReseed_d > 0)
169static fwk_work_t seed_needed_work = {
170 .handler = RNG_seed_needed_handler,
171};
172#endif
173
174/*! *********************************************************************************
175*************************************************************************************
176* Public functions
177*************************************************************************************
178********************************************************************************** */
179
180/*! *********************************************************************************
181 * \brief Initialize the RNG HW module.
182 * The PRNG seeding may be asynchronous, depending on platforms.
183 *
184 * \return Status of the RNG initialization sequence
185 *
186 ********************************************************************************** */
187int RNG_Init(void)
188{
189 int status = gRngInternalError_d;
190 do
191 {
192 /* Check if RNG is already initialized */
193 if (rng_ctx.Initialized)
194 {
195 status = gRngSuccess_d;
196 break;
197 }
198
199#if defined(gRngUseSecLib_d) && (gRngUseSecLib_d > 0)
200 /* Create mutex here in case it was not done already.
201 * Does nothing without error otherwise.
202 */
203 if (RNG_MUTEX_CREATE() != gSecSuccess_c)
204 {
205 break;
206 }
207#endif
208
209#if defined(gRngEnableAutoReseed_d) && (gRngEnableAutoReseed_d > 0)
210 /* The workqueue is used to post and schedule seed
211 * trig upon user demand using RNG_NotifyReseedNeeded().
212 */
213 if (WORKQ_InitSysWorkQ() < 0)
214 {
215 break;
216 }
217#endif
218
219#if defined(gPlatformHasNbu_d)
220 /* Enabled reseed requests from NBU */
221 PLATFORM_RegisterReceivedSeedRequest(&RNG_NotifyReseedNeeded);
222#endif
223
224#if defined(gPlatformIsNbu_d)
225 PLATFORM_RegisterSetNewSeed(&RNG_SetExternalSeed);
226#endif
227
228 rng_ctx.mPrngIsSeeded = FALSE;
229 rng_ctx.needReseed = FALSE;
230 rng_ctx.mPRNG_Requests = gRngMaxRequests_d;
231 status = RNG_Specific_Init(rng_ctx.PrngSeed);
232 /* RNG_Specific_Init retuns with mPrngIsSeeded set to TRUE if the seed can be obtained synchronously */
233
234 if (status != gRngSuccess_d)
235 {
236 break;
237 }
238
239 rng_ctx.Initialized = TRUE;
240 /* If seed was not set during RNG_Specific_Init initialization, skip */
241 if (!rng_ctx.mPrngIsSeeded)
242 {
243 break;
244 }
245 status = RNG_SetSeed();
246
247 } while (false);
248
249 return status;
250}
251
252/*! *********************************************************************************
253 * \brief Reinitialize the RNG module post-wakeup action
254 * Does nothing except for Secure-Subsystem that require an action to get
255 * ready after wakeup.
256 *
257 * \return Status of the RNG initialization sequence.
258 *
259 ********************************************************************************** */
260int RNG_ReInit(void)
261{
262 int status = gRngSuccess_d;
263#if gRngUseSecureSubSystem_d
264 status = CRYPTO_ReinitHardware();
265#endif
266 return status;
267}
268
269/*! *********************************************************************************
270 * \brief DeInitialize the RNG module.
271 * Resets the RNG context variables. Only used for test purposes.
272 *
273 * \return none
274 *
275 ********************************************************************************** */
276void RNG_DeInit(void)
277{
278 rng_ctx.Initialized = FALSE;
279 rng_ctx.mPrngIsSeeded = FALSE;
280 rng_ctx.needReseed = FALSE;
281}
282
283int RNG_GetTrueRandomNumber(uint32_t *pRandomNo)
284{
285 int status;
286
287 do
288 {
289 int rng_ret;
290
291 if (pRandomNo == NULL)
292 {
293 status = gRngBadArguments_d;
294 break;
295 }
296 if (!rng_ctx.Initialized)
297 {
298 status = gRngNotInitialized_d;
299 break;
300 }
301
302 rng_ret = RNG_Specific_GetRandomData((uint8_t *)pRandomNo, (uint16_t)sizeof(uint32_t));
303 if (rng_ret <= 0)
304 {
305 status = gRngInternalError_d;
306 break;
307 }
308
309 status = gRngSuccess_d;
310
311 } while (false);
312 return status;
313}
314
315/*! *********************************************************************************
316 * \brief Pseudo Random Number Generator (PRNG) implementation
317 * according to NIST FIPS Publication 186-2, APPENDIX 3
318 *
319 * Let x be the signer's private key.
320 * The following may be used to generate m values of x:
321 * Step 1. Choose a new, secret value for the seed-key, XKEY.
322 * Step 2. In hexadecimal notation let
323 * t = 67452301 EFCDAB89 98BADCFE 10325476 C3D2E1F0.
324 * This is the initial value for H0 || H1 || H2 || H3 || H4 in the SHS.
325 * Step 3. For j = 0 to m - 1 do
326 * a. XSEEDj = optional user input.
327 * b. XVAL = (XKEY + XSEEDj) mod 2^b
328 * c. xj = G(t,XVAL) mod q
329 * d. XKEY = (1 + XKEY + xj) mod 2^b
330 *
331 * \param[out] pOut - pointer to the output buffer
332 * \param[in] outBytes - the number of bytes to be copied (1-20)
333 * \param[in] pSeed - optional user SEED. Should be NULL if not used.
334 *
335 * \return If positive ( > 0) the number of random bytes produced,
336 * If negative denotes an error:
337 * gRngBadArguments_d if pOut is NULL or outBytes is 0 OR
338 * gRngNotInitialized_d if RNG_Init was not priorly called OR
339 * gRngInternalError_d in case of driver error OR
340 * gRngReseedPending_d if new call happened whereas reseed request
341 * was pending already .
342 *
343 ********************************************************************************** */
344int RNG_GetPseudoRandomData(uint8_t *pOut, uint8_t outBytes, uint8_t *pSeed)
345{
346 int ret;
347 do
348 {
349 uint16_t outputBytes = 0u;
350
351 if (pOut == NULL || outBytes == 0u)
352 {
353 ret = gRngBadArguments_d;
354 break;
355 }
356
357 if (rng_ctx.Initialized != TRUE)
358 {
359 ret = gRngNotInitialized_d;
360 break;
361 }
362
363 outputBytes = (uint16_t)outBytes;
364
365#if !defined gRngUseSecureSubSystem_d || (gRngUseSecureSubSystem_d == 0)
366 if (!rng_ctx.mPrngIsSeeded)
367 {
368 /* request reseed */
369 if (RNG_NotifyReseedNeeded() < 0)
370 {
371 /* if request fails, bad news */
372 ret = gRngInternalError_d;
373 }
374 else
375 {
376 /* wait for reseed to retry */
377 ret = gRngReseedPending_d;
378 }
379 break;
380 }
381 else
382 {
383 uint16_t i;
384 /* PRNG buffer used for both input and output */
385 uint32_t prngBuffer[mPRNG_NoOfLongWords_c] = {0UL};
386
387 if (pSeed != NULL)
388 {
389 rng_ctx.mPRNG_Requests = 1U;
390 }
391
392 if (rng_ctx.mPRNG_Requests == gRngMaxRequests_d)
393 {
394 if (RNG_NotifyReseedNeeded() < 0)
395 {
396 ret = gRngInternalError_d;
397 break;
398 }
399 }
400 /* Continue in spite of the gRngMaxRequests_d limit reached */
401 rng_ctx.mPRNG_Requests++;
402
403 /* b. XVAL = (XKEY + XSEEDj) mod 2^b */
404 for (i = 0u; i < mPRNG_NoOfLongWords_c; i++)
405 {
406 prngBuffer[i] = rng_ctx.PrngSeed[i]; /* PrngSeed is the XKEY */
407 }
408 /* a. XSEEDj = optional user input. */
409 if (pSeed != NULL)
410 {
411 for (i = 0u; i < mPRNG_NoOfBytes_c; i++)
412 {
413 ((uint8_t *)prngBuffer)[i] += pSeed[i];
414 }
415 }
416
417 /* c. xj = G(t,XVAL) mod q
418 ***************************/
419#if (defined gRngUseLehmerGen_c && (gRngUseLehmerGen_c > 0))
420 for (i = 0u; i < mPRNG_NoOfLongWords_c; i++)
421 {
422 uint32_t rand_val;
423 rand_val = RNG_LCG(rng_ctx.PrngSeed[i]); /* PrngSeed is the XKEY */
424 prngBuffer[i] = rand_val;
425 }
426#else
427 SHA256_Hash((uint8_t *)prngBuffer, mPRNG_NoOfBytes_c, (uint8_t *)prngBuffer);
428#endif
429 /* d. XKEY = (1 + XKEY + xj) mod 2^b */
430 rng_ctx.PrngSeed[0] += 1U; /* PrngSeed is the XKEY */
431 for (i = 0u; i < mPRNG_NoOfLongWords_c; i++)
432 {
433 rng_ctx.PrngSeed[i] += prngBuffer[i];
434 }
435
436 /* Check if the length provided exceeds the output data size */
437 if (outputBytes > mPRNG_NoOfBytes_c)
438 {
439 outputBytes = mPRNG_NoOfBytes_c;
440 }
441 /* Copy the generated number */
442 for (i = 0u; i < outputBytes; i++)
443 {
444 pOut[i] = ((uint8_t *)prngBuffer)[i];
445 }
446 }
447 ret = (int)outputBytes;
448#else /* gRngUseSecureSubSystem_d */
449 if (outputBytes > mPRNG_NoOfBytes_c)
450 {
451 outputBytes = mPRNG_NoOfBytes_c;
452 }
453 ret = RNG_Specific_GetRandomData(pOut, (uint16_t)outputBytes);
454#endif
455
456 } while (false);
457 return ret;
458}
459
460static int RNG_GetPseudoRandomDataWithContext(void *ctx_data, unsigned char *output, size_t len)
461{
462 NOT_USED(ctx_data);
463 int st = gRngBadArguments_d;
464
465 do
466 {
467 uint8_t *p;
468 size_t req_sz;
469 if (len == 0u)
470 {
471 st = gRngBadArguments_d;
472 break;
473 }
474 if (output == NULL)
475 {
476 st = gRngBadArguments_d;
477 break;
478 }
479
480 p = output;
481 req_sz = len;
482
483 while (req_sz > 0u)
484 {
485 uint32_t sz = MIN(req_sz, mPRNG_NoOfBytes_c);
486
487 st = RNG_GetPseudoRandomData(p, (uint8_t)sz, NULL);
488
489 if ((st > 0) && (st == (int)sz))
490 {
491 req_sz -= sz;
492 p += sz;
493 }
494 else
495 {
496 /* st contains an error code */
497 break;
498 }
499 }
500 if (st < 0)
501 {
502 break;
503 }
504 /* The expectation from the external caller of the function pointer is that 0 is returned
505 if its request is fulfilled, i.e. all random bytes were produced */
506 if (req_sz == 0u)
507 {
508 st = 0;
509 }
510 else
511 {
512 st = -1;
513 }
514 } while (false);
515 return st;
516}
517
518/*! *********************************************************************************
519 * \brief Returns a pointer to the general PRNG function
520 * Call RNG_SetPseudoRandomNoSeed() before calling this function.
521 *
522 * \return Function pointer to the general PRNG function or NULL if it
523 * was not seeded.
524 *
525 ********************************************************************************** */
526fpRngPrng_t RNG_GetPrngFunc(void)
527{
528 if (rng_ctx.mPrngIsSeeded == TRUE)
529 {
530 return RNG_GetPseudoRandomDataWithContext;
531 }
532 else
533 {
534 return NULL;
535 }
536}
537
538/*! *********************************************************************************
539 * \brief Returns a pointer to the general PRNG context
540 * Call RNG_SetPseudoRandomNoSeed() before calling this function.
541 *
542 * \return Function pointer to the general PRNG context or NULL if it
543 * was not initialized correctly.
544 *
545 ********************************************************************************** */
546void *RNG_GetPrngContext(void)
547{
548 if (rng_ctx.Initialized == TRUE)
549 {
550 return (void *)&rng_ctx;
551 }
552 else
553 {
554 return NULL;
555 }
556}
557
558int RNG_SetSeed(void)
559{
560 int status;
561 do
562 {
563 if (rng_ctx.Initialized != TRUE)
564 {
565 status = gRngNotInitialized_d;
566 break;
567 }
568
569 uint16_t nb_bytes = 0u;
570 status = RNG_Specific_GetRandomData((uint8_t *)rng_ctx.PrngSeed, mPRNG_NoOfBytes_c);
571 if (status <= 0)
572 {
573 break;
574 }
575 nb_bytes = (uint16_t)status;
576 if (nb_bytes == mPRNG_NoOfBytes_c)
577 {
578 rng_ctx.mPRNG_Requests = 1U;
579 rng_ctx.mPrngIsSeeded = TRUE;
580
581 if (PLATFORM_SendRngSeed((uint8_t *)rng_ctx.PrngSeed, mPRNG_NoOfBytes_c) >= 0)
582 {
583 rng_ctx.needReseed = FALSE;
584 status = gRngSuccess_d;
585 }
586 else
587 {
588 status = gRngInternalError_d;
589 assert(false);
590 }
591 }
592 else
593 {
594 status = gRngInternalError_d;
595 assert(false);
596 }
597 } while (false);
598 return status;
599}
600
601int RNG_NotifyReseedNeeded(void)
602{
603 int status;
604
605 do
606 {
607 /* On NBU side, PLATFORM_RequestRngSeed sends an RPMSG to the Host core,
608 * however on the the Host side, RNG_NotifyReseedNeeded is also called from ISR
609 * but PLATFORM_RequestRngSeed just returns 1 */
610 status = PLATFORM_RequestRngSeed();
611 if (status < 0)
612 {
613 break;
614 }
615 rng_ctx.needReseed = TRUE;
616#if defined(gRngEnableAutoReseed_d) && (gRngEnableAutoReseed_d > 0)
617 /* On MCU, submit a seed request to work queue */
618 status = WORKQ_Submit(&seed_needed_work);
619 if (status < 0)
620 {
621 break;
622 }
623#endif
624 } while (false);
625 return status;
626}
627
628bool_t RNG_IsReseedNeeded(void)
629{
630 /* Return whether reseeding is required or not */
631 return rng_ctx.needReseed;
632}
633
634int RNG_SetExternalSeed(uint8_t *external_seed)
635{
636 int status = gRngInternalError_d;
637 FLib_MemCpy(rng_ctx.PrngSeed, external_seed, mPRNG_NoOfBytes_c);
638 /* Inject entropy from externeal seed octet string */
639 status = PLATFORM_SendRngSeed(external_seed, mPRNG_NoOfBytes_c);
640 if (status >= 0)
641 {
642 rng_ctx.mPRNG_Requests = 1U;
643 rng_ctx.mPrngIsSeeded = TRUE;
644 rng_ctx.needReseed = FALSE;
645 status = gRngSuccess_d;
646 }
647 else
648 {
649 assert(false);
650 }
651 return status;
652}
653
654/*! *********************************************************************************
655*************************************************************************************
656* Private functions
657*************************************************************************************
658********************************************************************************** */
659#if defined(gRngSeedHwParamStorage_d) || defined(gRngSeedStorageAddr_d)
660static uint32_t Rng_read_seed_from_flash(void)
661{
662 uint32_t seed = 0U;
663#if defined(gRngSeedHwParamStorage_d)
664 hardwareParameters_t *pHWParams = NULL;
665 (void)NV_ReadHWParameters(&pHWParams);
666 seed = pHWParams->rngSeed;
667#elif defined(gRngSeedStorageAddr_d)
668 seed = *((uint32_t *)gRngSeedStorageAddr_d);
669#endif
670 return seed;
671}
672
673static void Rng_save_seed_to_flash(uint32_t seed)
674{
675 NV_Init();
676
677#if defined(gRngSeedHwParamStorage_d)
678 hardwareParameters_t *pHWParams = NULL;
679 (void)NV_ReadHWParameters(&pHWParams);
680 pHWParams->rngSeed = seed;
681 (void)NV_WriteHWParameters();
682
683#elif defined(gRngSeedStorageAddr_d)
684 (void)NV_FlashProgramUnaligned(gRngSeedStorageAddr_d, sizeof(seed), (uint8_t *)&seed);
685#endif
686}
687#endif
688
689#if ((defined(FSL_FEATURE_SOC_TRNG_COUNT)) && (FSL_FEATURE_SOC_TRNG_COUNT > 0U))
690static bool_t mRngDisallowMcuSleep = FALSE;
691/* The Allow/Disallow to sleep order is related to the use of a HW TRNG only */
692#if (cPWR_UsePowerDownMode)
693#define RNG_DisallowDeviceToSleep() PWR_DisallowDeviceToSleep()
694#define RNG_AllowDeviceToSleep() PWR_AllowDeviceToSleep()
695#else
696#define RNG_DisallowDeviceToSleep()
697#define RNG_AllowDeviceToSleep()
698#endif
699#if (defined(RW610_SERIES) || defined(RW612_SERIES))
700#define TRNG0 TRNG
701#endif
702static void TRNG_GoToSleep(void)
703{
704 if ((TRNG0->MCTL & TRNG_MCTL_ENT_VAL_MASK) != 0U)
705 {
706 if (mRngDisallowMcuSleep)
707 {
708 mRngDisallowMcuSleep = FALSE;
709 RNG_AllowDeviceToSleep();
710 }
711 }
712 else
713 {
714 if (!mRngDisallowMcuSleep)
715 {
716 mRngDisallowMcuSleep = TRUE;
717 RNG_DisallowDeviceToSleep();
718 }
719 }
720}
721
722void RNG_TrngIrqHandler(void)
723{
724 /* Clear Interrupt flags */
725 TRNG0->INT_CTRL &= ~(TRNG_INT_CTRL_ENT_VAL_MASK | TRNG_INT_CTRL_HW_ERR_MASK | TRNG_INT_CTRL_FRQ_CT_FAIL_MASK);
726
727 TRNG_GoToSleep();
728}
729#endif /* FSL_FEATURE_SOC_TRNG_COUNT */
730
731#if ((defined(FSL_FEATURE_SOC_RNG_COUNT)) && (FSL_FEATURE_SOC_RNG_COUNT > 0U))
732static int RNG_Specific_Init(uint32_t *pSeed)
733{
734 int status = gRngInternalError_d;
735
736 RNGA_Init(RNG);
737
738 /* Get seed for pseudo RNG */
739 if (RNGA_GetRandomData(RNG, pSeed, (int32_t)mPRNG_NoOfBytes_c) == 0)
740 {
741 rng_ctx.mPrngIsSeeded = TRUE;
742 status = gRngSuccess_d;
743 }
744 assert(gRngSuccess_d == status);
745
746 return status;
747}
748
749static int RNG_Specific_GetRandomData(uint8_t *pOut, uint16_t outBytes)
750{
751 int ret = gRngInternalError_d;
752 if (RNGA_GetRandomData(RNG, pOut, (size_t)outBytes) == 0)
753 {
754 ret = (int)outBytes;
755 }
756
757 return ret;
758}
759#elif ((defined(FSL_FEATURE_SOC_TRNG_COUNT)) && (FSL_FEATURE_SOC_TRNG_COUNT > 0U))
760static int RNG_Specific_Init(uint32_t *pSeed)
761{
762 int status = gRngInternalError_d;
763 trng_config_t config;
764
765 do
766 {
767 (void)TRNG_GetDefaultConfig(&config);
768
769 if (TRNG_Init(TRNG0, (const trng_config_t *)&config) != 0)
770 {
771 assert(false);
772 RAISE_ERROR(status, gRngInternalError_d);
773 }
774
775 /* Get seed for pseudo RNG */
776
777 if (TRNG_GetRandomData(TRNG0, pSeed, (size_t)mPRNG_NoOfBytes_c) != 0)
778 {
779 assert(false);
780 RAISE_ERROR(status, gRngInternalError_d);
781 }
782
783#if defined(gRngSeedStorageAddr_d) || defined(gRngSeedHwParamStorage_d)
784 TRNG_Deinit(TRNG0);
785#else
786 /* Check if the entropy generation ongoing */
787 TRNG_GoToSleep();
788
789 /* Clear Interrupt status.*/
790 TRNG0->INT_CTRL &= ~(TRNG_INT_CTRL_ENT_VAL_MASK | TRNG_INT_CTRL_HW_ERR_MASK | TRNG_INT_CTRL_FRQ_CT_FAIL_MASK);
791
792 /* Enable interrupt.*/
793 NVIC_SetPriority(TRNG0_IRQn, (uint32_t)gRngIsrPrio_c >> (8U - (uint8_t)__NVIC_PRIO_BITS));
794 (void)EnableIRQ(TRNG0_IRQn);
795 TRNG0->INT_MASK |= TRNG_INT_MASK_ENT_VAL_MASK | TRNG_INT_MASK_HW_ERR_MASK | TRNG_INT_MASK_FRQ_CT_FAIL_MASK;
796#endif
797 rng_ctx.mPrngIsSeeded = TRUE;
798 status = gRngSuccess_d;
799
800 } while (false);
801
802 return status;
803}
804
805static int RNG_Specific_GetRandomData(uint8_t *pOut, uint16_t outBytes)
806{
807 int ret;
808 do
809 {
810 /* Entropy valid wait loop part of function below, no need to check here. */
811 if ((uint8_t)TRNG_GetRandomData(TRNG0, pOut, (size_t)outBytes) != 0U)
812 {
813 ret = gRngInternalError_d;
814 break;
815 }
816 ret = (int)outBytes;
817
818 } while (false);
819
820 TRNG_GoToSleep();
821
822 return ret;
823}
824#elif gRNG_UsePhyRngForInitialSeed_d
825static int RNG_Specific_Init(uint32_t *pSeed)
826{
827 PhyGetRandomNo(pSeed);
828 rng_ctx.mPrngIsSeeded = TRUE;
829 return gRngSuccess_d;
830}
831
832static int RNG_Specific_GetRandomData(uint32_t *pOut, uint16_t outBytes)
833{
834 int ret = gRngBadArguments_d;
835 if (outBytes == sizeof(uint32_t))
836 {
837 PhyGetRandomNo(pOut);
838 ret = (int)sizeof(uint32_t);
839 }
840 return ret;
841}
842#elif defined gRngUseSecureSubSystem_d && (gRngUseSecureSubSystem_d != 0)
843
844static int RNG_Specific_GetRandomData(uint8_t *pOut, uint16_t outBytes)
845{
846 int ret;
847 sss_sscp_rng_t rctx;
848 bool init_passed = false;
849 do
850 {
851 if ((pOut == NULL) || (outBytes == 0U))
852 {
853 ret = gRngBadArguments_d;
854 break;
855 }
856
857 RNG_MUTEX_LOCK();
858
859 if (CRYPTO_InitHardware() != kStatus_Success)
860 {
861 ret = gRngNotInitialized_d;
862 break;
863 }
864
865 if (sss_sscp_rng_context_init(&g_sssSession, &rctx, SSS_HIGH_QUALITY_RNG) != kStatus_SSS_Success)
866 {
867 ret = gRngInternalError_d;
868 break;
869 }
870 init_passed = true;
871 if (sss_sscp_rng_get_random(&rctx, pOut, outBytes) != kStatus_SSS_Success)
872 {
873 ret = gRngInternalError_d;
874 break;
875 }
876 ret = (int)outBytes;
877
878 } while (false);
879
880 if (init_passed)
881 {
882 if (sss_sscp_rng_free(&rctx) != kStatus_SSS_Success)
883 {
884 assert(false);
885 }
886 }
887 RNG_MUTEX_UNLOCK();
888
889 return ret;
890}
891
892static int RNG_Specific_Init(uint32_t *pSeed)
893{
894 int status = gRngInternalError_d;
895 do
896 {
897 uint16_t Obtained_size;
898 int st;
899
900 st = RNG_Specific_GetRandomData((uint8_t *)pSeed, mPRNG_NoOfBytes_c);
901 if (st <= 0)
902 {
903 break;
904 }
905 Obtained_size = (uint16_t)st;
906 if (Obtained_size != mPRNG_NoOfBytes_c)
907 {
908 RAISE_ERROR(status, gRngInternalError_d);
909 }
910
911 rng_ctx.mPrngIsSeeded = TRUE; /* synchronous in the case of App core using SSS */
912 status = gRngSuccess_d;
913
914 } while (false);
915
916 return status;
917}
918
919#elif defined(gRngUseRngAdapter_c) && (gRngUseRngAdapter_c > 0)
920
921static int RNG_Specific_Init(uint32_t *pSeed)
922{
923 int ret = 0;
924 hal_rng_status_t status;
925
926 do
927 {
928 status = HAL_RngInit();
929 if ((status != kStatus_HAL_RngSuccess) && (status != KStatus_HAL_RngNotSupport))
930 {
931 ret = gRngInternalError_d;
932 break;
933 }
934
935 if (RNG_Specific_GetRandomData((uint8_t *)pSeed, mPRNG_NoOfBytes_c) <= 0)
936 {
937 ret = gRngInternalError_d;
938 break;
939 }
940
941 rng_ctx.mPrngIsSeeded = TRUE;
942
943 } while (false);
944
945 return ret;
946}
947
948static int RNG_Specific_GetRandomData(uint8_t *pOut, uint16_t outBytes)
949{
950 int ret = 0;
951 hal_rng_status_t status;
952
953 do
954 {
955 status = HAL_RngHwGetData(pOut, outBytes);
956
957 if (status != kStatus_HAL_RngSuccess)
958 {
959 if (status != KStatus_HAL_RngNotSupport)
960 {
961 ret = gRngInternalError_d;
962 break;
963 }
964
965 status = HAL_RngGetData(pOut, outBytes);
966
967 if (status != kStatus_HAL_RngSuccess)
968 {
969 ret = gRngInternalError_d;
970 break;
971 }
972 ret = (int)outBytes;
973 }
974 } while (false);
975
976 return ret;
977}
978
979#else
980
981static int RNG_Specific_Init(uint32_t *pSeed)
982{
983 /* no HW specific init is required */
984 (void)pSeed;
985
986 (void)RNG_NotifyReseedNeeded();
987
988 return gRngSuccess_d;
989}
990
991static int RNG_Specific_GetRandomData(uint8_t *pOut, uint16_t outBytes)
992{
993 (void)pOut;
994 (void)outBytes;
995 return 0;
996}
997
998#endif
999
1000#if (defined gRngUseLehmerGen_c && (gRngUseLehmerGen_c > 0))
1001
1002/*! *********************************************************************************
1003 * Optimized version of modulus 2^32 -5 (0xfffffffb is prime).
1004 * Method equivalent to x % 0xfffffffb, but saves more than 3000 cycles
1005 *
1006 * \param[in] x64 64 bit input value to be divided by 2^32-5
1007 *
1008 * \return 32 bit value of modulus 0xfffffffb.
1009 *
1010 ********************************************************************************** */
1011static inline uint32_t MOD_fffffffb(uint64_t x64)
1012{
1013 uint32_t res;
1014 x64 = (x64 & ~0UL) + (5U * (uint32_t)(x64 >> 32));
1015 x64 += 4U;
1016 res = (uint32_t)x64 + (5U * (uint32_t)(x64 >> 32));
1017 res -= 4U;
1018
1019 return res;
1020}
1021
1022/* */
1023/*! *********************************************************************************
1024 * RNG using a Lehmer Linear Congruential Generator.
1025 *
1026 * \param[in] prev_state 32 bit seed or previous value to be churned.
1027 *
1028 * \return 32 bit value of modulus 0xfffffffb.
1029 *
1030 ********************************************************************************** */
1031static uint32_t RNG_LCG(uint32_t prev_state)
1032{
1033 uint32_t val;
1034#define RNG_MULTIPLICAND 279470273UL
1035 uint64_t prod64 = (uint64_t)prev_state * RNG_MULTIPLICAND;
1036
1037 val = MOD_fffffffb(prod64);
1038
1039 return val;
1040}
1041#endif
1042
1043#if defined(gRngEnableAutoReseed_d) && (gRngEnableAutoReseed_d > 0)
1044static void RNG_seed_needed_handler(fwk_work_t *work)
1045{
1046 /* Execute reseed request from WorkQ */
1047 if (rng_ctx.needReseed == TRUE)
1048 {
1049 (void)RNG_SetSeed();
1050 }
1051}
1052#endif
1053/********************************** EOF ***************************************/