1 /**************************************************************************//**
2 * @file rng.c
3 * @version V3.00
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 Open random number generator
46 *
47 * @return 0 Successful
48 * -1 Failed
49 *
50 * @details The function is used to disable rng interrupt.
51 */
RNG_Open(void)52 int32_t RNG_Open(void)
53 {
54 int32_t i;
55 int32_t timeout = 0x1000000;
56
57 /* Basic Configuration */
58 CLK->AHBCLK |= CLK_AHBCLK_CRPTCKEN_Msk;
59 CLK->APBCLK1 |= CLK_APBCLK1_TRNGCKEN_Msk;
60 CLK->APBCLK0 |= CLK_APBCLK0_RTCCKEN_Msk;
61
62 RTC->LXTCTL |= (RTC_LXTCTL_C32KSEL_Msk | RTC_LXTCTL_LIRC32KEN_Msk); //To use LIRC32K
63
64 TRNG->ACT |= TRNG_ACT_ACT_Msk;
65 /* Waiting for ready */
66 i = 0;
67 while((TRNG->CTL & TRNG_CTL_READY_Msk) == 0)
68 {
69 if(i++ > timeout)
70 {
71 /* TRNG ready timeout */
72 return -1;
73 }
74 }
75
76 TRNG->CTL = (0 << TRNG_CTL_CLKPSC_Pos);
77
78
79 /* Enable SEEDGEN */
80 TRNG->CTL |= (1 << 8);
81
82 /* Waiting for seed ready */
83 i = 0;
84 while((TRNG->CTL & (1 << 9)) == 0)
85 {
86 if(i++ > timeout)
87 {
88 /* seed ready timeout */
89 return -1;
90 }
91 }
92
93 // Waiting for PRNG busy
94 i = 0;
95 while(CRPT->PRNG_CTL & (1 << 8))
96 {
97 if(i++ > timeout)
98 {
99 /* PRNG busy timeout */
100 return -1;
101 }
102 }
103
104 /* Set seed select to TRNG */
105 CRPT->PRNG_CTL = CRPT_PRNG_CTL_SEEDSEL_Msk;
106
107 /* Waiting for seed src ok */
108 i = 0;
109 while((CRPT->PRNG_CTL & CRPT_PRNG_CTL_SEEDSRC_Msk) == 0)
110 {
111 if(i++ > timeout)
112 {
113 /* PRNG src timeout */
114 return -1; // Timeout
115 }
116 }
117
118 /* Reload seed only at first time */
119 CRPT->PRNG_CTL |= (PRNG_KEY_SIZE_256 << CRPT_PRNG_CTL_KEYSZ_Pos) | CRPT_PRNG_CTL_START_Msk | CRPT_PRNG_CTL_SEEDRLD_Msk;
120
121 i = 0;
122 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
123 {
124 if(i++ > timeout)
125 {
126 /* busy timeout */
127 return -1;
128 }
129 }
130
131 return 0;
132 }
133
134
135 /**
136 * @brief Get random words
137 *
138 * @param[in] pu32Buf Buffer pointer to store the random number
139 *
140 * @param[in] nWords Buffer size in word count. nWords must <= 8
141 *
142 * @return Word count of random number in buffer
143 *
144 * @details The function is used to generate random numbers
145 */
RNG_Random(uint32_t * pu32Buf,int32_t nWords)146 int32_t RNG_Random(uint32_t *pu32Buf, int32_t nWords)
147 {
148 int32_t i;
149 int32_t timeout = 0x10000;
150
151 /* Waiting for Busy */
152 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk) {}
153
154 if(nWords > 8)
155 nWords = 8;
156
157 /* Trig to generate seed 256 bits random number */
158 CRPT->PRNG_CTL = (6 << CRPT_PRNG_CTL_KEYSZ_Pos) | CRPT_PRNG_CTL_START_Msk;
159
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 To generate a key to KS SRAM for ECDSA.
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 used to generate a key to KS SRAM for ECDSA.
187 * This key is necessary for ECDSA+Key Store function of ECC.
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 int32_t timeout = 0x1000000;
193
194 /* Basic Configuration */
195 CLK->AHBCLK |= CLK_AHBCLK_CRPTCKEN_Msk;
196 CLK->APBCLK1 |= CLK_APBCLK1_TRNGCKEN_Msk;
197 CLK->APBCLK0 |= CLK_APBCLK0_RTCCKEN_Msk;
198
199 RTC->LXTCTL |= (RTC_LXTCTL_C32KSEL_Msk | RTC_LXTCTL_LIRC32KEN_Msk); //To use LIRC32K
200
201 TRNG->ACT |= TRNG_ACT_ACT_Msk;
202 /* Waiting for ready */
203 i = 0;
204 while((TRNG->CTL & TRNG_CTL_READY_Msk) == 0)
205 {
206 if(i++ > timeout)
207 {
208 return -1; // Timeout
209 }
210 }
211
212 TRNG->CTL = (0 << TRNG_CTL_CLKPSC_Pos);
213
214 /* Reset seed select of PRNG */
215 CRPT->PRNG_CTL = 0;
216
217
218 /* Enable SEEDGEN */
219 TRNG->CTL |= TRNG_CTL_SEEDGEN_Msk;
220
221 /* Waiting for seed ready */
222 i = 0;
223 while((TRNG->CTL & TRNG_CTL_SEEDRDY_Msk) == 0)
224 {
225 if(i++ > timeout)
226 {
227 return -1; // Timeout
228 }
229 }
230
231 // Waiting for PRNG busy
232 i = 0;
233 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
234 {
235 if(i++ > timeout)
236 {
237 return -1; // Timeout
238 }
239 }
240
241
242 // Set seed select to TRNG
243 CRPT->PRNG_CTL = 1 << CRPT_PRNG_CTL_SEEDSEL_Pos;
244
245 // Waiting for seed src ok
246 i = 0;
247 while((CRPT->PRNG_CTL & CRPT_PRNG_CTL_SEEDSRC_Msk) == 0)
248 {
249 if(i++ > timeout)
250 {
251 return -1; // Timeout
252 }
253 }
254
255 /* It is necessary to set ECC_N for ECDSA */
256 for(i = 0; i < 18; i++)
257 CRPT->ECC_N[i] = au32ECC_N[i];
258
259 CRPT->PRNG_KSCTL = 0;
260
261 /* Reload seed only at first time */
262 CRPT->PRNG_CTL |= (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) |
263 CRPT_PRNG_CTL_START_Msk | CRPT_PRNG_CTL_SEEDRLD_Msk;
264
265
266 i = 0;
267 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
268 {
269 if(i++ > timeout)
270 {
271 return -1; // Timeout
272 }
273 }
274
275
276 CRPT->PRNG_KSCTL = (KS_OWNER_ECC << CRPT_PRNG_KSCTL_OWNER_Pos) |
277 CRPT_PRNG_KSCTL_ECDSA_Msk |
278 (CRPT_PRNG_KSCTL_WDST_Msk) |
279 (KS_SRAM << CRPT_PRNG_KSCTL_WSDST_Pos);
280
281 return 0;
282 }
283
284
285 /**
286 * @brief To generate a key to KS SRAM for ECDSA.
287 *
288 * @return -1 Failed
289 * Others The key number in KS SRAM
290 *
291 * @details The function is used to generate a key to KS SRAM for ECDSA.
292 * This key is necessary for ECDSA+Key Store function of ECC.
293 */
RNG_ECDSA(uint32_t u32KeySize)294 int32_t RNG_ECDSA(uint32_t u32KeySize)
295 {
296 int32_t timeout;
297 int32_t i;
298
299 /* Reload seed only at first time */
300 CRPT->PRNG_CTL = (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) |
301 0xc0 |
302 CRPT_PRNG_CTL_START_Msk;
303
304 timeout = 0x10000;
305 i = 0;
306 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
307 {
308 if(i++ > timeout)
309 {
310 //printf("busy timeout\n");
311 return -1; // Timeout
312 }
313 }
314
315 if(CRPT->PRNG_KSSTS & CRPT_PRNG_KSSTS_KCTLERR_Msk)
316 {
317 //printf("KCTLERR!\n");
318 return -1;
319 }
320
321 return (CRPT->PRNG_KSSTS & CRPT_PRNG_KSCTL_NUM_Msk);
322 }
323
324
325
326 /**
327 * @brief To generate a key to KS SRAM for ECDH.
328 *
329 * @param[in] u32KeySize It could be PRNG_KEY_SIZE_128 ~ PRNG_KEY_SIZE_571
330 *
331 * @param[in] au32ECC_N The N value of specified ECC curve.
332 *
333 * @return -1 Failed
334 * Others The key number in KS SRAM
335 *
336 * @details The function is used to generate a key to KS SRAM for ECDH.
337 * This key is necessary for ECDH+Key Store function of ECC.
338 */
RNG_ECDH_Init(uint32_t u32KeySize,uint32_t au32ECC_N[18])339 int32_t RNG_ECDH_Init(uint32_t u32KeySize, uint32_t au32ECC_N[18])
340 {
341 int32_t i;
342 int32_t timeout = 0x1000000;
343
344 /* Basic Configuration */
345 CLK->AHBCLK |= CLK_AHBCLK_CRPTCKEN_Msk;
346 CLK->APBCLK1 |= CLK_APBCLK1_TRNGCKEN_Msk;
347 CLK->APBCLK0 |= CLK_APBCLK0_RTCCKEN_Msk;
348
349 RTC->LXTCTL |= (RTC_LXTCTL_C32KSEL_Msk | RTC_LXTCTL_LIRC32KEN_Msk); //To use LIRC32K
350
351 TRNG->ACT |= TRNG_ACT_ACT_Msk;
352 /* Waiting for ready */
353 i = 0;
354 while((TRNG->CTL & TRNG_CTL_READY_Msk) == 0)
355 {
356 if(i++ > timeout)
357 {
358 /* TRNG ready timeout */
359 return -1;
360 }
361 }
362
363 TRNG->CTL = (0 << TRNG_CTL_CLKPSC_Pos);
364
365
366 /* Enable SEEDGEN */
367 TRNG->CTL |= TRNG_CTL_SEEDGEN_Msk;
368
369 /* Waiting for seed ready */
370 i = 0;
371 while((TRNG->CTL & TRNG_CTL_SEEDRDY_Msk) == 0)
372 {
373 if(i++ > timeout)
374 {
375 /* seed ready timeout */
376 return -1;
377 }
378 }
379
380 /* Waiting for PRNG busy */
381 i = 0;
382 while(CRPT->PRNG_CTL & TRNG_CTL_SEEDGEN_Msk)
383 {
384 if(i++ > timeout)
385 {
386 /* PRNG busy timeout */
387 return -1;
388 }
389 }
390
391
392
393 /* Set seed select to TRNG */
394 CRPT->PRNG_CTL = (1 << 6);
395
396 // Waiting for seed src ok
397 i = 0;
398 while((CRPT->PRNG_CTL & (1 << 7)) == 0)
399 {
400 if(i++ > timeout)
401 {
402 /* PRNG src timeout */
403 return -1;
404 }
405 }
406
407 /* It is necessary to set ECC_N for ECDSA */
408 for(i = 0; i < 18; i++)
409 CRPT->ECC_N[i] = au32ECC_N[i];
410
411 CRPT->PRNG_KSCTL = 0;
412
413 /* Reload seed only at first time */
414 CRPT->PRNG_CTL |= (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) |
415 CRPT_PRNG_CTL_START_Msk | CRPT_PRNG_CTL_SEEDRLD_Msk;
416
417
418 i = 0;
419 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
420 {
421 if(i++ > timeout)
422 {
423 /* busy timeout */
424 return -1;
425 }
426 }
427
428 CRPT->PRNG_KSCTL = (KS_OWNER_ECC << CRPT_PRNG_KSCTL_OWNER_Pos) |
429 (CRPT_PRNG_KSCTL_ECDH_Msk) |
430 (CRPT_PRNG_KSCTL_WDST_Msk) |
431 (KS_SRAM << CRPT_PRNG_KSCTL_WSDST_Pos);
432
433 return 0;
434 }
435
436
437 /**
438 * @brief To generate a key to KS SRAM for ECDH.
439 *
440 * @return -1 Failed
441 * Others The key number in KS SRAM
442 *
443 * @details The function is used to generate a key to KS SRAM for ECDH.
444 * This key is necessary for ECDH+Key Store function of ECC.
445 */
RNG_ECDH(uint32_t u32KeySize)446 int32_t RNG_ECDH(uint32_t u32KeySize)
447 {
448 int32_t timeout;
449 int32_t i;
450
451 /* Reload seed only at first time */
452 CRPT->PRNG_CTL = (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) |
453 0xc0 |
454 CRPT_PRNG_CTL_START_Msk;
455
456 timeout = 0x10000;
457 i = 0;
458 while(CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)
459 {
460 if(i++ > timeout)
461 return -1;
462 }
463
464 if(CRPT->PRNG_KSSTS & CRPT_PRNG_KSSTS_KCTLERR_Msk)
465 return -1;
466
467 return (CRPT->PRNG_KSSTS & CRPT_PRNG_KSCTL_NUM_Msk);
468 }
469
470 /**@}*/ /* end of group RNG_EXPORTED_FUNCTIONS */
471
472 /**@}*/ /* end of group RNG_Driver */
473
474 /**@}*/ /* end of group Standard_Driver */
475