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