public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "PierreGondois" <pierre.gondois@arm.com>
To: devel@edk2.groups.io
Cc: Sami Mujawar <sami.mujawar@arm.com>,
	Leif Lindholm <quic_llindhol@quicinc.com>,
	Ard Biesheuvel <ardb+tianocore@kernel.org>,
	Rebecca Cran <rebecca@bsdio.com>,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Edward Pickup <Edward.Pickup@arm.com>
Subject: [PATCH RESEND v1 7/7] ArmPkg/ArmAesLib: Add ArmAesLib
Date: Wed, 29 Jun 2022 21:13:55 +0200	[thread overview]
Message-ID: <20220629191355.2618844-8-Pierre.Gondois@arm.com> (raw)
In-Reply-To: <20220629191355.2618844-1-Pierre.Gondois@arm.com>

From: Pierre Gondois <Pierre.Gondois@arm.com>

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3970

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 <pierre.gondois@arm.com>
---
 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.<BR>
-# Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
+# Copyright (c) 2011 - 2022, Arm Limited. All rights reserved.<BR>
 # Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.<BR>
 # 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
 
   ArmPkg/Filesystem/SemihostFs/SemihostFs.inf
 
diff --git a/ArmPkg/Library/ArmAesLib/AArch64/AArch64AesLib.S b/ArmPkg/Library/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.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <AsmMacroIoLibV8.h>
+
+.arch_extension crypto
+
+// Generic notes:
+// - In AArch64, the AESE/AESD/AESMC/AESIMC instructions are using registers
+//   as <Vx>.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-bits words
+//                           with the number of elements depending on the 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 = 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 = 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-bits words
+//                           with the number of elements depending on the 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 = 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 = 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 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
+//   );
+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) using
+//     the Arm AESIMC instruction.
+//
+//   This is usefull to get decryption key for the Equivalent Inverse Cipher.
+//
+//   @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/ArmAesLib/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.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <AsmMacroIoLibV8.h>
+
+.fpu crypto-neon-fp-armv8
+
+// Generic notes:
+// - In Arm32, the AESE/AESD/AESMC/AESIMC instructions are using registers
+//   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-bits words
+//                           with the number of elements depending on the 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 = 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 = 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-bits words
+//                           with the number of elements depending on the 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 = 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 = 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 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
+//   );
+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) using
+//     the Arm AESIMC instruction.
+//
+//   This is usefull to get decryption key for the Equivalent Inverse Cipher.
+//
+//   @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/ArmAesLib/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.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Reference(s):
+   - FIPS 197 November 26, 2001:
+     Specification for the ADVANCED ENCRYPTION STANDARD (AES)
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/AesLib.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#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[] = {
+  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 == NULL)    ||
+      (InBlock == NULL)   ||
+      (OutBlock == NULL)  ||
+      (InBlock == OutBlock))
+  {
+    ASSERT (AesCtx != NULL);
+    ASSERT (InBlock != NULL);
+    ASSERT (OutBlock != NULL);
+    ASSERT (InBlock != 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 == NULL)  ||
+      (InBlock == NULL) ||
+      (OutBlock == NULL)  ||
+      (InBlock == OutBlock))
+  {
+    ASSERT (AesCtx != NULL);
+    ASSERT (InBlock != NULL);
+    ASSERT (OutBlock != NULL);
+    ASSERT (InBlock != 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|256.
+  @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 == NULL)                       ||
+      ((KeySize != 8 * AES_KEY_SIZE_128)  &&
+       (KeySize != 8 * AES_KEY_SIZE_192)  &&
+       (KeySize != 8 * AES_KEY_SIZE_256)) ||
+      (AesCtx == NULL))
+  {
+    ASSERT (Key != NULL);
+    ASSERT (
+      !((KeySize != 8 * AES_KEY_SIZE_128)   &&
+        (KeySize != 8 * AES_KEY_SIZE_192)    &&
+        (KeySize != 8 * AES_KEY_SIZE_256))
+      );
+    ASSERT (AesCtx != NULL);
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  // Internally, use bytes.
+  KeySize         = KeySize >> 3;
+  AesCtx->KeySize = KeySize;
+  KeyWords        = KeySize >> 2;
+
+  // The first part of the expanded key is the input key.
+  for (Index = 0; Index < KeyWords; Index++) {
+    AesCtx->ExpEncKey[Index] = ReadUnaligned32 (
+                                 (UINT32 *)(Key + (Index * sizeof (UINT32)))
+                                 );
+  }
+
+  for (Index = 0; Index < sizeof (mRoundConstants); Index++) {
+    KeyIn  = AesCtx->ExpEncKey + (Index * KeyWords);
+    KeyOut = KeyIn + KeyWords;
+
+    KeyOut[0]  = ArmAesSubWord (RRotU32 (KeyIn[KeyWords - 1], 8));
+    KeyOut[0] ^= mRoundConstants[Index] ^ KeyIn[0];
+    KeyOut[1]  = KeyOut[0] ^ KeyIn[1];
+    KeyOut[2]  = KeyOut[1] ^ KeyIn[2];
+    KeyOut[3]  = KeyOut[2] ^ KeyIn[3];
+
+    if (KeySize == AES_KEY_SIZE_192) {
+      if (Index >= 7) {
+        break;
+      }
+
+      KeyOut[4] = KeyOut[3] ^ KeyIn[4];
+      KeyOut[5] = KeyOut[4] ^ KeyIn[5];
+    } else if (KeySize == AES_KEY_SIZE_256) {
+      if (Index >= 6) {
+        break;
+      }
+
+      KeyOut[4] = ArmAesSubWord (KeyOut[3]) ^ KeyIn[4];
+      KeyOut[5] = KeyOut[4] ^ KeyIn[5];
+      KeyOut[6] = KeyOut[5] ^ KeyIn[6];
+      KeyOut[7] = 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  = (AES_BLOCK *)AesCtx->ExpEncKey;
+  OutBlock = (AES_BLOCK *)AesCtx->ExpDecKey;
+  RevIndex = GetNumRounds (AesCtx);
+
+  CopyMem (&OutBlock[0], &InBlock[RevIndex], sizeof (AES_BLOCK));
+  for (Index = 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/ArmAesLib/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.<BR>
+
+  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 bytes.
+ */
+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 words
+                          with the number of elements depending on the 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
+  );
+
+/** Decrypt an AES 128-bits block.
+
+  @param [in]  ExpDecKey  Expanded decryption key. An array of 32-bits words
+                          with the number of elements depending on the 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
+  );
+
+/** 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 Cipher.
+
+  @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/ArmAesLib/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.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION    = 0x0001001B
+  BASE_NAME      = ArmAesLib
+  FILE_GUID      = 585599F7-DA62-44F5-BA20-3D50AEF638B4
+  VERSION_STRING = 1.0
+  MODULE_TYPE    = BASE
+  LIBRARY_CLASS  = AesLib
+  CONSTRUCTOR    = 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
-- 
2.25.1


      parent reply	other threads:[~2022-06-29 19:14 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-29 19:13 [PATCH RESEND v1 0/7] Add AesLib and ArmAesLib PierreGondois
2022-06-29 19:13 ` [PATCH RESEND v1 1/7] ArmPkg: Update Armpkg.ci.yaml PierreGondois
2022-06-29 19:13 ` [PATCH RESEND v1 2/7] ArmPkg/ArmDisassemblerLib: Replace RotateRight() PierreGondois
2022-06-29 19:13 ` [PATCH RESEND v1 3/7] ArmPkg/ArmLib: Add ArmReadIdIsaR5() helper PierreGondois
2022-06-29 19:13 ` [PATCH RESEND v1 4/7] ArmPkg/ArmLib: Add ArmHasAesExt() PierreGondois
2022-06-29 19:13 ` [PATCH RESEND v1 5/7] MdePkg/AesLib: Definition for AES library class interface PierreGondois
2022-06-30  0:29   ` [edk2-devel] " Yao, Jiewen
2022-07-01  9:48     ` PierreGondois
2022-07-01 11:55       ` Yao, Jiewen
2022-07-01 13:58         ` PierreGondois
2022-07-01 14:40           ` Yao, Jiewen
2022-07-01 15:22             ` PierreGondois
2022-07-01 16:11               ` Yao, Jiewen
2022-07-04 13:16                 ` PierreGondois
2022-06-29 19:13 ` [PATCH RESEND v1 6/7] MdePkg/AesLib: Add NULL instance of AesLib PierreGondois
2022-06-29 19:13 ` PierreGondois [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220629191355.2618844-8-Pierre.Gondois@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox