]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Hash/CryptParallelHash.c
CryptoPkg: Add new hash algorithm ParallelHash256HashAll in BaseCryptLib.
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Hash / CryptParallelHash.c
CommitLineData
c1e66210
ZL
1/** @file\r
2 ParallelHash Implementation.\r
3\r
4Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "CryptParallelHash.h"\r
10#include <Library/MmServicesTableLib.h>\r
11#include <Library/SynchronizationLib.h>\r
12\r
13#define PARALLELHASH_CUSTOMIZATION "ParallelHash"\r
14\r
15UINTN mBlockNum;\r
16UINTN mBlockSize;\r
17UINTN mLastBlockSize;\r
18UINT8 *mInput;\r
19UINTN mBlockResultSize;\r
20UINT8 *mBlockHashResult;\r
21BOOLEAN *mBlockIsCompleted;\r
22SPIN_LOCK *mSpinLockList;\r
23\r
24/**\r
25 Complete computation of digest of each block.\r
26\r
27 Each AP perform the function called by BSP.\r
28\r
29 @param[in] ProcedureArgument Argument of the procedure.\r
30**/\r
31VOID\r
32EFIAPI\r
33ParallelHashApExecute (\r
34 IN VOID *ProcedureArgument\r
35 )\r
36{\r
37 UINTN Index;\r
38 BOOLEAN Status;\r
39\r
40 for (Index = 0; Index < mBlockNum; Index++) {\r
41 if (AcquireSpinLockOrFail (&mSpinLockList[Index])) {\r
42 //\r
43 // Completed, try next one.\r
44 //\r
45 if (mBlockIsCompleted[Index]) {\r
46 ReleaseSpinLock (&mSpinLockList[Index]);\r
47 continue;\r
48 }\r
49\r
50 //\r
51 // Calculate CShake256 for this block.\r
52 //\r
53 Status = CShake256HashAll (\r
54 mInput + Index * mBlockSize,\r
55 (Index == (mBlockNum - 1)) ? mLastBlockSize : mBlockSize,\r
56 mBlockResultSize,\r
57 NULL,\r
58 0,\r
59 NULL,\r
60 0,\r
61 mBlockHashResult + Index * mBlockResultSize\r
62 );\r
63 if (!EFI_ERROR (Status)) {\r
64 mBlockIsCompleted[Index] = TRUE;\r
65 }\r
66\r
67 ReleaseSpinLock (&mSpinLockList[Index]);\r
68 }\r
69 }\r
70}\r
71\r
72/**\r
73 Dispatch the block task to each AP in SMM mode.\r
74\r
75**/\r
76VOID\r
77EFIAPI\r
78MmDispatchBlockToAP (\r
79 VOID\r
80 )\r
81{\r
82 UINTN Index;\r
83\r
84 for (Index = 0; Index < gMmst->NumberOfCpus; Index++) {\r
85 if (Index != gMmst->CurrentlyExecutingCpu) {\r
86 gMmst->MmStartupThisAp (ParallelHashApExecute, Index, NULL);\r
87 }\r
88 }\r
89\r
90 return;\r
91}\r
92\r
93/**\r
94 Parallel hash function ParallelHash256, as defined in NIST's Special Publication 800-185,\r
95 published December 2016.\r
96\r
97 @param[in] Input Pointer to the input message (X).\r
98 @param[in] InputByteLen The number(>0) of input bytes provided for the input data.\r
99 @param[in] BlockSize The size of each block (B).\r
100 @param[out] Output Pointer to the output buffer.\r
101 @param[in] OutputByteLen The desired number of output bytes (L).\r
102 @param[in] Customization Pointer to the customization string (S).\r
103 @param[in] CustomByteLen The length of the customization string in bytes.\r
104\r
105 @retval TRUE ParallelHash256 digest computation succeeded.\r
106 @retval FALSE ParallelHash256 digest computation failed.\r
107 @retval FALSE This interface is not supported.\r
108\r
109**/\r
110BOOLEAN\r
111EFIAPI\r
112ParallelHash256HashAll (\r
113 IN CONST VOID *Input,\r
114 IN UINTN InputByteLen,\r
115 IN UINTN BlockSize,\r
116 OUT VOID *Output,\r
117 IN UINTN OutputByteLen,\r
118 IN CONST VOID *Customization,\r
119 IN UINTN CustomByteLen\r
120 )\r
121{\r
122 UINT8 EncBufB[sizeof (UINTN)+1];\r
123 UINTN EncSizeB;\r
124 UINT8 EncBufN[sizeof (UINTN)+1];\r
125 UINTN EncSizeN;\r
126 UINT8 EncBufL[sizeof (UINTN)+1];\r
127 UINTN EncSizeL;\r
128 UINTN Index;\r
129 UINT8 *CombinedInput;\r
130 UINTN CombinedInputSize;\r
131 BOOLEAN AllCompleted;\r
132 UINTN Offset;\r
133 BOOLEAN ReturnValue;\r
134\r
135 if ((InputByteLen == 0) || (OutputByteLen == 0) || (BlockSize == 0)) {\r
136 return FALSE;\r
137 }\r
138\r
139 if ((Input == NULL) || (Output == NULL)) {\r
140 return FALSE;\r
141 }\r
142\r
143 if ((CustomByteLen != 0) && (Customization == NULL)) {\r
144 return FALSE;\r
145 }\r
146\r
147 mBlockSize = BlockSize;\r
148\r
149 //\r
150 // Calculate block number n.\r
151 //\r
152 mBlockNum = InputByteLen % mBlockSize == 0 ? InputByteLen / mBlockSize : InputByteLen / mBlockSize + 1;\r
153\r
154 //\r
155 // Set hash result size of each block in bytes.\r
156 //\r
157 mBlockResultSize = OutputByteLen;\r
158\r
159 //\r
160 // Encode B, n, L to string and record size.\r
161 //\r
162 EncSizeB = LeftEncode (EncBufB, mBlockSize);\r
163 EncSizeN = RightEncode (EncBufN, mBlockNum);\r
164 EncSizeL = RightEncode (EncBufL, OutputByteLen * CHAR_BIT);\r
165\r
166 //\r
167 // Allocate buffer for combined input (newX), Block completed flag and SpinLock.\r
168 //\r
169 CombinedInputSize = EncSizeB + EncSizeN + EncSizeL + mBlockNum * mBlockResultSize;\r
170 CombinedInput = AllocateZeroPool (CombinedInputSize);\r
171 mBlockIsCompleted = AllocateZeroPool (mBlockNum * sizeof (BOOLEAN));\r
172 mSpinLockList = AllocatePool (mBlockNum * sizeof (SPIN_LOCK));\r
173 if ((CombinedInput == NULL) || (mBlockIsCompleted == NULL) || (mSpinLockList == NULL)) {\r
174 ReturnValue = FALSE;\r
175 goto Exit;\r
176 }\r
177\r
178 //\r
179 // Fill LeftEncode(B).\r
180 //\r
181 CopyMem (CombinedInput, EncBufB, EncSizeB);\r
182\r
183 //\r
184 // Prepare for parallel hash.\r
185 //\r
186 mBlockHashResult = CombinedInput + EncSizeB;\r
187 mInput = (UINT8 *)Input;\r
188 mLastBlockSize = InputByteLen % mBlockSize == 0 ? mBlockSize : InputByteLen % mBlockSize;\r
189\r
190 //\r
191 // Initialize SpinLock for each result block.\r
192 //\r
193 for (Index = 0; Index < mBlockNum; Index++) {\r
194 InitializeSpinLock (&mSpinLockList[Index]);\r
195 }\r
196\r
197 //\r
198 // Dispatch blocklist to each AP.\r
199 //\r
200 if (gMmst != NULL) {\r
201 MmDispatchBlockToAP ();\r
202 }\r
203\r
204 //\r
205 // Wait until all block hash completed.\r
206 //\r
207 do {\r
208 AllCompleted = TRUE;\r
209 for (Index = 0; Index < mBlockNum; Index++) {\r
210 if (AcquireSpinLockOrFail (&mSpinLockList[Index])) {\r
211 if (!mBlockIsCompleted[Index]) {\r
212 AllCompleted = FALSE;\r
213 ReturnValue = CShake256HashAll (\r
214 mInput + Index * mBlockSize,\r
215 (Index == (mBlockNum - 1)) ? mLastBlockSize : mBlockSize,\r
216 mBlockResultSize,\r
217 NULL,\r
218 0,\r
219 NULL,\r
220 0,\r
221 mBlockHashResult + Index * mBlockResultSize\r
222 );\r
223 if (ReturnValue) {\r
224 mBlockIsCompleted[Index] = TRUE;\r
225 }\r
226\r
227 ReleaseSpinLock (&mSpinLockList[Index]);\r
228 break;\r
229 }\r
230\r
231 ReleaseSpinLock (&mSpinLockList[Index]);\r
232 } else {\r
233 AllCompleted = FALSE;\r
234 break;\r
235 }\r
236 }\r
237 } while (!AllCompleted);\r
238\r
239 //\r
240 // Fill LeftEncode(n).\r
241 //\r
242 Offset = EncSizeB + mBlockNum * mBlockResultSize;\r
243 CopyMem (CombinedInput + Offset, EncBufN, EncSizeN);\r
244\r
245 //\r
246 // Fill LeftEncode(L).\r
247 //\r
248 Offset += EncSizeN;\r
249 CopyMem (CombinedInput + Offset, EncBufL, EncSizeL);\r
250\r
251 ReturnValue = CShake256HashAll (\r
252 CombinedInput,\r
253 CombinedInputSize,\r
254 OutputByteLen,\r
255 PARALLELHASH_CUSTOMIZATION,\r
256 AsciiStrLen (PARALLELHASH_CUSTOMIZATION),\r
257 Customization,\r
258 CustomByteLen,\r
259 Output\r
260 );\r
261\r
262Exit:\r
263 ZeroMem (CombinedInput, CombinedInputSize);\r
264\r
265 if (CombinedInput != NULL) {\r
266 FreePool (CombinedInput);\r
267 }\r
268\r
269 if (mSpinLockList != NULL) {\r
270 FreePool ((VOID *)mSpinLockList);\r
271 }\r
272\r
273 if (mBlockIsCompleted != NULL) {\r
274 FreePool (mBlockIsCompleted);\r
275 }\r
276\r
277 return ReturnValue;\r
278}\r