]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/OpensslLib/rand_pool.c
CryptoPkg/OpensslLib: Fix few typos
[mirror_edk2.git] / CryptoPkg / Library / OpensslLib / rand_pool.c
CommitLineData
b7396789
XL
1/** @file\r
2 OpenSSL_1_1_1b doesn't implement rand_pool_* functions for UEFI.\r
3 The file implement these functions.\r
4\r
5Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "internal/rand_int.h"\r
11#include <openssl/aes.h>\r
12\r
13#include <Uefi.h>\r
14#include <Library/TimerLib.h>\r
15\r
16#include "rand_pool_noise.h"\r
17\r
18/**\r
19 Get some randomness from low-order bits of GetPerformanceCounter results.\r
20 And combine them to the 64-bit value\r
21\r
22 @param[out] Rand Buffer pointer to store the 64-bit random value.\r
23\r
24 @retval TRUE Random number generated successfully.\r
25 @retval FALSE Failed to generate.\r
26**/\r
27STATIC\r
28BOOLEAN\r
29EFIAPI\r
30GetRandNoise64FromPerformanceCounter(\r
31 OUT UINT64 *Rand\r
32 )\r
33{\r
34 UINT32 Index;\r
35 UINT32 *RandPtr;\r
36\r
37 if (NULL == Rand) {\r
38 return FALSE;\r
39 }\r
40\r
41 RandPtr = (UINT32 *) Rand;\r
42\r
43 for (Index = 0; Index < 2; Index ++) {\r
44 *RandPtr = (UINT32) (GetPerformanceCounter () & 0xFF);\r
45 MicroSecondDelay (10);\r
46 RandPtr++;\r
47 }\r
48\r
49 return TRUE;\r
50}\r
51\r
52/**\r
53 Calls RandomNumber64 to fill\r
54 a buffer of arbitrary size with random bytes.\r
55\r
56 @param[in] Length Size of the buffer, in bytes, to fill with.\r
57 @param[out] RandBuffer Pointer to the buffer to store the random result.\r
58\r
59 @retval EFI_SUCCESS Random bytes generation succeeded.\r
60 @retval EFI_NOT_READY Failed to request random bytes.\r
61\r
62**/\r
63STATIC\r
64BOOLEAN\r
65EFIAPI\r
66RandGetBytes (\r
67 IN UINTN Length,\r
68 OUT UINT8 *RandBuffer\r
69 )\r
70{\r
71 BOOLEAN Ret;\r
72 UINT64 TempRand;\r
73\r
74 Ret = FALSE;\r
75\r
76 while (Length > 0) {\r
77 //\r
78 // Get random noise from platform.\r
79 // If it failed, fallback to PerformanceCounter\r
80 // If you really care about security, you must override\r
81 // GetRandomNoise64FromPlatform.\r
82 //\r
83 Ret = GetRandomNoise64 (&TempRand);\r
84 if (Ret == FALSE) {\r
85 Ret = GetRandNoise64FromPerformanceCounter (&TempRand);\r
86 }\r
87 if (!Ret) {\r
88 return Ret;\r
89 }\r
90 if (Length >= sizeof (TempRand)) {\r
91 *((UINT64*) RandBuffer) = TempRand;\r
92 RandBuffer += sizeof (UINT64);\r
93 Length -= sizeof (TempRand);\r
94 } else {\r
95 CopyMem (RandBuffer, &TempRand, Length);\r
96 Length = 0;\r
97 }\r
98 }\r
99\r
100 return Ret;\r
101}\r
102\r
103/**\r
104 Creates a 128bit random value that is fully forward and backward prediction resistant,\r
105 suitable for seeding a NIST SP800-90 Compliant.\r
106 This function takes multiple random numbers from PerformanceCounter to ensure reseeding\r
107 and performs AES-CBC-MAC over the data to compute the seed value.\r
108\r
109 @param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.\r
110\r
111 @retval TRUE Random seed generation succeeded.\r
112 @retval FALSE Failed to request random bytes.\r
113\r
114**/\r
115STATIC\r
116BOOLEAN\r
117EFIAPI\r
118RandGetSeed128 (\r
119 OUT UINT8 *SeedBuffer\r
120 )\r
121{\r
122 BOOLEAN Ret;\r
123 UINT8 RandByte[16];\r
124 UINT8 Key[16];\r
125 UINT8 Ffv[16];\r
126 UINT8 Xored[16];\r
127 UINT32 Index;\r
128 UINT32 Index2;\r
129 AES_KEY AESKey;\r
130\r
131 //\r
7aa8af45 132 // Chose an arbitrary key and zero the feed_forward_value (FFV)\r
b7396789
XL
133 //\r
134 for (Index = 0; Index < 16; Index++) {\r
135 Key[Index] = (UINT8) Index;\r
136 Ffv[Index] = 0;\r
137 }\r
138\r
139 AES_set_encrypt_key (Key, 16 * 8, &AESKey);\r
140\r
141 //\r
142 // Perform CBC_MAC over 32 * 128 bit values, with 10us gaps between 128 bit value\r
143 // The 10us gaps will ensure multiple reseeds within the system time with a large\r
144 // design margin.\r
145 //\r
146 for (Index = 0; Index < 32; Index++) {\r
147 MicroSecondDelay (10);\r
148 Ret = RandGetBytes (16, RandByte);\r
149 if (!Ret) {\r
150 return Ret;\r
151 }\r
152\r
153 //\r
154 // Perform XOR operations on two 128-bit value.\r
155 //\r
156 for (Index2 = 0; Index2 < 16; Index2++) {\r
157 Xored[Index2] = RandByte[Index2] ^ Ffv[Index2];\r
158 }\r
159\r
160 AES_encrypt (Xored, Ffv, &AESKey);\r
161 }\r
162\r
163 for (Index = 0; Index < 16; Index++) {\r
164 SeedBuffer[Index] = Ffv[Index];\r
165 }\r
166\r
167 return Ret;\r
168}\r
169\r
170/**\r
171 Generate high-quality entropy source.\r
172\r
173 @param[in] Length Size of the buffer, in bytes, to fill with.\r
174 @param[out] Entropy Pointer to the buffer to store the entropy data.\r
175\r
176 @retval EFI_SUCCESS Entropy generation succeeded.\r
177 @retval EFI_NOT_READY Failed to request random data.\r
178\r
179**/\r
180STATIC\r
181BOOLEAN\r
182EFIAPI\r
183RandGenerateEntropy (\r
184 IN UINTN Length,\r
185 OUT UINT8 *Entropy\r
186 )\r
187{\r
188 BOOLEAN Ret;\r
189 UINTN BlockCount;\r
190 UINT8 Seed[16];\r
191 UINT8 *Ptr;\r
192\r
193 BlockCount = Length / 16;\r
194 Ptr = (UINT8 *) Entropy;\r
195\r
196 //\r
197 // Generate high-quality seed for DRBG Entropy\r
198 //\r
199 while (BlockCount > 0) {\r
200 Ret = RandGetSeed128 (Seed);\r
201 if (!Ret) {\r
202 return Ret;\r
203 }\r
204 CopyMem (Ptr, Seed, 16);\r
205\r
206 BlockCount--;\r
207 Ptr = Ptr + 16;\r
208 }\r
209\r
210 //\r
211 // Populate the remained data as request.\r
212 //\r
213 Ret = RandGetSeed128 (Seed);\r
214 if (!Ret) {\r
215 return Ret;\r
216 }\r
217 CopyMem (Ptr, Seed, (Length % 16));\r
218\r
219 return Ret;\r
220}\r
221\r
222/*\r
223 * Add random bytes to the pool to acquire requested amount of entropy\r
224 *\r
225 * This function is platform specific and tries to acquire the requested\r
226 * amount of entropy by polling platform specific entropy sources.\r
227 *\r
228 * This is OpenSSL required interface.\r
229 */\r
230size_t rand_pool_acquire_entropy(RAND_POOL *pool)\r
231{\r
232 BOOLEAN Ret;\r
233 size_t bytes_needed;\r
234 unsigned char * buffer;\r
235\r
236 bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);\r
237 if (bytes_needed > 0) {\r
238 buffer = rand_pool_add_begin(pool, bytes_needed);\r
239\r
240 if (buffer != NULL) {\r
241 Ret = RandGenerateEntropy(bytes_needed, buffer);\r
242 if (FALSE == Ret) {\r
243 rand_pool_add_end(pool, 0, 0);\r
244 } else {\r
245 rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);\r
246 }\r
247 }\r
248 }\r
249\r
250 return rand_pool_entropy_available(pool);\r
251}\r
252\r
253/*\r
254 * Implementation for UEFI\r
255 *\r
256 * This is OpenSSL required interface.\r
257 */\r
258int rand_pool_add_nonce_data(RAND_POOL *pool)\r
259{\r
260 struct {\r
261 UINT64 Rand;\r
262 UINT64 TimerValue;\r
263 } data = { 0 };\r
264\r
265 RandGetBytes(8, (UINT8 *)&(data.Rand));\r
266 data.TimerValue = GetPerformanceCounter();\r
267\r
268 return rand_pool_add(pool, (unsigned char*)&data, sizeof(data), 0);\r
269}\r
270\r
271/*\r
272 * Implementation for UEFI\r
273 *\r
274 * This is OpenSSL required interface.\r
275 */\r
276int rand_pool_add_additional_data(RAND_POOL *pool)\r
277{\r
278 struct {\r
279 UINT64 Rand;\r
280 UINT64 TimerValue;\r
281 } data = { 0 };\r
282\r
283 RandGetBytes(8, (UINT8 *)&(data.Rand));\r
284 data.TimerValue = GetPerformanceCounter();\r
285\r
286 return rand_pool_add(pool, (unsigned char*)&data, sizeof(data), 0);\r
287}\r
288\r
289/*\r
7aa8af45 290 * Dummy Implementation for UEFI\r
b7396789
XL
291 *\r
292 * This is OpenSSL required interface.\r
293 */\r
294int rand_pool_init(void)\r
295{\r
296 return 1;\r
297}\r
298\r
299/*\r
7aa8af45 300 * Dummy Implementation for UEFI\r
b7396789
XL
301 *\r
302 * This is OpenSSL required interface.\r
303 */\r
304void rand_pool_cleanup(void)\r
305{\r
306}\r
307\r
308/*\r
7aa8af45 309 * Dummy Implementation for UEFI\r
b7396789
XL
310 *\r
311 * This is OpenSSL required interface.\r
312 */\r
313void rand_pool_keep_random_devices_open(int keep)\r
314{\r
315}\r
316\r