OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcRngLib.c
Go to the documentation of this file.
1
23#include <Library/BaseLib.h>
24#include <Library/BaseMemoryLib.h>
25#include <Library/DebugLib.h>
26#include <Library/OcMiscLib.h>
27#include <Library/OcCryptoLib.h>
28#include <Library/OcRngLib.h>
29
30#include <Register/Intel/Cpuid.h>
31
32#include "OcRngInternals.h"
33
35
36STATIC
37VOID
39 IN UINT32 BytesNeeded
40 )
41{
42 //
43 // Implementation design based on arc4random from FreeBSD.
44 //
45
46 UINTN Index;
47 UINT32 KeySeed[CHACHA_KEY_SIZE / sizeof (UINT32)];
48 UINT32 IvSeed[CHACHA_IV_SIZE / sizeof (UINT32)];
49 BOOLEAN Result;
50
51 STATIC_ASSERT (CHACHA_KEY_SIZE % sizeof (UINT32) == 0, "Unexpected key size");
52 STATIC_ASSERT (CHACHA_IV_SIZE % sizeof (UINT32) == 0, "Unexpected key size");
53
54 ASSERT (BytesNeeded <= MAX_BYTES_TO_EMIT);
55
56 //
57 // Do not reseed if we are initialised and do not yet need a reseed.
58 //
59 if (mRng.PrngInitialised && (mRng.BytesTillReseed >= BytesNeeded)) {
60 mRng.BytesTillReseed -= BytesNeeded;
61 return;
62 }
63
64 //
65 // Generate seeds.
66 //
67 for (Index = 0; Index < ARRAY_SIZE (KeySeed); ++Index) {
68 Result = GetRandomNumber32 (&KeySeed[Index]);
69 if (!Result) {
70 ASSERT (FALSE);
71 CpuDeadLoop ();
72 }
73 }
74
75 for (Index = 0; Index < ARRAY_SIZE (IvSeed); ++Index) {
76 Result = GetRandomNumber32 (&IvSeed[Index]);
77 if (!Result) {
78 ASSERT (FALSE);
79 CpuDeadLoop ();
80 }
81 }
82
83 //
84 // Reinitialize if we are making a second loop.
85 //
87 ZeroMem (mRng.Buffer, sizeof (mRng.Buffer));
88 //
89 // Fill buffer with keystream.
90 //
92 //
93 // Mix in RNG data.
94 //
95 for (Index = 0; Index < ARRAY_SIZE (KeySeed); ++Index) {
96 mRng.Buffer[Index] ^= KeySeed[Index];
97 }
98
99 for (Index = 0; Index < ARRAY_SIZE (IvSeed); ++Index) {
100 mRng.Buffer[ARRAY_SIZE (KeySeed) + Index] ^= IvSeed[Index];
101 }
102 } else {
103 mRng.PrngInitialised = TRUE;
104 }
105
106 //
107 // Setup ChaCha context.
108 //
109 ChaChaInitCtx (&mRng.ChaCha, (UINT8 *)KeySeed, (UINT8 *)IvSeed, 0);
110
111 SecureZeroMem (KeySeed, sizeof (KeySeed));
112 SecureZeroMem (IvSeed, sizeof (IvSeed));
113
114 mRng.BytesTillReseed = MAX_BYTES_TO_EMIT - BytesNeeded;
116
117 ZeroMem (mRng.Buffer, sizeof (mRng.Buffer));
118}
119
120STATIC
121VOID
123 OUT UINT8 *Data,
124 IN UINT32 Size
125 )
126{
127 UINT32 CurrentSize;
128
130
132
133 while (Size > 0) {
134 if (mRng.BytesInBuffer > 0) {
135 CurrentSize = MIN (Size, mRng.BytesInBuffer);
136
137 CopyMem (Data, mRng.Buffer + sizeof (mRng.Buffer) - mRng.BytesInBuffer, CurrentSize);
138 ZeroMem (mRng.Buffer + sizeof (mRng.Buffer) - mRng.BytesInBuffer, CurrentSize);
139
140 Data += CurrentSize;
141 Size -= CurrentSize;
142 mRng.BytesInBuffer -= CurrentSize;
143 }
144
145 if (mRng.BytesInBuffer == 0) {
146 ZeroMem (mRng.Buffer, sizeof (mRng.Buffer));
147 //
148 // Fill buffer with keystream.
149 //
151 //
152 // Immediately reinit for backtracking resistance.
153 //
157 }
158 }
159}
160
161STATIC
162UINT64
164 IN UINTN Bits
165 )
166{
167 UINTN Index;
168 UINT64 Entropy;
169 UINT64 Tmp;
170
171 //
172 // Uses non-deterministic CPU execution.
173 // REF: https://static.lwn.net/images/conf/rtlws11/random-hardware.pdf
174 // REF: https://www.osadl.org/fileadmin/dam/presentations/RTLWS11/okech-inherent-randomness.pdf
175 // REF: http://lkml.iu.edu/hypermail/linux/kernel/1909.3/03714.html
176 //
177 Entropy = 0;
178 for (Index = 0; Index < Bits; ++Index) {
179 Tmp = AsmReadTsc () + AsmAddRngJitter (AsmReadTsc ());
180 if ((Tmp & BIT0) != 0) {
181 Entropy |= LShiftU64 (1, Index);
182 }
183 }
184
185 return Entropy;
186}
187
199EFI_STATUS
200EFIAPI
202 VOID
203 )
204{
205 CPUID_VERSION_INFO_ECX RegEcx;
206
207 //
208 // Determine RDRAND support by examining bit 30 of the ECX register returned by
209 // CPUID. A value of 1 indicates that processor support RDRAND instruction.
210 //
211 AsmCpuid (1, 0, 0, &RegEcx.Uint32, 0);
212 mRng.HardwareRngAvailable = RegEcx.Bits.RDRAND != 0;
213
214 //
215 // Initialize PRNG.
216 //
217 ChaChaRngStir (0);
218
219 return EFI_SUCCESS;
220}
221
233BOOLEAN
234EFIAPI
236 OUT UINT16 *Rand
237 )
238{
239 UINT32 Index;
240
241 ASSERT (Rand != NULL);
242
244 //
245 // A loop to fetch a 16 bit random value with a retry count limit.
246 //
247 for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) {
248 if (AsmRdRand16 (Rand)) {
249 return TRUE;
250 }
251 }
252 }
253
254 *Rand = (UINT16)GetEntropyBits (sizeof (UINT16) * OC_CHAR_BIT);
255 return TRUE;
256}
257
269BOOLEAN
270EFIAPI
272 OUT UINT32 *Rand
273 )
274{
275 UINT32 Index;
276
277 ASSERT (Rand != NULL);
278
280 //
281 // A loop to fetch a 32 bit random value with a retry count limit.
282 //
283 for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) {
284 if (AsmRdRand32 (Rand)) {
285 return TRUE;
286 }
287 }
288 }
289
290 *Rand = (UINT32)GetEntropyBits (sizeof (UINT32) * OC_CHAR_BIT);
291 return TRUE;
292}
293
305BOOLEAN
306EFIAPI
308 OUT UINT64 *Rand
309 )
310{
311 UINT32 Index;
312
313 ASSERT (Rand != NULL);
314
316 //
317 // A loop to fetch a 64 bit random value with a retry count limit.
318 //
319 for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) {
320 if (AsmRdRand64 (Rand)) {
321 return TRUE;
322 }
323 }
324 }
325
326 *Rand = GetEntropyBits (sizeof (UINT64) * OC_CHAR_BIT);
327 return TRUE;
328}
329
341BOOLEAN
342EFIAPI
344 OUT UINT64 *Rand
345 )
346{
347 ASSERT (Rand != NULL);
348
350 //
351 // Read 64 bits twice
352 //
353 if ( GetRandomNumber64 (&Rand[0])
354 && GetRandomNumber64 (&Rand[1]))
355 {
356 return TRUE;
357 }
358 }
359
360 Rand[0] = GetEntropyBits (sizeof (UINT64) * OC_CHAR_BIT);
361 Rand[1] = GetEntropyBits (sizeof (UINT64) * OC_CHAR_BIT);
362 return TRUE;
363}
364
370UINT16
371EFIAPI
373 VOID
374 )
375{
376 UINT16 Rand;
377
378 ChaChaRngGenerate ((UINT8 *)&Rand, sizeof (Rand));
379
380 return Rand;
381}
382
388UINT32
389EFIAPI
391 VOID
392 )
393{
394 UINT32 Rand;
395
396 ChaChaRngGenerate ((UINT8 *)&Rand, sizeof (Rand));
397
398 return Rand;
399}
400
406UINT64
407EFIAPI
409 VOID
410 )
411{
412 UINT64 Rand;
413
414 ChaChaRngGenerate ((UINT8 *)&Rand, sizeof (Rand));
415
416 return Rand;
417}
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
DMG_SIZE_DEVICE_PATH Size
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
VOID ChaChaCryptBuffer(IN OUT CHACHA_CONTEXT *Context, IN CONST UINT8 *Source, OUT UINT8 *Destination, IN UINT32 Length)
Definition ChaCha.c:74
#define CHACHA_KEY_SIZE
Definition OcCryptoLib.h:79
VOID ChaChaInitCtx(OUT CHACHA_CONTEXT *Context, IN CONST UINT8 *Key, IN CONST UINT8 *Iv, IN UINT32 Counter)
Definition ChaCha.c:48
#define CHACHA_IV_SIZE
Definition OcCryptoLib.h:84
VOID * SecureZeroMem(OUT VOID *Buffer, IN UINTN Length)
Definition SecureMem.c:73
#define OC_CHAR_BIT
Definition OcMiscLib.h:25
UINT64 EFIAPI AsmAddRngJitter(IN UINT64 Value)
#define MAX_BYTES_TO_EMIT
#define RDRAND_RETRY_LIMIT
EFI_STATUS EFIAPI OcRngLibConstructor(VOID)
Definition OcRngLib.c:201
STATIC OC_RNG_CONTEXT mRng
Definition OcRngLib.c:34
UINT64 EFIAPI GetPseudoRandomNumber64(VOID)
Definition OcRngLib.c:408
BOOLEAN EFIAPI GetRandomNumber16(OUT UINT16 *Rand)
Definition OcRngLib.c:235
STATIC VOID ChaChaRngGenerate(OUT UINT8 *Data, IN UINT32 Size)
Definition OcRngLib.c:122
BOOLEAN EFIAPI GetRandomNumber32(OUT UINT32 *Rand)
Definition OcRngLib.c:271
STATIC VOID ChaChaRngStir(IN UINT32 BytesNeeded)
Definition OcRngLib.c:38
UINT16 EFIAPI GetPseudoRandomNumber16(VOID)
Definition OcRngLib.c:372
STATIC UINT64 GetEntropyBits(IN UINTN Bits)
Definition OcRngLib.c:163
BOOLEAN EFIAPI GetRandomNumber128(OUT UINT64 *Rand)
Definition OcRngLib.c:343
UINT32 EFIAPI GetPseudoRandomNumber32(VOID)
Definition OcRngLib.c:390
BOOLEAN EFIAPI GetRandomNumber64(OUT UINT64 *Rand)
Definition OcRngLib.c:307
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition UserMath.c:76
UINT64 EFIAPI AsmReadTsc(VOID)
Definition UserMisc.c:232
UINT32 AsmCpuid(IN UINT32 Index, OUT UINT32 *Eax, OPTIONAL OUT UINT32 *Ebx, OPTIONAL OUT UINT32 *Ecx, OPTIONAL OUT UINT32 *Edx OPTIONAL)
Definition UserMisc.c:45
#define ASSERT(x)
Definition coder.h:55
#define MIN(a, b)
Definition deflate.c:1673
BOOLEAN HardwareRngAvailable
BOOLEAN PrngInitialised
CHACHA_CONTEXT ChaCha
UINT8 Buffer[MAX_BYTES_IN_BUF]