1 /**
2   ******************************************************************************
3   * @file    low_level_rng.c
4   * @author  MCD Application Team
5   * @brief   Low Level Interface module to use STM32 RNG Ip
6   *          This file provides mbed-crypto random generataor
7   *
8   ******************************************************************************
9   * @attention
10   *
11   * <h2><center>&copy; Copyright (c) 2020-2021 STMicroelectronics.
12   * All rights reserved.</center></h2>
13   *
14   * This software component is licensed by ST under BSD 3-Clause license,
15   * the "License"; You may not use this file except in compliance with the
16   * License. You may obtain a copy of the License at:
17   *                        opensource.org/licenses/BSD-3-Clause
18   *
19   ******************************************************************************
20   */
21 #include "low_level_rng.h"
22 #include "stm32hal.h"
23 
24 static RNG_HandleTypeDef handle;
25 static uint8_t users = 0;
26 
27 #define COMPILER_BARRIER() __ASM __IO("" : : : "memory")
28 
atomic_incr_u8(__IO uint8_t * valuePtr,uint8_t delta)29 static uint8_t atomic_incr_u8(__IO uint8_t *valuePtr, uint8_t delta)
30 {
31   COMPILER_BARRIER();
32   uint8_t newValue;
33   do
34   {
35     newValue = __LDREXB(valuePtr) + delta;
36   } while (__STREXB(newValue, valuePtr));
37   COMPILER_BARRIER();
38   return newValue;
39 }
40 
RNG_Init(void)41 int RNG_Init(void)
42 {
43   uint32_t dummy;
44   /*  We're only supporting a single user of RNG */
45   if (atomic_incr_u8(&users, 1) > 1)
46   {
47     return -1;
48   }
49 #if defined(STM32L562xx) || defined(STM32L552xx)
50   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
51 
52   /*Select PLLQ output as RNG clock source */
53   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RNG;
54   PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_MSI;
55   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
56   {
57     users=0;
58     return -1;
59   }
60 #else
61   /* Select RNG clock source */
62   __HAL_RCC_RNG_CONFIG(RCC_RNGCLKSOURCE_HSI48);
63 #endif
64   /* RNG Peripheral clock enable */
65   __HAL_RCC_RNG_CLK_ENABLE();
66 
67   /* Initialize RNG instance */
68   handle.Instance = RNG;
69   handle.State = HAL_RNG_STATE_RESET;
70   handle.Lock = HAL_UNLOCKED;
71 
72   if (HAL_RNG_Init(&handle) != HAL_OK)
73   {
74     return -2;
75   }
76 
77   /* first random number generated after setting the RNGEN bit should not be used */
78   HAL_RNG_GenerateRandomNumber(&handle, &dummy);
79   return 0;
80 }
81 
RNG_GetBytes(uint8_t * output,size_t length,size_t * output_length)82 static void RNG_GetBytes(uint8_t *output, size_t length, size_t *output_length)
83 {
84   int32_t ret = 0;
85   uint8_t try = 0;
86   __IO uint8_t random[4];
87   *output_length = 0;
88 
89   /* Get Random byte */
90   while ((*output_length < length) && (ret == 0))
91   {
92     if (HAL_RNG_GenerateRandomNumber(&handle, (uint32_t *)random) != HAL_OK)
93     {
94       /* retry when random number generated are not immediately available */
95       if (try < 3)
96       {
97         try++;
98       }
99       else
100       {
101         ret = -1;
102       }
103     }
104     else
105     {
106       for (uint8_t i = 0; (i < 4) && (*output_length < length) ; i++)
107       {
108         *output++ = random[i];
109         *output_length += 1;
110         random[i] = 0;
111       }
112     }
113   }
114   /* Just be extra sure that we didn't do it wrong */
115   if ((__HAL_RNG_GET_FLAG(&handle, (RNG_FLAG_CECS | RNG_FLAG_SECS))) != 0)
116   {
117     *output_length = 0;
118   }
119 }
120 
RNG_DeInit(void)121 void RNG_DeInit(void)
122 {
123   /*Disable the RNG peripheral */
124   HAL_RNG_DeInit(&handle);
125   /* RNG Peripheral clock disable - assume we're the only users of RNG  */
126   __HAL_RCC_RNG_CLK_DISABLE();
127 
128   users = 0;
129 }
130 
131 
132 /*  interface for mbed-crypto */
mbedtls_hardware_poll(void * data,unsigned char * output,size_t len,size_t * olen)133 int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen)
134 {
135   RNG_GetBytes(output, len, olen);
136   if (*olen != len)
137   {
138     return -1;
139   }
140   return 0;
141 }
142