]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c
SecurityPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / SecurityPkg / RandomNumberGenerator / RngDxe / RdRand.c
1 /** @file
2 Support routines for RDRAND instruction access.
3
4 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9 #include <Library/RngLib.h>
10
11 #include "RdRand.h"
12 #include "AesCore.h"
13
14 /**
15 Calls RDRAND to fill a buffer of arbitrary size with random bytes.
16
17 @param[in] Length Size of the buffer, in bytes, to fill with.
18 @param[out] RandBuffer Pointer to the buffer to store the random result.
19
20 @retval EFI_SUCCESS Random bytes generation succeeded.
21 @retval EFI_NOT_READY Failed to request random bytes.
22
23 **/
24 EFI_STATUS
25 EFIAPI
26 RdRandGetBytes (
27 IN UINTN Length,
28 OUT UINT8 *RandBuffer
29 )
30 {
31 BOOLEAN IsRandom;
32 UINT64 TempRand[2];
33
34 while (Length > 0) {
35 IsRandom = GetRandomNumber128 (TempRand);
36 if (!IsRandom) {
37 return EFI_NOT_READY;
38 }
39 if (Length >= sizeof (TempRand)) {
40 WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[0]);
41 RandBuffer += sizeof (UINT64);
42 WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[1]);
43 RandBuffer += sizeof (UINT64);
44 Length -= sizeof (TempRand);
45 } else {
46 CopyMem (RandBuffer, TempRand, Length);
47 Length = 0;
48 }
49 }
50
51 return EFI_SUCCESS;
52 }
53
54 /**
55 Creates a 128bit random value that is fully forward and backward prediction resistant,
56 suitable for seeding a NIST SP800-90 Compliant, FIPS 1402-2 certifiable SW DRBG.
57 This function takes multiple random numbers through RDRAND without intervening
58 delays to ensure reseeding and performs AES-CBC-MAC over the data to compute the
59 seed value.
60
61 @param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.
62
63 @retval EFI_SUCCESS Random seed generation succeeded.
64 @retval EFI_NOT_READY Failed to request random bytes.
65
66 **/
67 EFI_STATUS
68 EFIAPI
69 RdRandGetSeed128 (
70 OUT UINT8 *SeedBuffer
71 )
72 {
73 EFI_STATUS Status;
74 UINT8 RandByte[16];
75 UINT8 Key[16];
76 UINT8 Ffv[16];
77 UINT8 Xored[16];
78 UINT32 Index;
79 UINT32 Index2;
80
81 //
82 // Chose an arbitary key and zero the feed_forward_value (FFV)
83 //
84 for (Index = 0; Index < 16; Index++) {
85 Key[Index] = (UINT8) Index;
86 Ffv[Index] = 0;
87 }
88
89 //
90 // Perform CBC_MAC over 32 * 128 bit values, with 10us gaps between 128 bit value
91 // The 10us gaps will ensure multiple reseeds within the HW RNG with a large design margin.
92 //
93 for (Index = 0; Index < 32; Index++) {
94 MicroSecondDelay (10);
95 Status = RdRandGetBytes (16, RandByte);
96 if (EFI_ERROR (Status)) {
97 return Status;
98 }
99
100 //
101 // Perform XOR operations on two 128-bit value.
102 //
103 for (Index2 = 0; Index2 < 16; Index2++) {
104 Xored[Index2] = RandByte[Index2] ^ Ffv[Index2];
105 }
106
107 AesEncrypt (Key, Xored, Ffv);
108 }
109
110 for (Index = 0; Index < 16; Index++) {
111 SeedBuffer[Index] = Ffv[Index];
112 }
113
114 return EFI_SUCCESS;
115 }
116
117 /**
118 Generate high-quality entropy source through RDRAND.
119
120 @param[in] Length Size of the buffer, in bytes, to fill with.
121 @param[out] Entropy Pointer to the buffer to store the entropy data.
122
123 @retval EFI_SUCCESS Entropy generation succeeded.
124 @retval EFI_NOT_READY Failed to request random data.
125
126 **/
127 EFI_STATUS
128 EFIAPI
129 RdRandGenerateEntropy (
130 IN UINTN Length,
131 OUT UINT8 *Entropy
132 )
133 {
134 EFI_STATUS Status;
135 UINTN BlockCount;
136 UINT8 Seed[16];
137 UINT8 *Ptr;
138
139 Status = EFI_NOT_READY;
140 BlockCount = Length / 16;
141 Ptr = (UINT8 *)Entropy;
142
143 //
144 // Generate high-quality seed for DRBG Entropy
145 //
146 while (BlockCount > 0) {
147 Status = RdRandGetSeed128 (Seed);
148 if (EFI_ERROR (Status)) {
149 return Status;
150 }
151 CopyMem (Ptr, Seed, 16);
152
153 BlockCount--;
154 Ptr = Ptr + 16;
155 }
156
157 //
158 // Populate the remained data as request.
159 //
160 Status = RdRandGetSeed128 (Seed);
161 if (EFI_ERROR (Status)) {
162 return Status;
163 }
164 CopyMem (Ptr, Seed, (Length % 16));
165
166 return Status;
167 }