--- /dev/null
+/** @file\r
+ cSHAKE-256 Digest Wrapper Implementations.\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
+\r
+#define CSHAKE256_SECURITY_STRENGTH 256\r
+#define CSHAKE256_RATE_IN_BYTES 136\r
+\r
+CONST CHAR8 mZeroPadding[CSHAKE256_RATE_IN_BYTES] = { 0 };\r
+\r
+/**\r
+ CShake256 initial function.\r
+\r
+ Initializes user-supplied memory pointed by CShake256Context as cSHAKE-256 hash context for\r
+ subsequent use.\r
+\r
+ @param[out] CShake256Context Pointer to cSHAKE-256 context being initialized.\r
+ @param[in] OutputLen The desired number of output length in bytes.\r
+ @param[in] Name Pointer to the function name string.\r
+ @param[in] NameLen The length of the function name in bytes.\r
+ @param[in] Customization Pointer to the customization string.\r
+ @param[in] CustomizationLen The length of the customization string in bytes.\r
+\r
+ @retval TRUE cSHAKE-256 context initialization succeeded.\r
+ @retval FALSE cSHAKE-256 context initialization failed.\r
+ @retval FALSE This interface is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CShake256Init (\r
+ OUT VOID *CShake256Context,\r
+ IN UINTN OutputLen,\r
+ IN CONST VOID *Name,\r
+ IN UINTN NameLen,\r
+ IN CONST VOID *Customization,\r
+ IN UINTN CustomizationLen\r
+ )\r
+{\r
+ BOOLEAN Status;\r
+ UINT8 EncBuf[sizeof (UINTN) + 1];\r
+ UINTN EncLen;\r
+ UINTN AbsorbLen;\r
+ UINTN PadLen;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if ((CShake256Context == NULL) || (OutputLen == 0) || ((NameLen != 0) && (Name == NULL)) || ((CustomizationLen != 0) && (Customization == NULL))) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Initialize KECCAK context with pad value and block size.\r
+ //\r
+ if ((NameLen == 0) && (CustomizationLen == 0)) {\r
+ //\r
+ // When N and S are both empty strings, cSHAKE(X, L, N, S) is equivalent to\r
+ // SHAKE as defined in FIPS 202.\r
+ //\r
+ Status = (BOOLEAN)KeccakInit (\r
+ (Keccak1600_Ctx *)CShake256Context,\r
+ '\x1f',\r
+ (KECCAK1600_WIDTH - CSHAKE256_SECURITY_STRENGTH * 2) / 8,\r
+ OutputLen\r
+ );\r
+\r
+ return Status;\r
+ } else {\r
+ Status = (BOOLEAN)KeccakInit (\r
+ (Keccak1600_Ctx *)CShake256Context,\r
+ '\x04',\r
+ (KECCAK1600_WIDTH - CSHAKE256_SECURITY_STRENGTH * 2) / 8,\r
+ OutputLen\r
+ );\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ AbsorbLen = 0;\r
+ //\r
+ // Absorb Absorb bytepad(.., rate).\r
+ //\r
+ EncLen = LeftEncode (EncBuf, CSHAKE256_RATE_IN_BYTES);\r
+ Status = (BOOLEAN)Sha3Update ((Keccak1600_Ctx *)CShake256Context, EncBuf, EncLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ AbsorbLen += EncLen;\r
+\r
+ //\r
+ // Absorb encode_string(N).\r
+ //\r
+ EncLen = LeftEncode (EncBuf, NameLen * 8);\r
+ Status = (BOOLEAN)Sha3Update ((Keccak1600_Ctx *)CShake256Context, EncBuf, EncLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ AbsorbLen += EncLen;\r
+ Status = (BOOLEAN)Sha3Update ((Keccak1600_Ctx *)CShake256Context, Name, NameLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ AbsorbLen += NameLen;\r
+\r
+ //\r
+ // Absorb encode_string(S).\r
+ //\r
+ EncLen = LeftEncode (EncBuf, CustomizationLen * 8);\r
+ Status = (BOOLEAN)Sha3Update ((Keccak1600_Ctx *)CShake256Context, EncBuf, EncLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ AbsorbLen += EncLen;\r
+ Status = (BOOLEAN)Sha3Update ((Keccak1600_Ctx *)CShake256Context, Customization, CustomizationLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ AbsorbLen += CustomizationLen;\r
+\r
+ //\r
+ // Absorb zero padding up to rate.\r
+ //\r
+ PadLen = CSHAKE256_RATE_IN_BYTES - AbsorbLen % CSHAKE256_RATE_IN_BYTES;\r
+ Status = (BOOLEAN)Sha3Update ((Keccak1600_Ctx *)CShake256Context, mZeroPadding, PadLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+/**\r
+ Digests the input data and updates cSHAKE-256 context.\r
+\r
+ This function performs cSHAKE-256 digest on a data buffer of the specified size.\r
+ It can be called multiple times to compute the digest of long or discontinuous data streams.\r
+ cSHAKE-256 context should be already correctly initialized by CShake256Init(), and should not be finalized\r
+ by CShake256Final(). Behavior with invalid context is undefined.\r
+\r
+ @param[in, out] CShake256Context Pointer to the cSHAKE-256 context.\r
+ @param[in] Data Pointer to the buffer containing the data to be hashed.\r
+ @param[in] DataSize Size of Data buffer in bytes.\r
+\r
+ @retval TRUE cSHAKE-256 data digest succeeded.\r
+ @retval FALSE cSHAKE-256 data digest failed.\r
+ @retval FALSE This interface is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CShake256Update (\r
+ IN OUT VOID *CShake256Context,\r
+ IN CONST VOID *Data,\r
+ IN UINTN DataSize\r
+ )\r
+{\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (CShake256Context == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check invalid parameters, in case that only DataLength was checked in OpenSSL.\r
+ //\r
+ if ((Data == NULL) && (DataSize != 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return (BOOLEAN)(Sha3Update ((Keccak1600_Ctx *)CShake256Context, Data, DataSize));\r
+}\r
+\r
+/**\r
+ Completes computation of the cSHAKE-256 digest value.\r
+\r
+ This function completes cSHAKE-256 hash computation and retrieves the digest value into\r
+ the specified memory. After this function has been called, the cSHAKE-256 context cannot\r
+ be used again.\r
+ cSHAKE-256 context should be already correctly initialized by CShake256Init(), and should not be\r
+ finalized by CShake256Final(). Behavior with invalid cSHAKE-256 context is undefined.\r
+\r
+ @param[in, out] CShake256Context Pointer to the cSHAKE-256 context.\r
+ @param[out] HashValue Pointer to a buffer that receives the cSHAKE-256 digest\r
+ value.\r
+\r
+ @retval TRUE cSHAKE-256 digest computation succeeded.\r
+ @retval FALSE cSHAKE-256 digest computation failed.\r
+ @retval FALSE This interface is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CShake256Final (\r
+ IN OUT VOID *CShake256Context,\r
+ OUT UINT8 *HashValue\r
+ )\r
+{\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if ((CShake256Context == NULL) || (HashValue == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // cSHAKE-256 Hash Finalization.\r
+ //\r
+ return (BOOLEAN)(Sha3Final ((Keccak1600_Ctx *)CShake256Context, HashValue));\r
+}\r
+\r
+/**\r
+ Computes the CSHAKE-256 message digest of a input data buffer.\r
+\r
+ This function performs the CSHAKE-256 message digest of a given data buffer, and places\r
+ the digest value into the specified memory.\r
+\r
+ @param[in] Data Pointer to the buffer containing the data to be hashed.\r
+ @param[in] DataSize Size of Data buffer in bytes.\r
+ @param[in] OutputLen Size of output in bytes.\r
+ @param[in] Name Pointer to the function name string.\r
+ @param[in] NameLen Size of the function name in bytes.\r
+ @param[in] Customization Pointer to the customization string.\r
+ @param[in] CustomizationLen Size of the customization string in bytes.\r
+ @param[out] HashValue Pointer to a buffer that receives the CSHAKE-256 digest\r
+ value.\r
+\r
+ @retval TRUE CSHAKE-256 digest computation succeeded.\r
+ @retval FALSE CSHAKE-256 digest computation failed.\r
+ @retval FALSE This interface is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CShake256HashAll (\r
+ IN CONST VOID *Data,\r
+ IN UINTN DataSize,\r
+ IN UINTN OutputLen,\r
+ IN CONST VOID *Name,\r
+ IN UINTN NameLen,\r
+ IN CONST VOID *Customization,\r
+ IN UINTN CustomizationLen,\r
+ OUT UINT8 *HashValue\r
+ )\r
+{\r
+ BOOLEAN Status;\r
+ Keccak1600_Ctx Ctx;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (HashValue == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((Data == NULL) && (DataSize != 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = CShake256Init (&Ctx, OutputLen, Name, NameLen, Customization, CustomizationLen);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = CShake256Update (&Ctx, Data, DataSize);\r
+ if (!Status) {\r
+ return FALSE;\r
+ }\r
+\r
+ return CShake256Final (&Ctx, HashValue);\r
+}\r