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