audk/CryptoPkg/Library/BaseCryptLib/Hash/CryptParallelHash.c

255 lines
6.8 KiB
C

/** @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;
}