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