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