1 /*
2  * Copyright (c) 2018-2023, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== Random.c ========
34  */
35 
36 #include <ti/drivers/dpl/HwiP.h>
37 #include <ti/drivers/utils/Random.h>
38 
39 #include <stdint.h>
40 #include <stdbool.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include <ti/devices/DeviceFamily.h>
45 
46 #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 || \
47      DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X1_CC26X1 || \
48      DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2 || \
49      DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X4_CC26X3_CC26X4)
50 
51     #include <ti/drivers/TRNG.h>
52     #include <ti/drivers/trng/TRNGCC26XX.h>
53     #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>
54 #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC23X0)
55     #include <ti/drivers/RNG.h>
56     #include <ti/drivers/rng/RNGLPF3RF.h>
57 #endif
58 
59 #define STATE_SIZE_IN_WORDS 5
60 
61 static uint32_t state[STATE_SIZE_IN_WORDS];
62 
63 /*
64  *  ======== Random_seedAutomatic ========
65  */
Random_seedAutomatic(void)66 int_fast16_t Random_seedAutomatic(void)
67 {
68 
69 #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0 || \
70      DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X1_CC26X1 || \
71      DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2 || \
72      DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X4_CC26X3_CC26X4)
73 
74     TRNGCC26XX_Object object = {0};
75     TRNG_Params params;
76     CryptoKey seedKey;
77     int_fast16_t status;
78 
79     /* Use minimum TRNGCC26XX_SAMPLES_PER_CYCLE_MIN since
80      * we do not need the full amount of entropy and only need
81      * to kickstart the PRNG.
82      */
83     const TRNGCC26XX_HWAttrs hwAttrs = {
84         .samplesPerCycle = TRNGCC26XX_SAMPLES_PER_CYCLE_MIN,
85         .intPriority     = ~0,
86     };
87 
88     /* Allocate TRNG instance on the stack since we will not need it
89      * hereafter. This also helps avoid problems with hardcoded indexes.
90      */
91     TRNG_Config config = {.object = &object, .hwAttrs = &hwAttrs};
92 
93     params.returnBehavior = TRNG_RETURN_BEHAVIOR_POLLING;
94 
95     TRNG_init();
96 
97     TRNG_Handle handle = TRNG_construct(&config, &params);
98 
99     if (!handle)
100     {
101         return Random_STATUS_ERROR;
102     }
103 
104     CryptoKeyPlaintext_initBlankKey(&seedKey, (uint8_t *)state, sizeof(state));
105 
106     status = TRNG_generateEntropy(handle, &seedKey);
107 
108     TRNG_close(handle);
109 
110     if (status != TRNG_STATUS_SUCCESS)
111     {
112         return Random_STATUS_ERROR;
113     }
114 
115     return Random_STATUS_SUCCESS;
116 
117 #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC23X0)
118     RNG_Config rngConfig;
119     RNG_Handle rngHandle;
120     RNG_Params rngParams;
121     RNGLPF3RF_Object rngObject = {0};
122 
123     int_fast16_t status;
124 
125     /*
126      * Note: For CC23X0, RNG must be initialized by application in a task context with interrupts enabled
127      * using the following steps, before using Random_seedAutomatic() and prior to the use of the Radio.
128      * 1. Read radio noise using RCL_AdcNoise_get_samples_blocking(). This RCL function must
129      *    be called from a task context with interrupts enabled and therefore cannot be called
130      *    by startup code. This must be executed prior to the use of the radio.
131      * 2. Condition the noise to seed the RNG using RNGLPF3RF_conditionNoiseToGenerateSeed().
132      * 3. Initialize the RNG from the application with RNG_init()
133      * RNG_init() need not be called again here or by any other code.
134      */
135     rngConfig.object  = &rngObject;
136     rngConfig.hwAttrs = NULL;
137 
138     RNG_Params_init(&rngParams);
139 
140     rngHandle = RNG_construct(&rngConfig, &rngParams);
141 
142     if (!rngHandle)
143     {
144         return Random_STATUS_ERROR;
145     }
146 
147     status = RNG_getRandomBits(rngHandle, &state, sizeof(state) * 8);
148 
149     RNG_close(rngHandle);
150 
151     if (status != RNG_STATUS_SUCCESS)
152     {
153         return Random_STATUS_ERROR;
154     }
155 
156     return Random_STATUS_SUCCESS;
157 #else
158 
159     /* If neither a TRNG nor a unique ID are available, use a constant */
160     state[0] = 0x00000001;
161     state[1] = 0x00000002;
162     state[2] = 0x00000003;
163     state[3] = 0x00000004;
164     state[4] = 0x00000005;
165 
166     return Random_STATUS_SUCCESS;
167 #endif
168 }
169 
170 /*
171  *  ======== Random_seedManual ========
172  */
Random_seedManual(uint8_t seed[Random_SEED_LENGTH])173 void Random_seedManual(uint8_t seed[Random_SEED_LENGTH])
174 {
175     uintptr_t key;
176 
177     key = HwiP_disable();
178 
179     memcpy(state, seed, sizeof(state));
180 
181     HwiP_restore(key);
182 }
183 
184 /*
185  *  ======== Random_getNumber ========
186  */
Random_getNumber(void)187 uint32_t Random_getNumber(void)
188 {
189     uintptr_t key;
190     uint32_t s;
191     uint32_t v;
192     uint32_t result;
193 
194     key = HwiP_disable();
195 
196     /* "xorwow" XOR shift PRNG from section 3.1 of Marsaglia's "Xorshift RNGs" paper */
197     v = state[3];
198 
199     v ^= v >> 2;
200     v ^= v << 1;
201 
202     state[3] = state[2];
203     state[2] = state[1];
204     state[1] = state[0];
205     s        = state[0];
206 
207     v ^= s;
208     v ^= s << 4;
209 
210     state[0] = v;
211 
212     state[4] += 362437;
213 
214     result = v + state[4];
215 
216     HwiP_restore(key);
217 
218     return result;
219 }
220 
221 /*
222  *  ======== Random_getBytes ========
223  */
Random_getBytes(void * buffer,size_t bufferSize)224 void Random_getBytes(void *buffer, size_t bufferSize)
225 {
226     uint32_t i;
227     uint32_t randomNumber;
228 
229     for (i = 0; i < bufferSize / sizeof(uint32_t); i++)
230     {
231         ((uint32_t *)buffer)[i] = Random_getNumber();
232     }
233 
234     randomNumber = Random_getNumber();
235 
236     memcpy((uint32_t *)buffer + bufferSize / sizeof(uint32_t), &randomNumber, bufferSize % sizeof(uint32_t));
237 }
238