MCUXpresso SDK Documentation

middleware/wireless/framework/services/SecLib_RNG/RNG.c

middleware/wireless/framework/services/SecLib_RNG/RNG.c#

   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 ***************************************/