REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3596 Parallel hash function ParallelHash256HashAll, as defined in NIST's Special Publication 800-185, published December 2016. It utilizes multi-process to calculate the digest. Passed CI test. Onprotocol version code passed test. Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com> Cc: Guomin Jiang <guomin.jiang@intel.com> Cc: Siyuan Fu <siyuan.fu@intel.com> Signed-off-by: Zhihao Li <zhihao.li@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
		
			
				
	
	
		
			279 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			279 lines
		
	
	
		
			7.2 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/MmServicesTableLib.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]);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dispatch the block task to each AP in SMM mode.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| MmDispatchBlockToAP (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
| 
 | |
|   for (Index = 0; Index < gMmst->NumberOfCpus; Index++) {
 | |
|     if (Index != gMmst->CurrentlyExecutingCpu) {
 | |
|       gMmst->MmStartupThisAp (ParallelHashApExecute, Index, NULL);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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.
 | |
|   //
 | |
|   if (gMmst != NULL) {
 | |
|     MmDispatchBlockToAP ();
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 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;
 | |
| }
 |