mirror of https://github.com/acidanthera/audk.git
255 lines
6.8 KiB
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;
|
|
}
|