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>© 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