From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web09.16026.1656530378849059963 for ; Wed, 29 Jun 2022 12:19:39 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: pierre.gondois@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BEAB61480; Wed, 29 Jun 2022 12:19:38 -0700 (PDT) Received: from pierre123.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 5D2323F792; Wed, 29 Jun 2022 12:19:36 -0700 (PDT) From: "PierreGondois" To: devel@edk2.groups.io Cc: Sami Mujawar , Leif Lindholm , Ard Biesheuvel , Rebecca Cran , Michael D Kinney , Liming Gao , Jiewen Yao , Jian J Wang Subject: [PATCH RESEND v1 6/9] MdePkg/DrbgLib: Add Ctr Drbg mechanism functions Date: Wed, 29 Jun 2022 21:18:43 +0200 Message-Id: <20220629191848.2619317-7-Pierre.Gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220629191848.2619317-1-Pierre.Gondois@arm.com> References: <20220629191848.2619317-1-Pierre.Gondois@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Pierre Gondois >>From the NIST Special Publication 800-90A, the implementation of a Drbg can be split into: 1. DRBG Mechanism Functions (s9 of the spec), describing the operations generic to all the mechanisms. 2. DRBG Algorithm Specifications (s10 of the spec), describing the operations specific to each mechanisms (CTR, HMAC, ...) This patch implements the 2., i.e. the operations specific to the Ctr Drbg mechanism. Signed-off-by: Pierre Gondois --- MdePkg/Library/DrbgLib/CtrDrbg.c | 899 +++++++++++++++++++++++++++++++ MdePkg/Library/DrbgLib/CtrDrbg.h | 100 ++++ 2 files changed, 999 insertions(+) create mode 100644 MdePkg/Library/DrbgLib/CtrDrbg.c create mode 100644 MdePkg/Library/DrbgLib/CtrDrbg.h diff --git a/MdePkg/Library/DrbgLib/CtrDrbg.c b/MdePkg/Library/DrbgLib/Ct= rDrbg.c new file mode 100644 index 000000000000..7db4d724086a --- /dev/null +++ b/MdePkg/Library/DrbgLib/CtrDrbg.c @@ -0,0 +1,899 @@ +/** @file + Ctr Drbg implementation. + (Counter Deterministic Random Bit Generator) + Cf. [1] s10.2.1 CTR_DRBG + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - [1] NIST Special Publication 800-90A Revision 1, June 2015, Recommen= dation + for Random Number Generation Using Deterministic Random Bit Gene= rators. + (https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/fina= l) + - [2] NIST Special Publication 800-90B, Recommendation for the Entropy + Sources Used for Random Bit Generation. + (https://csrc.nist.gov/publications/detail/sp/800-90b/final) + - [3] (Second Draft) NIST Special Publication 800-90C, Recommendation = for + Random Bit Generator (RBG) Constructions. + (https://csrc.nist.gov/publications/detail/sp/800-90c/draft) + - [4] NIST Special Publication 800-57 Part 1 Revision 5, May 2020, + Recommendation for Key Management:Part 1 - General. + (https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-= 5/final) + - [5] Unified Extensible Firmware Interface (UEFI) Specification, + Version 2.8 Errata B, May 2020 + (https://www.uefi.org/specifications) + - [6] FIPS 197 November 26, 2001: + Specification for the ADVANCED ENCRYPTION STANDARD (AES) + + @par Glossary: + - TRNG - True Random Number Generator + - Sec - Security + - DRBG - Deterministic Random Bits Generator + - CTR - Counter +**/ + +#include +#include +#include +#include + +#include "Common.h" +#include "CtrDrbg.h" + +/** Get a nonce. + + [1] s10.2.1.3.1 Instantiation When a Derivation Function is Not Used + + When instantiation is performed using this method, full-entropy input + is required, and a nonce is not used. + + @param [in, out] DrbgHandle The Drbg handle. + @param [out] NonceStream Stream containing the Nonce. + + @retval EFI_SUCCESS Success. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgGetNonce ( + IN OUT DRBG_HANDLE DrbgHandle, + OUT BIT_STREAM *NonceStream + ) +{ + // Nothing to do. + return EFI_SUCCESS; +} + +/** Check the internal state. + + @param [in] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgCheckInternalState ( + IN DRBG_HANDLE DrbgHandle + ) +{ + CTR_INTERNAL_STATE *CtrIntState; + + CtrIntState =3D (CTR_INTERNAL_STATE *)DrbgHandle->IntState.DrbgAlgoInt= State; + + // Just check that key and value BitStreams are still ok. + if ((IsBitStreamEmpty (CtrIntState->Val) || + (IsBitStreamEmpty (CtrIntState->Key)))) + { + ASSERT (!IsBitStreamEmpty (CtrIntState->Val)); + ASSERT (!IsBitStreamEmpty (CtrIntState->Key)); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** Update algorithm. + + CTR_DRBG_Update implementation. + + Cf. [1] s10.2.1.2 The Update Function (CTR_DRBG_Update) + + @param [in] ProvidedData The data to be used. This must be exac= tly + seedlen bits in length. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgUpdate ( + IN BIT_STREAM *ProvidedData, + IN OUT DRBG_HANDLE DrbgHandle + ) +{ + EFI_STATUS Status; + BIT_STREAM *IncStream; + BIT_STREAM *OutBlkStream; + BIT_STREAM *TempStream; + CTR_INTERNAL_STATE *CtrIntState; + CTR_VALUE_DEFINITIONS *CtrVal; + + if (IsBitStreamEmpty (ProvidedData) || + (DrbgHandle =3D=3D NULL) || + (DrbgHandle->IntState.DrbgAlgoIntState =3D=3D NULL) || + (DrbgHandle->DrbgVal.DrbgAlgoVal =3D=3D NULL)) + { + ASSERT (!IsBitStreamEmpty (ProvidedData)); + ASSERT (DrbgHandle !=3D NULL); + ASSERT (DrbgHandle->IntState.DrbgAlgoIntState !=3D NULL); + ASSERT (DrbgHandle->DrbgVal.DrbgAlgoVal !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + IncStream =3D NULL; + OutBlkStream =3D NULL; + TempStream =3D NULL; + CtrIntState =3D (CTR_INTERNAL_STATE *)DrbgHandle->IntState.DrbgAlgoIn= tState; + CtrVal =3D (CTR_VALUE_DEFINITIONS *)DrbgHandle->DrbgVal.DrbgAlgo= Val; + + if (BitStreamBitLen (ProvidedData) !=3D CtrVal->SeedLen) { + ASSERT (BitStreamBitLen (ProvidedData) =3D=3D CtrVal->SeedLen); + return EFI_INVALID_PARAMETER; + } + + // 1. temp =3D Null. + Status =3D BitStreamAlloc (0, &TempStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // 2. While (len (temp) < seedlen) do + while (BitStreamBitLen (TempStream) < CtrVal->SeedLen) { + // 2.1 If ctr_len < blocklen + if (CtrVal->CtrLen < CtrVal->SeedLen) { + // 2.1.1 inc =3D (rightmost (V, ctr_len) + 1) mod 2 ^ ctr_len. + Status =3D BitStreamRightmost ( + CtrIntState->Val, + CtrVal->CtrLen, + &IncStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamAddModulo (1, CtrVal->CtrLen, IncStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 2.1.2 V =3D leftmost (V, blocklen - ctr_len) || inc. + Status =3D BitStreamLeftmost ( + CtrIntState->Val, + CtrVal->BlockLen - CtrVal->CtrLen, + &CtrIntState->Val + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamConcat ( + CtrIntState->Val, + IncStream, + &CtrIntState->Val + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamFree (&IncStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } else { + // (2.1) Else V =3D (V+1) mod 2 ^ blocklen. + Status =3D BitStreamAddModulo (1, CtrVal->BlockLen, CtrIntState->V= al); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } + + // 2.2 output_block =3D Block_Encrypt (Key, V). + Status =3D BlockEncrypt (DrbgHandle, &OutBlkStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 2.3 temp =3D temp || output_block. + Status =3D BitStreamConcat (TempStream, OutBlkStream, &TempStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamFree (&OutBlkStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } // while + + // 3. temp =3D leftmost (temp, seedlen). + Status =3D BitStreamLeftmost (TempStream, CtrVal->SeedLen, &TempStream= ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 4. temp =3D temp XoR provided_data. + Status =3D BitStreamXor (TempStream, ProvidedData, &TempStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 5. Key =3D leftmost (temp, keylen). + Status =3D BitStreamFree (&CtrIntState->Key); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamLeftmost (TempStream, CtrVal->KeyLen, &CtrIntState= ->Key); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 6. V =3D rightmost (temp, blocklen). + Status =3D BitStreamFree (&CtrIntState->Val); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamRightmost ( + TempStream, + CtrVal->BlockLen, + &CtrIntState->Val + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + // Fall through. + } + +ExitHandler: + if (IncStream !=3D NULL) { + BitStreamFree (&IncStream); + } + + if (OutBlkStream !=3D NULL) { + BitStreamFree (&OutBlkStream); + } + + if (TempStream !=3D NULL) { + BitStreamFree (&TempStream); + } + + // 7. Return (Key, V). + return Status; +} + +/** Instantiate algorithm. + + CTR_DRBG_Instantiate_algorithm implementation. + + Cf. [1] s10.2.1.3.1 Instantiation When a Derivation Function is Not Us= ed + + @param [in] EntropyInput The string of bits obtained from the + randomness source. + @param [in] PersStrBitStream The personalization string received fr= om the + consuming application. Note that the l= ength + of the personalization_string may be z= ero. + Note: PersStrBitStream must be initial= ized, + even with a NULL BitStream. + @param [out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgInstantiateAlgo ( + IN BIT_STREAM *EntropyInput, + IN BIT_STREAM *PersStrBitStream, + OUT DRBG_HANDLE DrbgHandle + ) +{ + EFI_STATUS Status; + BIT_STREAM *LocalStream; + BIT_STREAM *SeedMaterial; + CTR_INTERNAL_STATE *CtrIntState; + CTR_VALUE_DEFINITIONS *CtrVal; + UINTN Temp; + + if (IsBitStreamEmpty (EntropyInput) || + (PersStrBitStream =3D=3D NULL) || + (DrbgHandle =3D=3D NULL) || + (DrbgHandle->IntState.DrbgAlgoIntState =3D=3D NULL) || + (DrbgHandle->DrbgVal.DrbgAlgoVal =3D=3D NULL)) + { + ASSERT (!IsBitStreamEmpty (EntropyInput)); + ASSERT (PersStrBitStream !=3D NULL); + ASSERT (DrbgHandle !=3D NULL); + ASSERT (DrbgHandle->IntState.DrbgAlgoIntState !=3D NULL); + ASSERT (DrbgHandle->DrbgVal.DrbgAlgoVal !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + LocalStream =3D NULL; + SeedMaterial =3D NULL; + CtrIntState =3D (CTR_INTERNAL_STATE *)DrbgHandle->IntState.DrbgAlgoIn= tState; + CtrVal =3D (CTR_VALUE_DEFINITIONS *)DrbgHandle->DrbgVal.DrbgAlgo= Val; + + // 1. temp =3D len (personalization_string). + Temp =3D BitStreamBitLen (PersStrBitStream); + + // 2. If (temp < seedlen), then + // personalization_string =3D personalization_string || 0 ^ seedlen - = temp. + if (Temp < CtrVal->SeedLen) { + Status =3D BitStreamAlloc (CtrVal->SeedLen - Temp, &LocalStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status =3D BitStreamConcat ( + PersStrBitStream, + LocalStream, + &PersStrBitStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } + + // 3. seed_material =3D entropy_input XoR personalization_string. + Status =3D BitStreamXor (EntropyInput, PersStrBitStream, &SeedMaterial= ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 4. Key =3D 0 ^ keylen. + Status =3D BitStreamAlloc (CtrVal->KeyLen, &CtrIntState->Key); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 5. V =3D 0 ^ blocklen. + Status =3D BitStreamAlloc (CtrVal->BlockLen, &CtrIntState->Val); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 6. (Key, V) =3D CTR_DRBG_Update (seed_material, Key, V). + Status =3D CtrDrbgUpdate (SeedMaterial, DrbgHandle); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 7. reseed_counter =3D 1. + CtrIntState->ReseedCounter =3D 1; + +ExitHandler: + if (SeedMaterial !=3D NULL) { + BitStreamFree (&SeedMaterial); + } + + if (LocalStream !=3D NULL) { + BitStreamFree (&LocalStream); + } + + // 8. Return (V, Key, reseed_counter). + return Status; +} + +/** Reseed algorithm + + CTR_DRBG_Reseed_algorithm implementation. + + Cf. [1] s10.2.1.4.1 Reseeding When a Derivation Function is Not Used + + @param [in] EntropyInput The string of bits obtained from the + randomness source. + @param [in] AddInput The additional input string received + from the consuming application. Note + that the length of the additional_inpu= t + string may be zero. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgReseedAlgo ( + IN BIT_STREAM *EntropyInput, + IN BIT_STREAM *AddInput, + IN OUT DRBG_HANDLE DrbgHandle + ) +{ + EFI_STATUS Status; + UINTN Temp; + BIT_STREAM *LocalStream; + BIT_STREAM *SeedMaterial; + CTR_INTERNAL_STATE *CtrIntState; + CTR_VALUE_DEFINITIONS *CtrVal; + + if (IsBitStreamEmpty (EntropyInput) || + (AddInput =3D=3D NULL) || + (DrbgHandle =3D=3D NULL) || + (DrbgHandle->IntState.DrbgAlgoIntState =3D=3D NULL) || + (DrbgHandle->DrbgVal.DrbgAlgoVal =3D=3D NULL)) + { + ASSERT (!IsBitStreamEmpty (EntropyInput)); + ASSERT (AddInput !=3D NULL); + ASSERT (DrbgHandle !=3D NULL); + ASSERT (DrbgHandle->IntState.DrbgAlgoIntState !=3D NULL); + ASSERT (DrbgHandle->DrbgVal.DrbgAlgoVal !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + LocalStream =3D NULL; + SeedMaterial =3D NULL; + CtrIntState =3D (CTR_INTERNAL_STATE *)DrbgHandle->IntState.DrbgAlgoIn= tState; + CtrVal =3D (CTR_VALUE_DEFINITIONS *)DrbgHandle->DrbgVal.DrbgAlgo= Val; + + // 1. temp =3D len (additional_input). + Temp =3D BitStreamBitLen (AddInput); + + // 2. If (temp < seedlen), + // then additional_input =3D additional_input || 0 ^ (seedlen - temp). + if (Temp < CtrVal->SeedLen) { + Status =3D BitStreamAlloc (CtrVal->SeedLen - Temp, &LocalStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status =3D BitStreamConcat ( + AddInput, + LocalStream, + &AddInput + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } + + // 3. seed_material =3D entropy_input XoR additional_input. + Status =3D BitStreamXor (EntropyInput, AddInput, &SeedMaterial); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 4. (Key, V) =3D CTR_DRBG_Update (seed_material, Key, V). + Status =3D CtrDrbgUpdate (SeedMaterial, DrbgHandle); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 5. reseed_counter =3D 1. + CtrIntState->ReseedCounter =3D 1; + +ExitHandler: + if (LocalStream !=3D NULL) { + BitStreamFree (&LocalStream); + } + + if (SeedMaterial !=3D NULL) { + BitStreamFree (&SeedMaterial); + } + + // 6. Return (V, Key, reseed_counter). + return Status; +} + +/** Generate algorithm. + + CTR_DRBG_Generate_algorithm implementation. + + Cf. s10.2.1.5.1 Generating Pseudorandom Bits When a Derivation Functio= n + is Not Used + + To reflect that 'a reseed is required before the requested pseudorando= m bits + can be generated', the EFI_NOT_READY return code is used. + + @param [in] AddInput The additional input string receiv= ed from + the consuming application. Note th= at the + length of the additional_input str= ing + may be zero. + @param [in] RequestedNbBits The number of pseudorandom bits to= be + returned to the generate function. + @param [out] RndBitStream BitStream containing the random bi= ts. + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_NOT_READY A reseed is required before the reques= ted + pseudorandom bits can be generated. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgGenerateAlgo ( + IN BIT_STREAM *AddInput, + IN UINTN RequestedNbBits, + OUT BIT_STREAM **RndBitStream, + IN OUT DRBG_HANDLE DrbgHandle + ) +{ + EFI_STATUS Status; + UINTN Temp; + BIT_STREAM *IncStream; + BIT_STREAM *LocalStream; + BIT_STREAM *OutBlkStream; + BIT_STREAM *TempStream; + CTR_INTERNAL_STATE *CtrIntState; + CTR_VALUE_DEFINITIONS *CtrVal; + + if ((AddInput =3D=3D NULL) || + (RequestedNbBits =3D=3D 0) || + (RndBitStream =3D=3D NULL) || + (*RndBitStream !=3D NULL) || + (DrbgHandle =3D=3D NULL) || + (DrbgHandle->IntState.DrbgAlgoIntState =3D=3D NULL) || + (DrbgHandle->DrbgVal.DrbgAlgoVal =3D=3D NULL)) + { + ASSERT (AddInput !=3D NULL); + ASSERT (RequestedNbBits !=3D 0); + ASSERT (RndBitStream !=3D NULL); + ASSERT (*RndBitStream =3D=3D NULL); + ASSERT (DrbgHandle !=3D NULL); + ASSERT (DrbgHandle->IntState.DrbgAlgoIntState !=3D NULL); + ASSERT (DrbgHandle->DrbgVal.DrbgAlgoVal !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + IncStream =3D NULL; + LocalStream =3D NULL; + OutBlkStream =3D NULL; + TempStream =3D NULL; + CtrIntState =3D (CTR_INTERNAL_STATE *)DrbgHandle->IntState.DrbgAlgoIn= tState; + CtrVal =3D (CTR_VALUE_DEFINITIONS *)DrbgHandle->DrbgVal.DrbgAlgo= Val; + + // 1. If reseed_counter > reseed_interval, + // then return an indication that a reseed is required. + if (CtrIntState->ReseedCounter > CtrVal->ReseedInterval) { + return EFI_NOT_READY; + } + + // 2. If (additional_input !=3D Null), then + if (!IsBitStreamEmpty (AddInput)) { + // 2.1 temp =3D len (additional_input). + Temp =3D BitStreamBitLen (AddInput); + + // 2.2 If (temp < seedlen), then + // additional_input =3D additional_input || 0 seedlen - temp . + if (Temp < CtrVal->SeedLen) { + Status =3D BitStreamAlloc (CtrVal->SeedLen - Temp, &LocalStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status =3D BitStreamConcat (AddInput, LocalStream, &AddInput); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } + + // 2.3 (Key, V) =3D CTR_DRBG_Update (additional_input, Key, V). + Status =3D CtrDrbgUpdate (AddInput, DrbgHandle); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } else { + // (2.) Else additional_input =3D 0 ^ seedlen. + Status =3D BitStreamFree (&AddInput); // Freeing &AddInput, this is = wrong, AddInput is now a local parameter + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamAlloc (CtrVal->SeedLen, &AddInput); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } + + // 3. temp =3D Null. + Status =3D BitStreamAlloc (0, &TempStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 4. While (len (temp) < requested_number_of_bits) do: + while (BitStreamBitLen (TempStream) < RequestedNbBits) { + // 4.1 If ctr_len < blocklen + if (CtrVal->CtrLen < CtrVal->BlockLen) { + // 4.1.1 inc =3D (rightmost (V, ctr_len) + 1) mod 2 ^ ctr_len. + Status =3D BitStreamRightmost ( + CtrIntState->Val, + CtrVal->CtrLen, + &IncStream + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamAddModulo (1, CtrVal->CtrLen, IncStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 4.1.2 V =3D leftmost (V, blocklen-ctr_len) || inc. + Status =3D BitStreamLeftmost ( + CtrIntState->Val, + CtrVal->BlockLen - CtrVal->CtrLen, + &CtrIntState->Val + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamConcat ( + CtrIntState->Val, + IncStream, + &CtrIntState->Val + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamFree (&IncStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } else { + // (4.1) Else V =3D (V+1) mod 2 ^ blocklen. + Status =3D BitStreamAddModulo (1, CtrVal->BlockLen, CtrIntState->V= al); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } + + // 4.2 output_block =3D Block_Encrypt (Key, V). + Status =3D BlockEncrypt (DrbgHandle, &OutBlkStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 4.3 temp =3D temp || output_block. + Status =3D BitStreamConcat (TempStream, OutBlkStream, &TempStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + Status =3D BitStreamFree (&OutBlkStream); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + } // while + + // 5. returned_bits =3D leftmost (temp, requested_number_of_bits). + Status =3D BitStreamLeftmost (TempStream, RequestedNbBits, RndBitStrea= m); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 6. (Key, V) =3D CTR_DRBG_Update (additional_input, Key, V). + Status =3D CtrDrbgUpdate (AddInput, DrbgHandle); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + goto ExitHandler; + } + + // 7. reseed_counter =3D reseed_counter + 1. + CtrIntState->ReseedCounter +=3D 1; + +ExitHandler: + if (IncStream !=3D NULL) { + BitStreamFree (&IncStream); + } + + if (LocalStream !=3D NULL) { + BitStreamFree (&LocalStream); + } + + if (OutBlkStream !=3D NULL) { + BitStreamFree (&OutBlkStream); + } + + if (TempStream !=3D NULL) { + BitStreamFree (&TempStream); + } + + // 8. Return (SUCCESS, returned_bits, Key, V, reseed_counter). + return Status; +} + +/** Uninstantiate a DRBG instance. + + [1] s9.4 Removing a DRBG Instantiation + + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +STATIC +EFI_STATUS +EFIAPI +CtrDrbgUninstantiateFn ( + IN OUT DRBG_HANDLE DrbgHandle + ) +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + CTR_INTERNAL_STATE *CtrIntState; + + if ((DrbgHandle =3D=3D NULL) || + (DrbgHandle->IntState.DrbgAlgoIntState =3D=3D NULL) || + (DrbgHandle->DrbgVal.DrbgAlgoVal =3D=3D NULL)) + { + ASSERT (DrbgHandle !=3D NULL); + ASSERT (DrbgHandle->IntState.DrbgAlgoIntState !=3D NULL); + ASSERT (DrbgHandle->DrbgVal.DrbgAlgoVal !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + ReturnStatus =3D EFI_SUCCESS; + CtrIntState =3D (CTR_INTERNAL_STATE *)DrbgHandle->IntState.DrbgAlgoIn= tState; + + // 1. If state_handle indicates an invalid state, then return (ERROR_F= LAG). + // 2. Erase the contents of the internal state indicated by state_hand= le. + + Status =3D BitStreamFree (&CtrIntState->Key); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + ReturnStatus =3D Status; + } + + Status =3D BitStreamFree (&CtrIntState->Val); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + ReturnStatus =3D Status; + } + + FreePool (DrbgHandle); + + // 3. Return (SUCCESS). + return ReturnStatus; +} + +/** Drbg mechanism specific instantiation steps. + + @param [in, out] DrbgHandle The Drbg handle. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Out of resources. +**/ +EFI_STATUS +EFIAPI +CtrInitHandle ( + IN OUT DRBG_HANDLE DrbgHandle + ) +{ + DRBG_VALUE_DEFINITIONS *DrbgVal; + CTR_INTERNAL_STATE *CtrIntState; + CTR_VALUE_DEFINITIONS *CtrVal; + + if (DrbgHandle =3D=3D NULL) { + ASSERT (DrbgHandle !=3D NULL); + return EFI_INVALID_PARAMETER; + } + + CopyMem ( + &DrbgHandle->Algo, + &gEfiRngAlgorithmSp80090Ctr256Guid, + sizeof (EFI_RNG_ALGORITHM) + ); + + // Allocate CtrIntState. Fields are init to 0. + CtrIntState =3D AllocateZeroPool (sizeof (CTR_INTERNAL_STATE)); + if (CtrIntState =3D=3D NULL) { + ASSERT (CtrIntState !=3D NULL); + return EFI_OUT_OF_RESOURCES; + } + + DrbgHandle->IntState.DrbgAlgoIntState =3D CtrIntState; + + // Allocate CtrVal. Fields are init to 0. + CtrVal =3D AllocateZeroPool (sizeof (CTR_VALUE_DEFINITIONS)); + if (CtrVal =3D=3D NULL) { + ASSERT (CtrVal !=3D NULL); + FreePool (CtrIntState); + return EFI_OUT_OF_RESOURCES; + } + + DrbgHandle->DrbgVal.DrbgAlgoVal =3D CtrVal; + + // CTR DRBG definitions, cf [1] Table 3 'Definitions for the CTR_DRBG'= . + // No derivation function is used. + // Only 256 bits AES is allowed (Cf. [5] 'Section 37.5 Random Number + // Generator Protocol') + + // Drbg generic values. + DrbgVal =3D &DrbgHandle->DrbgVal; + DrbgVal->HighestSuppSecStrength =3D 256; + DrbgVal->MinLen =3D CTR_DRBG_AES_256_SEEDLEN; + DrbgVal->MaxLen =3D CTR_DRBG_AES_256_SEEDLEN; + DrbgVal->MaxPersStrLen =3D CTR_DRBG_AES_256_SEEDLEN; + DrbgVal->MaxAddInputLen =3D CTR_DRBG_AES_256_SEEDLEN; + DrbgVal->MaxNbBitsPerRequest =3D 1 << 19; + + // Ctr specific values. + CtrVal->BlockLen =3D CTR_DRBG_AES_BLOCKLEN; + // 4 <=3D ctr_len <=3D blocklen. Choose blocklen to be faster. + CtrVal->CtrLen =3D CTR_DRBG_AES_BLOCKLEN; + CtrVal->KeyLen =3D CTR_DRBG_AES_256_KEYLEN; + CtrVal->MinRequiredEntropy =3D SecStrength256bits; + CtrVal->SeedLen =3D CTR_DRBG_AES_256_SEEDLEN; + CtrVal->ReseedInterval =3D (UINT64)1 << 48; + + // CtrDrbg supports both mechanisms. + DrbgHandle->PredResSupported =3D TRUE; + DrbgHandle->ReseedSupported =3D TRUE; + + // CtrDrbg specific implementations. + DrbgHandle->DrbgGetNonce =3D CtrDrbgGetNonce; + DrbgHandle->DrbgCheckInternalState =3D CtrDrbgCheckInternalState; + DrbgHandle->DrbgUpdate =3D CtrDrbgUpdate; + DrbgHandle->DrbgReseedAlgo =3D CtrDrbgReseedAlgo; + DrbgHandle->DrbgGenerateAlgo =3D CtrDrbgGenerateAlgo; + DrbgHandle->DrbgInstantiateAlgo =3D CtrDrbgInstantiateAlgo; + DrbgHandle->DrbgUninstantiateFn =3D CtrDrbgUninstantiateFn; + + return EFI_SUCCESS; +} diff --git a/MdePkg/Library/DrbgLib/CtrDrbg.h b/MdePkg/Library/DrbgLib/Ct= rDrbg.h new file mode 100644 index 000000000000..df9c5108388a --- /dev/null +++ b/MdePkg/Library/DrbgLib/CtrDrbg.h @@ -0,0 +1,100 @@ +/** @file + Ctr Drbg implementation. + (Counter Deterministic Random Bit Generator) + Cf. [1] s10.2.1 CTR_DRBG + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - [1] NIST Special Publication 800-90A Revision 1, June 2015, Recommen= dation + for Random Number Generation Using Deterministic Random Bit Gene= rators. + (https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/fina= l) + - [2] NIST Special Publication 800-90B, Recommendation for the Entropy + Sources Used for Random Bit Generation. + (https://csrc.nist.gov/publications/detail/sp/800-90b/final) + - [3] (Second Draft) NIST Special Publication 800-90C, Recommendation = for + Random Bit Generator (RBG) Constructions. + (https://csrc.nist.gov/publications/detail/sp/800-90c/draft) + - [4] NIST Special Publication 800-57 Part 1 Revision 5, May 2020, + Recommendation for Key Management:Part 1 - General. + (https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-= 5/final) + - [5] Unified Extensible Firmware Interface (UEFI) Specification, + Version 2.8 Errata B, May 2020 + (https://www.uefi.org/specifications) + - [6] FIPS 197 November 26, 2001: + Specification for the ADVANCED ENCRYPTION STANDARD (AES) + + @par Glossary: + - TRNG - True Random Number Generator + - Sec - Security + - DRBG - Deterministic Random Bits Generator + - CTR - Counter +**/ + +#ifndef CTR_DRBG_LIB_H_ +#define CTR_DRBG_LIB_H_ + +/* Blocklen when using CTR DRBG AES-128, AES-192 and + AES-256 algorithm. + + Cf. [6] Figure 4. 'Key-Block-Round Combinations' + Cf. [1] Table 3 'Definitions for the CTR_DRBG' + + Output block length is also called 'outlen'. +*/ +#define CTR_DRBG_AES_BLOCKLEN 128 + +/* Key length when using CTR DRBG AES-256 algorithm. + + Cf. [1] Table 3 'Definitions for the CTR_DRBG' + Cf. [5] s37.5 'Random Number Generator Protocol': + 'Security level must be at least 256 bits' +*/ +#define CTR_DRBG_AES_256_KEYLEN 256 + +/** Seed length when using CTR DRBG AES-256 algorithm. + + Cf. [1] Table 3 'Definitions for the CTR_DRBG' + Seed length (seedlen =3D outlen + keylen) +*/ +#define CTR_DRBG_AES_256_SEEDLEN (CTR_DRBG_AES_BLOCKLEN + \ + CTR_DRBG_AES_256_KEYLEN) + +/** Ctr specific internal state. + + Some fields defined at [1] s10.2.1.1 'CTR_DRBG Internal State' might b= e + in the DRBG_INTERNAL_STATE structure. +*/ +typedef struct { + // Working state. + /// Value + BIT_STREAM *Val; + /// Key + BIT_STREAM *Key; + /// Counter: Number of requests for pseudorandom bits + /// since instantiation or reseeding + UINTN ReseedCounter; +} CTR_INTERNAL_STATE; + +/** Ctr specific values. + + Cf. [1] Table 3: Definitions for the CTR_DRBG + Some fields might be in the DRBG_VALUE_DEFINITIONS structure. +*/ +typedef struct { + /// Input and output block length + UINTN BlockLen; + /// Counter field length. + UINTN CtrLen; + // Key length. + UINTN KeyLen; + /// Required minimum entropy for instantiate and reseed. + UINTN MinRequiredEntropy; + /// Seed length. + UINTN SeedLen; + /// Maximum number of requests between two reseeds. + UINT64 ReseedInterval; +} CTR_VALUE_DEFINITIONS; + +#endif // CTR_DRBG_LIB_H_ --=20 2.25.1