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.web08.15772.1656530084725520595 for ; Wed, 29 Jun 2022 12:14:44 -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 A8496152B; Wed, 29 Jun 2022 12:14:44 -0700 (PDT) Received: from pierre123.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 44F7B3F792; Wed, 29 Jun 2022 12:14:42 -0700 (PDT) From: "PierreGondois" To: devel@edk2.groups.io Cc: Sami Mujawar , Leif Lindholm , Ard Biesheuvel , Rebecca Cran , Michael D Kinney , Liming Gao , Edward Pickup Subject: [PATCH RESEND v1 7/7] ArmPkg/ArmAesLib: Add ArmAesLib Date: Wed, 29 Jun 2022 21:13:55 +0200 Message-Id: <20220629191355.2618844-8-Pierre.Gondois@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220629191355.2618844-1-Pierre.Gondois@arm.com> References: <20220629191355.2618844-1-Pierre.Gondois@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Pierre Gondois BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3970 The Armv8.0 Cryptographic Extension 'FEAT_AES' provides instructions for the acceleration of encryption and decryption. Add an ArmAesLib relying on this feature to implement the AES algorithm. Signed-off-by: Pierre Gondois --- ArmPkg/ArmPkg.dsc | 3 +- .../Library/ArmAesLib/AArch64/AArch64AesLib.S | 183 ++++++++++++ ArmPkg/Library/ArmAesLib/Arm/ArmAesLib.S | 183 ++++++++++++ ArmPkg/Library/ArmAesLib/ArmAesLib.c | 261 ++++++++++++++++++ ArmPkg/Library/ArmAesLib/ArmAesLib.h | 96 +++++++ ArmPkg/Library/ArmAesLib/ArmAesLib.inf | 34 +++ 6 files changed, 759 insertions(+), 1 deletion(-) create mode 100644 ArmPkg/Library/ArmAesLib/AArch64/AArch64AesLib.S create mode 100644 ArmPkg/Library/ArmAesLib/Arm/ArmAesLib.S create mode 100644 ArmPkg/Library/ArmAesLib/ArmAesLib.c create mode 100644 ArmPkg/Library/ArmAesLib/ArmAesLib.h create mode 100644 ArmPkg/Library/ArmAesLib/ArmAesLib.inf diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 02d1caa3ab40..72efeb77012e 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -2,7 +2,7 @@ # ARM processor package. # # Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.
-# Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.
+# Copyright (c) 2011 - 2022, Arm Limited. All rights reserved.
# Copyright (c) 2016, Linaro Ltd. All rights reserved.
# Copyright (c) Microsoft Corporation.
# Copyright (c) 2021, Ampere Computing LLC. All rights reserved. @@ -139,6 +139,7 @@ [Components.common] ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf ArmPkg/Library/OpteeLib/OpteeLib.inf ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf + ArmPkg/Library/ArmAesLib/ArmAesLib.inf =20 ArmPkg/Filesystem/SemihostFs/SemihostFs.inf =20 diff --git a/ArmPkg/Library/ArmAesLib/AArch64/AArch64AesLib.S b/ArmPkg/Li= brary/ArmAesLib/AArch64/AArch64AesLib.S new file mode 100644 index 000000000000..07d1d30e6e91 --- /dev/null +++ b/ArmPkg/Library/ArmAesLib/AArch64/AArch64AesLib.S @@ -0,0 +1,183 @@ +/** @file + AArch64 AES implementation. + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +.arch_extension crypto + +// Generic notes: +// - In AArch64, the AESE/AESD/AESMC/AESIMC instructions are using regis= ters +// as .16B +// - For some CPUs, the latency of LD1 is 6, thus the unfolding. +// - The latency of the AESE/AESMC pair is 2. +// Cf. +// Arm Cortex-X1 Core Revision: r1p2 Software Optimization Guide +// Arm Cortex-X2 Core Revision: r2p0 Software Optimization Guide + +// /** Encrypt an AES block. +// +// @param [in] ExpEncKey Expanded encryption key. An array of 32-bit= s words +// with the number of elements depending on th= e key +// size: +// * 128-bits: 44 words +// * 192-bits: 52 words +// * 256-bits: 60 words +// @param [in] Rounds Number of rounds (depending on the key size= ). +// @param [in] InBlock Input Block. The block to cipher. +// @param [out] OutBlock Output Block. The ciphered block. +// **/ +// VOID +// ArmAesEncrypt ( +// IN UINT32 CONST *ExpEncKey, +// IN UINT32 Rounds, +// IN UINT8 CONST *InBlock, +// OUT UINT8 *OutBlock +// ); +ASM_FUNC(ArmAesEncrypt) + ld1 {v0.16b}, [x2] + cmp w1, #12 + beq 0f + + // Rounds =3D 10 or 14. Start loading the expanded key. + ld1 {v4.4s}, [x0], #16 + ld1 {v1.4s}, [x0], #16 + ld1 {v2.4s}, [x0], #16 + adds w1, w1, #1 + b 2f + + // Rounds =3D 12. Start loading the expanded key. +0: ld1 {v2.4s}, [x0], #16 + ld1 {v3.4s}, [x0], #16 + ld1 {v4.4s}, [x0], #16 + subs w1, w1, #1 + b 3f + + // Start of the loop (unfolded for 4 rounds). +1: ld1 {v4.4s}, [x0], #16 + aese v0.16b, v1.16b + aesmc v0.16b, v0.16b +3: ld1 {v1.4s}, [x0], #16 + aese v0.16b, v2.16b + aesmc v0.16b, v0.16b + ld1 {v2.4s}, [x0], #16 + aese v0.16b, v3.16b + aesmc v0.16b, v0.16b +2: subs w1, w1, #4 + ld1 {v3.4s}, [x0], #16 + aese v0.16b, v4.16b + aesmc v0.16b, v0.16b + bpl 1b + + // Final round. + aese v0.16b, v1.16b + eor v0.16b, v0.16b, v2.16b + st1 {v0.16b}, [x3] + ret + +// /** Decrypt an AES 128-bits block. +// +// @param [in] ExpDecKey Expanded decryption key. An array of 32-bit= s words +// with the number of elements depending on th= e key +// size: +// * 128-bits: 44 words +// * 192-bits: 52 words +// * 256-bits: 60 words +// @param [in] Rounds Number of rounds (depending on the key size= ). +// @param [in] InBlock Input Block. The block to de-cipher. +// @param [out] OutBlock Output Block. The de-ciphered block. +// **/ +// VOID +// ArmAesDecrypt ( +// IN UINT32 CONST *ExpDecKey, +// IN UINT32 Rounds, +// IN UINT8 CONST *InBlock, +// OUT UINT8 *OutBlock +// ); +ASM_FUNC(ArmAesDecrypt) + ld1 {v0.16b}, [x2] + cmp w1, #12 + beq 0f + + // Rounds =3D 10 or 14. Start loading the expanded key. + ld1 {v4.4s}, [x0], #16 + ld1 {v1.4s}, [x0], #16 + ld1 {v2.4s}, [x0], #16 + adds w1, w1, #1 + b 2f + + // Rounds =3D 12. Start loading the expanded key. +0: ld1 {v2.4s}, [x0], #16 + ld1 {v3.4s}, [x0], #16 + ld1 {v4.4s}, [x0], #16 + subs w1, w1, #1 + b 3f + + // Start of the loop (unfolded for 4 rounds). +1: ld1 {v4.4s}, [x0], #16 + aesd v0.16b, v1.16b + aesimc v0.16b, v0.16b +3: ld1 {v1.4s}, [x0], #16 + aesd v0.16b, v2.16b + aesimc v0.16b, v0.16b + ld1 {v2.4s}, [x0], #16 + aesd v0.16b, v3.16b + aesimc v0.16b, v0.16b +2: subs w1, w1, #4 + ld1 {v3.4s}, [x0], #16 + aesd v0.16b, v4.16b + aesimc v0.16b, v0.16b + bpl 1b + + // Final round. + aesd v0.16b, v1.16b + eor v0.16b, v0.16b, v2.16b + st1 {v0.16b}, [x3] + ret + +// /** Perform a SubWord() operation (applying AES Sbox) on a 32-bits wo= rd. +// +// The Arm AESE instruction performs the AddRoundKey(), ShiftRows() an= d +// SubBytes() AES steps in this order. +// +// During key expansion, only SubBytes() should be performed, so: +// - use a key of {0} so AddRoundKey() becomes an identity function; +// - the dup instruction allows to have a matrix with identic rows, +// so ShiftRows() has no effect. +// +// @param [in] InWord The 32-bits word to apply SubWord() on. +// +// @return SubWord(word). +// **/ +// UINT32 +// ArmAesSubWord ( +// IN UINT32 InWord +// ); +ASM_FUNC(ArmAesSubWord) + dup v1.4s, w0 + movi v0.16b, #0 + aese v0.16b, v1.16b + umov w0, v0.s[0] + ret + +// /** Perform a InvMixColumns() operation on an AES block (128-bits) us= ing +// the Arm AESIMC instruction. +// +// This is usefull to get decryption key for the Equivalent Inverse Ci= pher. +// +// @param [in] InBlock Input block. +// @param [out] OutBlock Output blocked. +// **/ +// VOID +// ArmAesInvert ( +// IN AES_BLOCK CONST *InBlock, +// OUT AES_BLOCK *OutBlock +// ); +ASM_FUNC(ArmAesInvert) + ld1 {v0.4s}, [x1] + aesimc v1.16b, v0.16b + st1 {v1.4s}, [x0] + ret diff --git a/ArmPkg/Library/ArmAesLib/Arm/ArmAesLib.S b/ArmPkg/Library/Ar= mAesLib/Arm/ArmAesLib.S new file mode 100644 index 000000000000..247d7c3d9ca2 --- /dev/null +++ b/ArmPkg/Library/ArmAesLib/Arm/ArmAesLib.S @@ -0,0 +1,183 @@ +/** @file + Arm(32) AES implementation. + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +.fpu crypto-neon-fp-armv8 + +// Generic notes: +// - In Arm32, the AESE/AESD/AESMC/AESIMC instructions are using registe= rs +// as qX +// - For some CPUs, the latency of VLD1 is 6, thus the unfolding. +// - The latency of the AESE/AESMC pair is 2. +// Cf. +// Arm Cortex-X1 Core Revision: r1p2 Software Optimization Guide +// Arm Cortex-X2 Core Revision: r2p0 Software Optimization Guide + +// /** Encrypt an AES block. +// +// @param [in] ExpEncKey Expanded encryption key. An array of 32-bit= s words +// with the number of elements depending on th= e key +// size: +// * 128-bits: 44 words +// * 192-bits: 52 words +// * 256-bits: 60 words +// @param [in] Rounds Number of rounds (depending on the key size= ). +// @param [in] InBlock Input Block. The block to cipher. +// @param [out] OutBlock Output Block. The ciphered block. +// **/ +// VOID +// ArmAesEncrypt ( +// IN UINT32 CONST *ExpEncKey, +// IN UINT32 Rounds, +// IN UINT8 CONST *InBlock, +// OUT UINT8 *OutBlock +// ); +ASM_FUNC(ArmAesEncrypt) + vld1.8 {q0}, [r2] + cmp r1, #12 + beq 0f + + // Rounds =3D 10 or 14. Start loading the expanded key. + vld1.8 {q4}, [r0]! + vld1.8 {q1}, [r0]! + vld1.8 {q2}, [r0]! + adds r1, r1, #1 + b 2f + + // Rounds =3D 12. Start loading the expanded key. +0: vld1.8 {q2}, [r0]! + vld1.8 {q3}, [r0]! + vld1.8 {q4}, [r0]! + subs r1, r1, #1 + b 3f + + // Start of the loop (unfolded for 4 rounds). +1: vld1.8 {q4}, [r0]! + aese.8 q0, q1 + aesmc.8 q0, q0 +3: vld1.8 {q1}, [r0]! + aese.8 q0, q2 + aesmc.8 q0, q0 + vld1.8 {q2}, [r0]! + aese.8 q0, q3 + aesmc.8 q0, q0 +2: subs r1, r1, #4 + vld1.8 {q3}, [r0]! + aese.8 q0, q4 + aesmc.8 q0, q0 + bpl 1b + + // Final round. + aese.8 q0, q1 + veor q0, q0, q2 + vst1.8 {q0}, [r3] + bx lr + +// /** Decrypt an AES 128-bits block. +// +// @param [in] ExpDecKey Expanded decryption key. An array of 32-bit= s words +// with the number of elements depending on th= e key +// size: +// * 128-bits: 44 words +// * 192-bits: 52 words +// * 256-bits: 60 words +// @param [in] Rounds Number of rounds (depending on the key size= ). +// @param [in] InBlock Input Block. The block to de-cipher. +// @param [out] OutBlock Output Block. The de-ciphered block. +// **/ +// VOID +// ArmAesDecrypt ( +// IN UINT32 CONST *ExpDecKey, +// IN UINT32 Rounds, +// IN UINT8 CONST *InBlock, +// OUT UINT8 *OutBlock +// ); +ASM_FUNC(ArmAesDecrypt) + vld1.8 {q0}, [r2] + cmp r1, #12 + beq 0f + + // Rounds =3D 10 or 14. Start loading the expanded key. + vld1.8 {q4}, [r0]! + vld1.8 {q1}, [r0]! + vld1.8 {q2}, [r0]! + adds r1, r1, #1 + b 2f + + // Rounds =3D 12. Start loading the expanded key. +0: vld1.8 {q2}, [r0]! + vld1.8 {q3}, [r0]! + vld1.8 {q4}, [r0]! + subs r1, r1, #1 + b 3f + + // Start of the loop (unfolded for 4 rounds). +1: vld1.8 {q4}, [r0]! + aesd.8 q0, q1 + aesimc.8 q0, q0 +3: vld1.8 {q1}, [r0]! + aesd.8 q0, q2 + aesimc.8 q0, q0 + vld1.8 {q2}, [r0]! + aesd.8 q0, q3 + aesimc.8 q0, q0 +2: subs r1, r1, #4 + vld1.8 {q3}, [r0]! + aesd.8 q0, q4 + aesimc.8 q0, q0 + bpl 1b + + // Final round. + aesd.8 q0, q1 + veor q0, q0, q2 + vst1.8 {q0}, [r3] + bx lr + +// /** Perform a SubWord() operation (applying AES Sbox) on a 32-bits wo= rd. +// +// The Arm AESE instruction performs the AddRoundKey(), ShiftRows() an= d +// SubBytes() AES steps in this order. +// +// During key expansion, only SubBytes() should be performed, so: +// - use a key of {0} so AddRoundKey() becomes an identity function; +// - the dup instruction allows to have a matrix with identic rows, +// so ShiftRows() has no effect. +// +// @param [in] InWord The 32-bits word to apply SubWord() on. +// +// @return SubWord(word). +// **/ +// UINT32 +// ArmAesSubWord ( +// IN UINT32 InWord +// ); +ASM_FUNC(ArmAesSubWord) + vdup.32 q1, r0 + vmov.i64 q0, #0 + aese.8 q0, q1 + vmov.f32 r0, s0 + bx lr + +// /** Perform a InvMixColumns() operation on an AES block (128-bits) us= ing +// the Arm AESIMC instruction. +// +// This is usefull to get decryption key for the Equivalent Inverse Ci= pher. +// +// @param [in] InBlock Input block. +// @param [out] OutBlock Output blocked. +// **/ +// VOID +// ArmAesInvert ( +// IN AES_BLOCK CONST *InBlock, +// OUT AES_BLOCK *OutBlock +// ); +ASM_FUNC(ArmAesInvert) + vld1.8 {q0}, [r1] + aesimc.8 q1, q0 + vst1.8 {q1}, [r0] + bx lr diff --git a/ArmPkg/Library/ArmAesLib/ArmAesLib.c b/ArmPkg/Library/ArmAes= Lib/ArmAesLib.c new file mode 100644 index 000000000000..ff3cfce75b2b --- /dev/null +++ b/ArmPkg/Library/ArmAesLib/ArmAesLib.c @@ -0,0 +1,261 @@ +/** @file + Arm AES Library + + Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - FIPS 197 November 26, 2001: + Specification for the ADVANCED ENCRYPTION STANDARD (AES) +**/ + +#include +#include +#include +#include +#include +#include "ArmAesLib.h" + +/** The constructor checks that the FEAT_AES extension is available. + + @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS= . +**/ +RETURN_STATUS +EFIAPI +AesLibConstructor ( + VOID + ) +{ + if (!ArmHasAesExt ()) { + DEBUG (( + DEBUG_ERROR, + "FEAT_AES extension is not available. " + "This library cannot be used.\n" + )); + ASSERT_RETURN_ERROR (RETURN_UNSUPPORTED); + } + + return RETURN_SUCCESS; +} + +/** + AES key schedule round constants. +*/ +STATIC +UINT8 CONST +mRoundConstants[] =3D { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, +}; + +/** Get the number of Rounds. + + AES needs to perform a different number of rounds depending on the key= size: + * 128-bits: 10 + * 192-bits: 12 + * 256-bits: 14 + So 6 + (n/4) rounds + + @param [in] AesCtx AES context struct. + + @return Number of rounds. +**/ +STATIC +UINT32 +GetNumRounds ( + IN AES_CTX CONST *AesCtx + ) +{ + return 6 + (AesCtx->KeySize >> 2); +} + +/** Encrypt an AES block. + + Buffers are little-endian. Overlapping is not checked. + + @param [in] AesCtx AES context. + AesCtx is initialized with AesInitCtx (). + @param [in] InBlock Input Block. The block to cipher. + @param [out] OutBlock Output Block. The ciphered block. + + @retval RETURN_SUCCESS Success. + @retval RETURN_INVALID_PARAMETER Invalid parameter. + @retval RETURN_UNSUPPORTED Unsupported. +**/ +RETURN_STATUS +EFIAPI +AesEncrypt ( + IN AES_CTX *AesCtx, + IN UINT8 CONST *InBlock, + OUT UINT8 *OutBlock + ) +{ + if ((AesCtx =3D=3D NULL) || + (InBlock =3D=3D NULL) || + (OutBlock =3D=3D NULL) || + (InBlock =3D=3D OutBlock)) + { + ASSERT (AesCtx !=3D NULL); + ASSERT (InBlock !=3D NULL); + ASSERT (OutBlock !=3D NULL); + ASSERT (InBlock !=3D OutBlock); + return RETURN_INVALID_PARAMETER; + } + + ArmAesEncrypt ( + AesCtx->ExpEncKey, + GetNumRounds (AesCtx), + InBlock, + OutBlock + ); + + return RETURN_SUCCESS; +} + +/** Decrypt an AES block. + + Buffers are little-endian. Overlapping is not checked. + + @param [in] AesCtx AES context. + AesCtx is initialized with AesInitCtx (). + @param [in] InBlock Input Block. The block to de-cipher. + @param [out] OutBlock Output Block. The de-ciphered block. + + @retval RETURN_SUCCESS Success. + @retval RETURN_INVALID_PARAMETER Invalid parameter. + @retval RETURN_UNSUPPORTED Unsupported. +**/ +RETURN_STATUS +EFIAPI +AesDecrypt ( + IN AES_CTX *AesCtx, + IN UINT8 CONST *InBlock, + OUT UINT8 *OutBlock + ) +{ + if ((AesCtx =3D=3D NULL) || + (InBlock =3D=3D NULL) || + (OutBlock =3D=3D NULL) || + (InBlock =3D=3D OutBlock)) + { + ASSERT (AesCtx !=3D NULL); + ASSERT (InBlock !=3D NULL); + ASSERT (OutBlock !=3D NULL); + ASSERT (InBlock !=3D OutBlock); + return RETURN_INVALID_PARAMETER; + } + + ArmAesDecrypt ( + AesCtx->ExpDecKey, + GetNumRounds (AesCtx), + InBlock, + OutBlock + ); + + return RETURN_SUCCESS; +} + +/** Initialize an AES_CTX structure. + + @param [in] Key AES key. Buffer of KeySize bytes. + The buffer is little endian. + @param [in] KeySize Size of the key. Must be one of 128|192|25= 6. + @param [in, out] AesCtx AES context to initialize. + + @retval RETURN_SUCCESS Success. + @retval RETURN_INVALID_PARAMETER Invalid parameter. + @retval RETURN_UNSUPPORTED Unsupported. +**/ +RETURN_STATUS +EFIAPI +AesInitCtx ( + IN UINT8 *Key, + IN UINT32 KeySize, + IN OUT AES_CTX *AesCtx + ) +{ + UINTN Index; + UINTN RevIndex; + UINT32 KeyWords; + UINT32 *KeyIn; + UINT32 *KeyOut; + AES_BLOCK *InBlock; + AES_BLOCK *OutBlock; + + if ((Key =3D=3D NULL) || + ((KeySize !=3D 8 * AES_KEY_SIZE_128) && + (KeySize !=3D 8 * AES_KEY_SIZE_192) && + (KeySize !=3D 8 * AES_KEY_SIZE_256)) || + (AesCtx =3D=3D NULL)) + { + ASSERT (Key !=3D NULL); + ASSERT ( + !((KeySize !=3D 8 * AES_KEY_SIZE_128) && + (KeySize !=3D 8 * AES_KEY_SIZE_192) && + (KeySize !=3D 8 * AES_KEY_SIZE_256)) + ); + ASSERT (AesCtx !=3D NULL); + return RETURN_INVALID_PARAMETER; + } + + // Internally, use bytes. + KeySize =3D KeySize >> 3; + AesCtx->KeySize =3D KeySize; + KeyWords =3D KeySize >> 2; + + // The first part of the expanded key is the input key. + for (Index =3D 0; Index < KeyWords; Index++) { + AesCtx->ExpEncKey[Index] =3D ReadUnaligned32 ( + (UINT32 *)(Key + (Index * sizeof (UINT3= 2))) + ); + } + + for (Index =3D 0; Index < sizeof (mRoundConstants); Index++) { + KeyIn =3D AesCtx->ExpEncKey + (Index * KeyWords); + KeyOut =3D KeyIn + KeyWords; + + KeyOut[0] =3D ArmAesSubWord (RRotU32 (KeyIn[KeyWords - 1], 8)); + KeyOut[0] ^=3D mRoundConstants[Index] ^ KeyIn[0]; + KeyOut[1] =3D KeyOut[0] ^ KeyIn[1]; + KeyOut[2] =3D KeyOut[1] ^ KeyIn[2]; + KeyOut[3] =3D KeyOut[2] ^ KeyIn[3]; + + if (KeySize =3D=3D AES_KEY_SIZE_192) { + if (Index >=3D 7) { + break; + } + + KeyOut[4] =3D KeyOut[3] ^ KeyIn[4]; + KeyOut[5] =3D KeyOut[4] ^ KeyIn[5]; + } else if (KeySize =3D=3D AES_KEY_SIZE_256) { + if (Index >=3D 6) { + break; + } + + KeyOut[4] =3D ArmAesSubWord (KeyOut[3]) ^ KeyIn[4]; + KeyOut[5] =3D KeyOut[4] ^ KeyIn[5]; + KeyOut[6] =3D KeyOut[5] ^ KeyIn[6]; + KeyOut[7] =3D KeyOut[6] ^ KeyIn[7]; + } + } + + /* + * Generate the decryption key for the Equivalent Inverse Cipher. + * First and last state of the expanded encryption key are copied + * to the expanded decryption key. + * The other ones are copied bottom up from the expanded encryption + * key and undergo an InvMixColumns(). + */ + InBlock =3D (AES_BLOCK *)AesCtx->ExpEncKey; + OutBlock =3D (AES_BLOCK *)AesCtx->ExpDecKey; + RevIndex =3D GetNumRounds (AesCtx); + + CopyMem (&OutBlock[0], &InBlock[RevIndex], sizeof (AES_BLOCK)); + for (Index =3D 1, RevIndex--; RevIndex > 0; Index++, RevIndex--) { + ArmAesInvert (OutBlock + Index, InBlock + RevIndex); + } + + CopyMem (&OutBlock[Index], &InBlock[0], sizeof (AES_BLOCK)); + + return RETURN_SUCCESS; +} diff --git a/ArmPkg/Library/ArmAesLib/ArmAesLib.h b/ArmPkg/Library/ArmAes= Lib/ArmAesLib.h new file mode 100644 index 000000000000..dd926491a816 --- /dev/null +++ b/ArmPkg/Library/ArmAesLib/ArmAesLib.h @@ -0,0 +1,96 @@ +/** @file + Arm AES Library + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - FIPS 197 November 26, 2001: + Specification for the ADVANCED ENCRYPTION STANDARD (AES) +**/ + +#ifndef ARM_AES_LIB_H_ +#define ARM_AES_LIB_H_ + +/* An AES block is 128-bits long and can be seen as a matrix of 4 * 4 by= tes. + */ +typedef struct AesBlock { + /// The AES block. + UINT8 Block[AES_BLOCK_SIZE]; +} AES_BLOCK; + +/** Encrypt an AES block. + + @param [in] ExpEncKey Expanded encryption key. An array of 32-bits w= ords + with the number of elements depending on the k= ey + size: + * 128-bits: 44 words + * 192-bits: 52 words + * 256-bits: 60 words + @param [in] Rounds Number of rounds (depending on the key size). + @param [in] InBlock Input Block. The block to cipher. + @param [out] OutBlock Output Block. The ciphered block. +**/ +VOID +ArmAesEncrypt ( + IN UINT32 CONST *ExpEncKey, + IN UINT32 Rounds, + IN UINT8 CONST *InBlock, + OUT UINT8 *OutBlock + ); + +/** Decrypt an AES 128-bits block. + + @param [in] ExpDecKey Expanded decryption key. An array of 32-bits w= ords + with the number of elements depending on the k= ey + size: + * 128-bits: 44 words + * 192-bits: 52 words + * 256-bits: 60 words + @param [in] Rounds Number of rounds (depending on the key size). + @param [in] InBlock Input Block. The block to de-cipher. + @param [out] OutBlock Output Block. The de-ciphered block. +**/ +VOID +ArmAesDecrypt ( + IN UINT32 CONST *ExpDecKey, + IN UINT32 Rounds, + IN UINT8 CONST *InBlock, + OUT UINT8 *OutBlock + ); + +/** Perform a SubWord() operation (applying AES Sbox) on a 32-bits word. + + The Arm AESE instruction performs the AddRoundKey(), ShiftRows() and + SubBytes() AES steps in this order. + + During key expansion, only SubBytes() should be performed, so: + - use a key of {0} so AddRoundKey() becomes an identity function; + - the dup instruction allows to have a matrix with identic rows, + so ShiftRows() has no effect. + + @param [in] InWord The 32-bits word to apply SubWord() on. + + @return SubWord(word). +**/ +UINT32 +ArmAesSubWord ( + IN UINT32 InWord + ); + +/** Perform a InvMixColumns() operation on an AES block (128-bits) using + the Arm AESIMC instruction. + + This is usefull to get decryption key for the Equivalent Inverse Ciphe= r. + + @param [in] InBlock Input block. + @param [out] OutBlock Output blocked. +**/ +VOID +ArmAesInvert ( + IN AES_BLOCK CONST *InBlock, + OUT AES_BLOCK *OutBlock + ); + +#endif // ARM_AES_LIB_H_ diff --git a/ArmPkg/Library/ArmAesLib/ArmAesLib.inf b/ArmPkg/Library/ArmA= esLib/ArmAesLib.inf new file mode 100644 index 000000000000..73c664a9f888 --- /dev/null +++ b/ArmPkg/Library/ArmAesLib/ArmAesLib.inf @@ -0,0 +1,34 @@ +## @file +# AES Library +# +# Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D ArmAesLib + FILE_GUID =3D 585599F7-DA62-44F5-BA20-3D50AEF638B4 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D BASE + LIBRARY_CLASS =3D AesLib + CONSTRUCTOR =3D AesLibConstructor + +[Sources] + ArmAesLib.c + ArmAesLib.h + +[Sources.ARM] + Arm/ArmAesLib.S + +[Sources.AARCH64] + AArch64/AArch64AesLib.S + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmLib + BaseLib --=20 2.25.1