| /** @file | |
| ParallelHash Implementation. | |
| Copyright (c) 2022, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "CryptParallelHash.h" | |
| #include <Library/SynchronizationLib.h> | |
| #define PARALLELHASH_CUSTOMIZATION "ParallelHash" | |
| UINTN mBlockNum; | |
| UINTN mBlockSize; | |
| UINTN mLastBlockSize; | |
| UINT8 *mInput; | |
| UINTN mBlockResultSize; | |
| UINT8 *mBlockHashResult; | |
| BOOLEAN *mBlockIsCompleted; | |
| SPIN_LOCK *mSpinLockList; | |
| /** | |
| Complete computation of digest of each block. | |
| Each AP perform the function called by BSP. | |
| @param[in] ProcedureArgument Argument of the procedure. | |
| **/ | |
| VOID | |
| EFIAPI | |
| ParallelHashApExecute ( | |
| IN VOID *ProcedureArgument | |
| ) | |
| { | |
| UINTN Index; | |
| BOOLEAN Status; | |
| for (Index = 0; Index < mBlockNum; Index++) { | |
| if (AcquireSpinLockOrFail (&mSpinLockList[Index])) { | |
| // | |
| // Completed, try next one. | |
| // | |
| if (mBlockIsCompleted[Index]) { | |
| ReleaseSpinLock (&mSpinLockList[Index]); | |
| continue; | |
| } | |
| // | |
| // Calculate CShake256 for this block. | |
| // | |
| Status = CShake256HashAll ( | |
| mInput + Index * mBlockSize, | |
| (Index == (mBlockNum - 1)) ? mLastBlockSize : mBlockSize, | |
| mBlockResultSize, | |
| NULL, | |
| 0, | |
| NULL, | |
| 0, | |
| mBlockHashResult + Index * mBlockResultSize | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| mBlockIsCompleted[Index] = TRUE; | |
| } | |
| ReleaseSpinLock (&mSpinLockList[Index]); | |
| } | |
| } | |
| } | |
| /** | |
| Parallel hash function ParallelHash256, as defined in NIST's Special Publication 800-185, | |
| published December 2016. | |
| @param[in] Input Pointer to the input message (X). | |
| @param[in] InputByteLen The number(>0) of input bytes provided for the input data. | |
| @param[in] BlockSize The size of each block (B). | |
| @param[out] Output Pointer to the output buffer. | |
| @param[in] OutputByteLen The desired number of output bytes (L). | |
| @param[in] Customization Pointer to the customization string (S). | |
| @param[in] CustomByteLen The length of the customization string in bytes. | |
| @retval TRUE ParallelHash256 digest computation succeeded. | |
| @retval FALSE ParallelHash256 digest computation failed. | |
| @retval FALSE This interface is not supported. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| ParallelHash256HashAll ( | |
| IN CONST VOID *Input, | |
| IN UINTN InputByteLen, | |
| IN UINTN BlockSize, | |
| OUT VOID *Output, | |
| IN UINTN OutputByteLen, | |
| IN CONST VOID *Customization, | |
| IN UINTN CustomByteLen | |
| ) | |
| { | |
| UINT8 EncBufB[sizeof (UINTN)+1]; | |
| UINTN EncSizeB; | |
| UINT8 EncBufN[sizeof (UINTN)+1]; | |
| UINTN EncSizeN; | |
| UINT8 EncBufL[sizeof (UINTN)+1]; | |
| UINTN EncSizeL; | |
| UINTN Index; | |
| UINT8 *CombinedInput; | |
| UINTN CombinedInputSize; | |
| BOOLEAN AllCompleted; | |
| UINTN Offset; | |
| BOOLEAN ReturnValue; | |
| if ((InputByteLen == 0) || (OutputByteLen == 0) || (BlockSize == 0)) { | |
| return FALSE; | |
| } | |
| if ((Input == NULL) || (Output == NULL)) { | |
| return FALSE; | |
| } | |
| if ((CustomByteLen != 0) && (Customization == NULL)) { | |
| return FALSE; | |
| } | |
| mBlockSize = BlockSize; | |
| // | |
| // Calculate block number n. | |
| // | |
| mBlockNum = InputByteLen % mBlockSize == 0 ? InputByteLen / mBlockSize : InputByteLen / mBlockSize + 1; | |
| // | |
| // Set hash result size of each block in bytes. | |
| // | |
| mBlockResultSize = OutputByteLen; | |
| // | |
| // Encode B, n, L to string and record size. | |
| // | |
| EncSizeB = LeftEncode (EncBufB, mBlockSize); | |
| EncSizeN = RightEncode (EncBufN, mBlockNum); | |
| EncSizeL = RightEncode (EncBufL, OutputByteLen * CHAR_BIT); | |
| // | |
| // Allocate buffer for combined input (newX), Block completed flag and SpinLock. | |
| // | |
| CombinedInputSize = EncSizeB + EncSizeN + EncSizeL + mBlockNum * mBlockResultSize; | |
| CombinedInput = AllocateZeroPool (CombinedInputSize); | |
| mBlockIsCompleted = AllocateZeroPool (mBlockNum * sizeof (BOOLEAN)); | |
| mSpinLockList = AllocatePool (mBlockNum * sizeof (SPIN_LOCK)); | |
| if ((CombinedInput == NULL) || (mBlockIsCompleted == NULL) || (mSpinLockList == NULL)) { | |
| ReturnValue = FALSE; | |
| goto Exit; | |
| } | |
| // | |
| // Fill LeftEncode(B). | |
| // | |
| CopyMem (CombinedInput, EncBufB, EncSizeB); | |
| // | |
| // Prepare for parallel hash. | |
| // | |
| mBlockHashResult = CombinedInput + EncSizeB; | |
| mInput = (UINT8 *)Input; | |
| mLastBlockSize = InputByteLen % mBlockSize == 0 ? mBlockSize : InputByteLen % mBlockSize; | |
| // | |
| // Initialize SpinLock for each result block. | |
| // | |
| for (Index = 0; Index < mBlockNum; Index++) { | |
| InitializeSpinLock (&mSpinLockList[Index]); | |
| } | |
| // | |
| // Dispatch blocklist to each AP. | |
| // | |
| DispatchBlockToAp (); | |
| // | |
| // Wait until all block hash completed. | |
| // | |
| do { | |
| AllCompleted = TRUE; | |
| for (Index = 0; Index < mBlockNum; Index++) { | |
| if (AcquireSpinLockOrFail (&mSpinLockList[Index])) { | |
| if (!mBlockIsCompleted[Index]) { | |
| AllCompleted = FALSE; | |
| ReturnValue = CShake256HashAll ( | |
| mInput + Index * mBlockSize, | |
| (Index == (mBlockNum - 1)) ? mLastBlockSize : mBlockSize, | |
| mBlockResultSize, | |
| NULL, | |
| 0, | |
| NULL, | |
| 0, | |
| mBlockHashResult + Index * mBlockResultSize | |
| ); | |
| if (ReturnValue) { | |
| mBlockIsCompleted[Index] = TRUE; | |
| } | |
| ReleaseSpinLock (&mSpinLockList[Index]); | |
| break; | |
| } | |
| ReleaseSpinLock (&mSpinLockList[Index]); | |
| } else { | |
| AllCompleted = FALSE; | |
| break; | |
| } | |
| } | |
| } while (!AllCompleted); | |
| // | |
| // Fill LeftEncode(n). | |
| // | |
| Offset = EncSizeB + mBlockNum * mBlockResultSize; | |
| CopyMem (CombinedInput + Offset, EncBufN, EncSizeN); | |
| // | |
| // Fill LeftEncode(L). | |
| // | |
| Offset += EncSizeN; | |
| CopyMem (CombinedInput + Offset, EncBufL, EncSizeL); | |
| ReturnValue = CShake256HashAll ( | |
| CombinedInput, | |
| CombinedInputSize, | |
| OutputByteLen, | |
| PARALLELHASH_CUSTOMIZATION, | |
| AsciiStrLen (PARALLELHASH_CUSTOMIZATION), | |
| Customization, | |
| CustomByteLen, | |
| Output | |
| ); | |
| Exit: | |
| ZeroMem (CombinedInput, CombinedInputSize); | |
| if (CombinedInput != NULL) { | |
| FreePool (CombinedInput); | |
| } | |
| if (mSpinLockList != NULL) { | |
| FreePool ((VOID *)mSpinLockList); | |
| } | |
| if (mBlockIsCompleted != NULL) { | |
| FreePool (mBlockIsCompleted); | |
| } | |
| return ReturnValue; | |
| } |