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