1 /**************************************************************************//**
2 * @file rng.c
3 * @version V3.01
4 * @brief Show how to get true random number.
5 *
6 * @copyright SPDX-License-Identifier: Apache-2.0
7 * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9
10 #include <stdio.h>
11 #include "NuMicro.h"
12
13 /** @addtogroup Standard_Driver Standard Driver
14 @{
15 */
16
17 /** @addtogroup RNG_Driver RNG Driver
18 @{
19 */
20
21
22 /** @addtogroup RNG_EXPORTED_FUNCTIONS RNG Exported Functions
23 @{
24 */
25
26 typedef enum _RNG_KEY_SIZE
27 {
28 KEY_128 = 0,
29 KEY_192 = 2,
30 KEY_224 = 3,
31 KEY_233 = 4,
32 KEY_255 = 5,
33 KEY_256 = 6,
34 KEY_283 = 7,
35 KEY_384 = 8,
36 KEY_409 = 9,
37 KEY_512 = 10,
38 KEY_521 = 11,
39 KEY_571 = 12
40
41 } eRNG_SZ;
42
43
44 /**
45 * @brief Basic Configuration of TRNG and PRNG
46 *
47 * @details The function is used to set the basic configuration for TRNG and PRNG.
48 */
RNG_BasicConfig()49 static void RNG_BasicConfig()
50 {
51 int32_t i;
52 int32_t timeout = 0x1000000;
53
54 /* Enable TRNG & PRNG */
55 CLK->AHBCLK0 |= CLK_AHBCLK0_CRPTCKEN_Msk;
56 CLK->APBCLK1 |= CLK_APBCLK1_TRNGCKEN_Msk;
57
58 /* Use LIRC as TRNG engine clock */
59 CLK->PWRCTL |= CLK_PWRCTL_LIRCEN_Msk;
60 while((CLK->STATUS & CLK_STATUS_LIRCSTB_Msk) == 0)
61 {
62 if(i++ > timeout) break; /* Wait LIRC time-out */
63 }
64 CLK->CLKSEL2 = (CLK->CLKSEL2 & (~CLK_CLKSEL2_TRNGSEL_Msk)) | CLK_CLKSEL2_TRNGSEL_LIRC;
65
66 }
67
68
69
70
71 /**
72 * @brief Open random number generator
73 *
74 * @return 0 Successful
75 * -1 Failed
76 *
77 * @details The function is used to disable rng interrupt.
78 */
RNG_Open()79 int32_t RNG_Open()
80 {
81 int32_t i;
82 int32_t timeout = 0x1000000;
83
84 RNG_BasicConfig();
85
86 /* TRNG Activate */
87 TRNG->ACT |= TRNG_ACT_ACT_Msk;
88 /* Waiting for ready */
89 i = 0;
90 while((TRNG->CTL & TRNG_CTL_READY_Msk) == 0)
91 {
92 if(i++ > timeout)
93 {
94 /* TRNG ready timeout */
95 return -1;
96 }
97 }
98
99 /* CLKPSC is default to 0. The performance maybe low but suitable for any cases */
100 TRNG->CTL = 0;
101
102 /* Waiting for PRNG busy */
103 i = 0;
104 while((CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk) == CRPT_PRNG_CTL_BUSY_Msk)
105 {
106 if(i++ > timeout)
107 {
108 /* PRNG busy timeout */
109 return -1;
110 }
111 }
112
113 /* Reload seed from TRNG only at first time */
114 CRPT->PRNG_CTL = (PRNG_KEY_SIZE_256 << CRPT_PRNG_CTL_KEYSZ_Pos) | CRPT_PRNG_CTL_START_Msk | CRPT_PRNG_CTL_SEEDRLD_Msk | PRNG_CTL_SEEDSRC_TRNG;
115
116 i = 0;
117 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
118 {
119 if(i++ > timeout)
120 {
121 /* busy timeout */
122 return -1;
123 }
124 }
125
126 return 0;
127 }
128
129
130 /**
131 * @brief Get random words
132 *
133 * @param[in] pu32Buf Buffer pointer to store the random number
134 *
135 * @param[in] nWords Buffer size in word count. nWords must <= 8
136 *
137 * @return Word count of random number in buffer
138 *
139 * @details The function is used to generate random numbers
140 */
RNG_Random(uint32_t * pu32Buf,int32_t nWords)141 int32_t RNG_Random(uint32_t *pu32Buf, int32_t nWords)
142 {
143 int32_t i;
144 int32_t timeout = 0x10000;
145
146 /* Waiting for Busy */
147 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
148 {
149 if(timeout-- < 0)
150 return 0;
151 }
152
153 if(nWords > 8)
154 nWords = 8;
155
156 /* Trig to generate seed 256 bits random number */
157 CRPT->PRNG_CTL = (6 << CRPT_PRNG_CTL_KEYSZ_Pos) | CRPT_PRNG_CTL_START_Msk;
158
159 timeout = 0x10000;
160 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
161 {
162 if(timeout-- < 0)
163 return 0;
164 }
165
166 for(i = 0; i < nWords; i++)
167 {
168 pu32Buf[i] = CRPT->PRNG_KEY[i];
169 }
170
171 return nWords;
172 }
173
174
175
176 /**
177 * @brief Initial function for ECDSA key generator for Key Store
178 *
179 * @param[in] u32KeySize It could be PRNG_KEY_SIZE_128 ~ PRNG_KEY_SIZE_571
180 *
181 * @param[in] au32ECC_N The N value of specified ECC curve.
182 *
183 * @return -1 Failed
184 * Others The key number in KS SRAM
185 *
186 * @details The function is initial funciton of RNG_ECDSA function.
187 * This funciton should be called before calling RNG_ECDSA().
188 */
RNG_ECDSA_Init(uint32_t u32KeySize,uint32_t au32ECC_N[18])189 int32_t RNG_ECDSA_Init(uint32_t u32KeySize, uint32_t au32ECC_N[18])
190 {
191 int32_t i;
192
193 /* Initial TRNG and PRNG for random number */
194 if(RNG_Open())
195 return -1;
196
197 /* It is necessary to set ECC_N for ECDSA */
198 for(i = 0; i < 18; i++)
199 CRPT->ECC_N[i] = au32ECC_N[i];
200
201 CRPT->PRNG_KSCTL = (KS_OWNER_ECC << CRPT_PRNG_KSCTL_OWNER_Pos) |
202 CRPT_PRNG_KSCTL_ECDSA_Msk |
203 (CRPT_PRNG_KSCTL_WDST_Msk) |
204 (KS_SRAM << CRPT_PRNG_KSCTL_WSDST_Pos);
205
206 return 0;
207 }
208
209
210 /**
211 * @brief To generate a key to KS SRAM for ECDSA.
212 *
213 * @return -1 Failed
214 * Others The key number in KS SRAM
215 *
216 * @details The function is used to generate a key to KS SRAM for ECDSA.
217 * This key is necessary for ECDSA+Key Store function of ECC.
218 */
RNG_ECDSA(uint32_t u32KeySize)219 int32_t RNG_ECDSA(uint32_t u32KeySize)
220 {
221
222 int32_t timeout;
223 int32_t i;
224
225 /* Reload seed only at first time */
226 CRPT->PRNG_CTL = (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) | CRPT_PRNG_CTL_START_Msk | PRNG_CTL_SEEDSRC_TRNG;
227
228 timeout = 0x10000;
229 i = 0;
230 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
231 {
232 if(i++ > timeout)
233 {
234 return -1;
235 }
236 }
237
238 if(CRPT->PRNG_KSSTS & CRPT_PRNG_KSSTS_KCTLERR_Msk)
239 {
240 return -1;
241 }
242
243 return (CRPT->PRNG_KSSTS & CRPT_PRNG_KSCTL_NUM_Msk);
244 }
245
246
247
248 /**
249 * @brief Initial funciton for RNG_ECDH.
250 *
251 * @param[in] u32KeySize It could be PRNG_KEY_SIZE_128 ~ PRNG_KEY_SIZE_571
252 *
253 * @param[in] au32ECC_N The N value of specified ECC curve.
254 *
255 * @return -1 Failed
256 * Others The key number in KS SRAM
257 *
258 * @details The function is initial function of RNG_ECDH.
259 *
260 */
RNG_ECDH_Init(uint32_t u32KeySize,uint32_t au32ECC_N[18])261 int32_t RNG_ECDH_Init(uint32_t u32KeySize, uint32_t au32ECC_N[18])
262 {
263 int32_t i;
264
265 /* Initial Random Number Generator */
266 if(RNG_Open())
267 return -1;
268
269 /* It is necessary to set ECC_N for ECDSA */
270 for(i = 0; i < 18; i++)
271 CRPT->ECC_N[i] = au32ECC_N[i];
272
273 CRPT->PRNG_KSCTL = (KS_OWNER_ECC << CRPT_PRNG_KSCTL_OWNER_Pos) |
274 (CRPT_PRNG_KSCTL_ECDH_Msk) |
275 (CRPT_PRNG_KSCTL_WDST_Msk) |
276 (KS_SRAM << CRPT_PRNG_KSCTL_WSDST_Pos);
277
278 return 0;
279 }
280
281
282 /**
283 * @brief To generate a key to KS SRAM for ECDH.
284 *
285 * @return -1 Failed
286 * Others The key number in KS SRAM
287 *
288 * @details The function is used to generate a key to KS SRAM for ECDH.
289 * This key is necessary for ECDH+Key Store function of ECC.
290 */
RNG_ECDH(uint32_t u32KeySize)291 int32_t RNG_ECDH(uint32_t u32KeySize)
292 {
293 int32_t timeout;
294 int32_t i;
295
296 /* Reload seed only at first time */
297 CRPT->PRNG_CTL = (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) | CRPT_PRNG_CTL_START_Msk | PRNG_CTL_SEEDSRC_TRNG;
298
299 timeout = 0x10000;
300 i = 0;
301 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
302 {
303 if(i++ > timeout)
304 return -1;
305 }
306
307 if(CRPT->PRNG_KSSTS & CRPT_PRNG_KSSTS_KCTLERR_Msk)
308 return -1;
309
310 return (CRPT->PRNG_KSSTS & CRPT_PRNG_KSCTL_NUM_Msk);
311 }
312
313
314 /**
315 * @brief To generate entropy from hardware entropy source (TRNG)
316 *
317 * @return -1 Failed
318 * Others The bytes in pu8Out buffer
319 *
320 * @details The function is used to generate entropy from TRNG.
321 */
RNG_EntropyPoll(uint8_t * pu8Out,int32_t i32Len)322 int32_t RNG_EntropyPoll(uint8_t* pu8Out, int32_t i32Len)
323 {
324 int32_t timeout;
325 int32_t i;
326
327 if((TRNG->CTL & TRNG_CTL_READY_Msk) == 0)
328 {
329 /* TRNG is not in active */
330 printf("trng is not active\n");
331 return -1;
332 }
333
334 /* Trigger entropy generate */
335 TRNG->CTL |= TRNG_CTL_TRNGEN_Msk;
336
337 for(i = 0; i < i32Len; i++)
338 {
339 timeout = SystemCoreClock;
340 while((TRNG->CTL & TRNG_CTL_DVIF_Msk) == 0)
341 {
342 if(timeout-- <= 0)
343 {
344 /* Timeout error */
345 printf("timeout\n");
346 return -1;
347 }
348 }
349 /* Get one byte entroy */
350 *pu8Out++ = TRNG->DATA;
351 }
352
353 return i32Len;
354 }
355
356 /**@}*/ /* end of group RNG_EXPORTED_FUNCTIONS */
357
358 /**@}*/ /* end of group RNG_Driver */
359
360 /**@}*/ /* end of group Standard_Driver */
361
362