]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IpSecDxe/IpSecCryptIo.c
Hash2 driver to [Components.IA32, Components.X64, Components.IPF] section.
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecCryptIo.c
index 7011f98b060a502fdb2f93c6b69e1322e48b37d5..8396c5900391651e435f42e4b9188ac228311a1e 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 /** @file\r
-  Common operation for Security.\r
+  Common interfaces to call Security library.\r
 \r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
 \r
 #include "IpSecCryptIo.h"\r
 //\r
 \r
 #include "IpSecCryptIo.h"\r
 //\r
-// Alogrithm's informations for the Encrypt/Decrpt Alogrithm.\r
+// The informations for the supported Encrypt/Decrpt Alogrithm.\r
 //\r
 //\r
-ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
-  {EFI_IPSEC_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},\r
-  {(UINT8)-1,           0, 0, 0, NULL, NULL, NULL, NULL}\r
+GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
+  {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},\r
+  {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL},  \r
+  {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},\r
+  {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}\r
 };\r
 };\r
+\r
+//\r
+// The informations for the supported Authentication algorithm\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r
+  {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+  {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+  {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}\r
+};\r
+\r
 //\r
 //\r
-// Alogrithm's informations for the Authentication algorithm\r
+// The information for the supported Hash aglorithm\r
 //\r
 //\r
-AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r
-  {EFI_IPSEC_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
-  {EFI_IPSEC_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
-  {(UINT8)-1,           0, 0, 0, NULL, NULL, NULL, NULL}\r
+GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {\r
+  {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+  {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+  {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}\r
 };\r
 \r
 };\r
 \r
+BOOLEAN  mInitialRandomSeed = FALSE;\r
 \r
 /**\r
 \r
 /**\r
-  Get the block size of encrypt alogrithm. The block size is based on the algorithm used.\r
+  Get the block size of specified encryption alogrithm.\r
 \r
 \r
-  @param[in]  AlgorithmId          The encrypt algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
 \r
   @return The value of block size.\r
 \r
 \r
   @return The value of block size.\r
 \r
@@ -48,9 +61,6 @@ IpSecGetEncryptBlockSize (
 \r
   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
 \r
   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
-      //\r
-      // The BlockSize is same with IvSize.\r
-      //\r
       return mIpsecEncryptAlgorithmList[Index].BlockSize;\r
     }\r
   }\r
       return mIpsecEncryptAlgorithmList[Index].BlockSize;\r
     }\r
   }\r
@@ -59,9 +69,33 @@ IpSecGetEncryptBlockSize (
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
-  Get the IV size of encrypt alogrithm. The IV size is based on the algorithm used.\r
+  Get the key length of the specified encryption alogrithm.\r
+\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return The value of key length.\r
+\r
+**/\r
+UINTN\r
+IpSecGetEncryptKeyLength (\r
+  IN UINT8   AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+\r
+  for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
+      return mIpsecEncryptAlgorithmList[Index].KeyLength;\r
+    }\r
+  }\r
+\r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Get the IV size of the specified encryption alogrithm.\r
 \r
 \r
-  @param[in]  AlgorithmId          The encrypt algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
 \r
   @return The value of IV size.\r
 \r
 \r
   @return The value of IV size.\r
 \r
@@ -75,9 +109,6 @@ IpSecGetEncryptIvLength (
 \r
   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
 \r
   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
-      //\r
-      // The BlockSize is same with IvSize.\r
-      //\r
       return mIpsecEncryptAlgorithmList[Index].IvLength;\r
     }\r
   }\r
       return mIpsecEncryptAlgorithmList[Index].IvLength;\r
     }\r
   }\r
@@ -86,24 +117,53 @@ IpSecGetEncryptIvLength (
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
-  Get the ICV size of Authenticaion alogrithm. The ICV size is based on the algorithm used.\r
+  Get the HMAC digest length by the specified Algorithm ID.\r
 \r
 \r
-  @param[in]  AuthAlgorithmId          The Authentication algorithm ID.\r
+  @param[in]  AlgorithmId  The specified Alogrithm ID.\r
+\r
+  @return The digest length of the specified Authentication Algorithm ID.\r
+\r
+**/\r
+UINTN\r
+IpSecGetHmacDigestLength (\r
+  IN UINT8  AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+\r
+  for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {\r
+      //\r
+      // Return the Digest Length of the Algorithm.\r
+      //\r
+      return mIpsecAuthAlgorithmList[Index].DigestLength;\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Get the ICV size of the specified Authenticaion alogrithm.\r
+\r
+  @param[in]  AlgorithmId          The Authentication algorithm ID.\r
 \r
   @return The value of ICV size.\r
 \r
 **/\r
 UINTN\r
 IpSecGetIcvLength (\r
 \r
   @return The value of ICV size.\r
 \r
 **/\r
 UINTN\r
 IpSecGetIcvLength (\r
-  IN UINT8  AuthAlgorithmId\r
+  IN UINT8  AlgorithmId\r
   )\r
 {\r
   UINT8 Index;\r
   )\r
 {\r
   UINT8 Index;\r
+\r
   for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
   for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
-    if (AuthAlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
+    if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
       return mIpsecAuthAlgorithmList[Index].IcvLength;\r
     }\r
   }\r
       return mIpsecAuthAlgorithmList[Index].IcvLength;\r
     }\r
   }\r
+\r
   return (UINTN) -1;\r
 }\r
 \r
   return (UINTN) -1;\r
 }\r
 \r
@@ -112,7 +172,7 @@ IpSecGetIcvLength (
   IV and return EFI_SUCCESS.\r
 \r
   @param[in]  IvBuffer  The pointer of the IV buffer.\r
   IV and return EFI_SUCCESS.\r
 \r
   @param[in]  IvBuffer  The pointer of the IV buffer.\r
-  @param[in]  IvSize    The IV size.\r
+  @param[in]  IvSize    The IV size in bytes.\r
 \r
   @retval     EFI_SUCCESS  Create a random data for IV.\r
 \r
 \r
   @retval     EFI_SUCCESS  Create a random data for IV.\r
 \r
@@ -124,10 +184,835 @@ IpSecGenerateIv (
   )\r
 {\r
   if (IvSize != 0) {\r
   )\r
 {\r
   if (IvSize != 0) {\r
+    return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get index of the specified encryption alogrithm from the mIpsecEncryptAlgorithemList.\r
+\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return the index.\r
+  \r
+**/\r
+UINTN\r
+IpSecGetIndexFromEncList (\r
+  IN UINT8   AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+  \r
+  for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
+      return Index;\r
+    }\r
+  }\r
+  \r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Get index of the specified encryption alogrithm from the mIpsecAuthAlgorithemList.\r
+\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return the index.\r
+  \r
+**/\r
+UINTN\r
+IpSecGetIndexFromAuthList (\r
+  IN UINT8   AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+  \r
+  for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
+      //\r
+      // The BlockSize is same with IvSize.\r
+      //\r
+      return Index;\r
+    }\r
+  }\r
+  \r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Encrypt the buffer.\r
+\r
+  This function calls relevant encryption interface from CryptoLib according to\r
+  the input alogrithm ID. The InData should be multiple of block size. This function\r
+  doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+  same with the block size. The block size is different from the different algorithm.\r
+\r
+  @param[in]       AlgorithmId    The Alogrithem identification defined in RFC.\r
+  @param[in]       Key            Pointer to the buffer containing encrypting key.\r
+  @param[in]       KeyBits        The length of the key in bits.\r
+  @param[in]       Ivec           Point to the buffer containning the Initializeion\r
+                                  Vector (IV) data.\r
+  @param[in]       InData         Point to the buffer containing the data to be\r
+                                  encrypted.\r
+  @param[in]       InDataLength   The length of InData in Bytes.\r
+  @param[out]      OutData        Point to the buffer that receives the encryption\r
+                                  output.\r
+\r
+  @retval EFI_UNSUPPORTED       The input Algorithm is not supported.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoEncrypt (\r
+  IN CONST UINT8      AlgorithmId,\r
+  IN CONST UINT8      *Key,\r
+  IN CONST UINTN      KeyBits,\r
+  IN CONST UINT8      *Ivec, OPTIONAL\r
+  IN       UINT8      *InData,\r
+  IN       UINTN      InDataLength,\r
+     OUT   UINT8      *OutData\r
+  )\r
+{  \r
+  UINTN         Index;\r
+  UINTN         ContextSize;\r
+  UINT8         *Context;\r
+  EFI_STATUS    Status;\r
+  \r
+  Status = EFI_UNSUPPORTED;\r
+  \r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_EALG_NULL:\r
+  case IKE_EALG_NONE:\r
+    CopyMem (OutData, InData, InDataLength);\r
+    return EFI_SUCCESS;\r
+\r
+  case IKE_EALG_3DESCBC:\r
+  case IKE_EALG_AESCBC:\r
+    Index = IpSecGetIndexFromEncList (AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();\r
+    Context     = AllocateZeroPool (ContextSize);\r
+\r
+    if (Context == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Initiate Context\r
+    //\r
+    if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r
+      if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {\r
+        Status = EFI_SUCCESS;\r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    return Status;\r
+\r
+  }\r
+\r
+  if (Context != NULL) {\r
+    FreePool (Context);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Decrypts the buffer.\r
+\r
+  This function calls relevant Decryption interface from CryptoLib according to\r
+  the input alogrithm ID. The InData should be multiple of block size. This function\r
+  doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+  same with the block size. The block size is different from the different algorithm.\r
+\r
+  @param[in]       AlgorithmId    The Alogrithem identification defined in RFC.\r
+  @param[in]       Key            Pointer to the buffer containing encrypting key.\r
+  @param[in]       KeyBits        The length of the key in bits.\r
+  @param[in]       Ivec           Point to the buffer containning the Initializeion\r
+                                  Vector (IV) data.\r
+  @param[in]       InData         Point to the buffer containing the data to be\r
+                                  decrypted.\r
+  @param[in]       InDataLength   The length of InData in Bytes.\r
+  @param[out]      OutData        Pointer to the buffer that receives the decryption\r
+                                  output.\r
+\r
+  @retval EFI_UNSUPPORTED       The input Algorithm is not supported.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDecrypt (\r
+  IN CONST UINT8      AlgorithmId,\r
+  IN CONST UINT8      *Key,\r
+  IN CONST UINTN      KeyBits,\r
+  IN CONST UINT8      *Ivec, OPTIONAL\r
+  IN       UINT8      *InData,\r
+  IN       UINTN      InDataLength,\r
+     OUT   UINT8      *OutData\r
+  )\r
+{  \r
+  UINTN         Index;\r
+  UINTN         ContextSize;\r
+  UINT8         *Context;\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_EALG_NULL:\r
+  case IKE_EALG_NONE:\r
+    CopyMem (OutData, InData, InDataLength);\r
+    return EFI_SUCCESS;\r
+\r
+  case IKE_EALG_3DESCBC:\r
+  case IKE_EALG_AESCBC:\r
+    Index = IpSecGetIndexFromEncList(AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();\r
+    Context     = AllocateZeroPool (ContextSize);\r
+    if (Context == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Initiate Context\r
+    //\r
+    if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r
+      if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {\r
+        Status = EFI_SUCCESS;      \r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    return Status;\r
+  }\r
+\r
+  if (Context != NULL) {\r
+    FreePool (Context);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Digests the Payload with key and store the result into the OutData.\r
+\r
+  This function calls relevant Hmac interface from CryptoLib according to\r
+  the input alogrithm ID. It computes all datas from InDataFragment and output\r
+  the result into the OutData buffer. If the OutDataSize is larger than the related\r
+  HMAC alogrithm output size, return EFI_INVALID_PARAMETER.\r
+  \r
+  @param[in]      AlgorithmId     The authentication Identification.\r
+  @param[in]      Key             Pointer of the authentication key.\r
+  @param[in]      KeyLength       The length of the Key in bytes.\r
+  @param[in]      InDataFragment  The list contains all data to be authenticated.\r
+  @param[in]      FragmentCount   The size of the InDataFragment.\r
+  @param[out]     OutData         For in, the buffer to receive the output data.\r
+                                  For out, the buffer contains the authenticated data.\r
+  @param[in]      OutDataSize     The size of the buffer of OutData.\r
+\r
+  @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.\r
+  @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.\r
+  @retval EFI_SUCCESS           Authenticate the payload successfully.\r
+  @retval otherwise             Authentication of the payload fails.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHmac (\r
+  IN     CONST UINT8              AlgorithmId,\r
+  IN     CONST UINT8              *Key,\r
+  IN           UINTN              KeyLength,\r
+  IN           HASH_DATA_FRAGMENT *InDataFragment,\r
+  IN           UINTN              FragmentCount,\r
+     OUT       UINT8              *OutData,\r
+  IN           UINTN              OutDataSize\r
+  )\r
+{\r
+  UINTN        ContextSize;\r
+  UINTN        Index;\r
+  UINT8        FragmentIndex;\r
+  UINT8        *HashContext;\r
+  EFI_STATUS   Status;\r
+  UINT8        *OutHashData;\r
+  UINTN        OutHashSize;\r
+\r
+  Status      = EFI_UNSUPPORTED;\r
+  OutHashData = NULL;\r
+\r
+  OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
+  //\r
+  // If the expected hash data size is larger than the related Hash algorithm\r
+  // output length, return EFI_INVALID_PARAMETER.\r
+  //\r
+  if (OutDataSize > OutHashSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  OutHashData = AllocatePool (OutHashSize);\r
+\r
+  if (OutHashData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_AALG_NONE :\r
+  case IKE_AALG_NULL :\r
+    return EFI_SUCCESS;\r
+\r
+  case IKE_AALG_SHA1HMAC:\r
+    Index = IpSecGetIndexFromAuthList (AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get Context Size\r
     //\r
     //\r
-    //TODO: return CryptGenerateRandom (IvBuffer, IvSize);\r
+    ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();\r
+    HashContext = AllocateZeroPool (ContextSize);\r
+\r
+    if (HashContext == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Exit;\r
+    }\r
+\r
     //\r
     //\r
+    // Initiate HMAC context and hash the input data.\r
+    //\r
+    if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {\r
+      for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r
+        if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (\r
+                HashContext,\r
+                InDataFragment[FragmentIndex].Data,\r
+                InDataFragment[FragmentIndex].DataSize\r
+                )\r
+          ) {\r
+          goto Exit;\r
+        }\r
+      }\r
+      if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {\r
+        //\r
+        // In some cases, like the Icv computing, the Icv size might be less than\r
+        // the key length size, so copy the part of hash data to the OutData.\r
+        //\r
+        CopyMem (OutData, OutHashData, OutDataSize);\r
+        Status = EFI_SUCCESS;\r
+      }\r
+\r
+      goto Exit;\r
+    }    \r
+      \r
+  default:\r
+    return Status;\r
+  }\r
+\r
+Exit:\r
+  if (HashContext != NULL) {\r
+    FreePool (HashContext);\r
+  }\r
+  if (OutHashData != NULL) {\r
+    FreePool (OutHashData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Digests the Payload and store the result into the OutData.\r
+\r
+  This function calls relevant Hash interface from CryptoLib according to\r
+  the input alogrithm ID. It computes all datas from InDataFragment and output\r
+  the result into the OutData buffer. If the OutDataSize is larger than the related\r
+  Hash alogrithm output size, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in]      AlgorithmId     The authentication Identification.\r
+  @param[in]      InDataFragment  A list contains all data to be authenticated.\r
+  @param[in]      FragmentCount   The size of the InDataFragment.\r
+  @param[out]     OutData         For in, the buffer to receive the output data.\r
+                                  For out, the buffer contains the authenticated data.\r
+  @param[in]      OutDataSize     The size of the buffer of OutData.\r
+\r
+  @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.\r
+  @retval EFI_SUCCESS           Authenticated the payload successfully.\r
+  @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash\r
+                                algorithm could handle.\r
+  @retval otherwise             Authentication of the payload failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHash (\r
+  IN     CONST UINT8              AlgorithmId,\r
+  IN           HASH_DATA_FRAGMENT *InDataFragment,\r
+  IN           UINTN              FragmentCount,\r
+     OUT       UINT8              *OutData,\r
+  IN           UINTN              OutDataSize\r
+  )\r
+{\r
+  UINTN        ContextSize;\r
+  UINTN        Index;\r
+  UINT8        FragmentIndex;\r
+  UINT8        *HashContext;\r
+  EFI_STATUS   Status;\r
+  UINT8        *OutHashData;\r
+  UINTN        OutHashSize;\r
+\r
+  Status      = EFI_UNSUPPORTED;\r
+  OutHashData = NULL;\r
+  \r
+  OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
+  //\r
+  // If the expected hash data size is larger than the related Hash algorithm\r
+  // output length, return EFI_INVALID_PARAMETER.  \r
+  //\r
+  if (OutDataSize > OutHashSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  OutHashData = AllocatePool (OutHashSize);\r
+  if (OutHashData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_AALG_NONE:\r
+  case IKE_AALG_NULL:\r
     return EFI_SUCCESS;\r
     return EFI_SUCCESS;\r
+\r
+  case IKE_AALG_SHA1HMAC:\r
+    Index = IpSecGetIndexFromAuthList (AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();\r
+    HashContext = AllocateZeroPool (ContextSize);\r
+    if (HashContext == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Exit;\r
+    }\r
+    \r
+    //\r
+    // Initiate Hash context and hash the input data.\r
+    //\r
+    if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {\r
+      for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r
+        if (!mIpsecHashAlgorithmList[Index].HashUpdate (\r
+                HashContext,\r
+                InDataFragment[FragmentIndex].Data,\r
+                InDataFragment[FragmentIndex].DataSize\r
+                )\r
+          ) {\r
+          goto Exit;\r
+        }\r
+      }\r
+      if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {\r
+        //\r
+        // In some cases, like the Icv computing, the Icv size might be less than\r
+        // the key length size, so copy the part of hash data to the OutData.\r
+        //\r
+        CopyMem (OutData, OutHashData, OutDataSize);            \r
+        Status = EFI_SUCCESS;\r
+      }\r
+      \r
+      goto Exit;        \r
+    }    \r
+    \r
+  default:\r
+    return Status;\r
+  }\r
+\r
+Exit:\r
+  if (HashContext != NULL) {\r
+    FreePool (HashContext);\r
+  }\r
+  if (OutHashData != NULL) {\r
+    FreePool (OutHashData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates the Diffie-Hellman public key.\r
+\r
+  This function first initiate a DHContext, then call the DhSetParameter() to set\r
+  the prime and primelenght, at end call the DhGenerateKey() to generates random\r
+  secret exponent, and computes the public key. The output returned via parameter\r
+  PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey\r
+  buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned\r
+  and PublicKeySize is set to the required buffer size to obtain the public key.\r
+\r
+  @param[in, out] DhContext       Pointer to the DH context.\r
+  @param[in]      Generator       Vlaue of generator.\r
+  @param[in]      PrimeLength     Length in bits of prime to be generated.\r
+  @param[in]      Prime           Pointer to the buffer to receive the generated\r
+                                  prime number.\r
+  @param[out]     PublicKey       Pointer to the buffer to receive generated public key.\r
+  @param[in, out] PublicKeySize   For in, the size of PublicKey buffer in bytes.\r
+                                  For out, the size of data returned in PublicKey\r
+                                  buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS             The operation perfoms successfully.\r
+  @retval Otherwise               The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhGetPublicKey (\r
+  IN OUT   UINT8  **DhContext,\r
+  IN       UINTN  Generator,\r
+  IN       UINTN  PrimeLength,\r
+  IN CONST UINT8  *Prime,\r
+     OUT   UINT8  *PublicKey,\r
+  IN OUT   UINTN  *PublicKeySize\r
+  ) \r
+{\r
+  EFI_STATUS   Status;\r
+  \r
+  *DhContext = DhNew ();\r
+  ASSERT (*DhContext != NULL);\r
+  if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+\r
+  if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+  return EFI_SUCCESS;\r
+\r
+Exit:\r
+  if (*DhContext != NULL) {\r
+    DhFree (*DhContext);\r
+    DhContext = NULL;\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates exchanged common key.\r
+\r
+  Given peer's public key, this function computes the exchanged common key, based\r
+  on its own context including value of prime modulus and random secret exponent.\r
+\r
+  @param[in, out] DhContext         Pointer to the DH context.\r
+  @param[in]      PeerPublicKey     Pointer to the peer's Public Key.\r
+  @param[in]      PeerPublicKeySize Size of peer's public key in bytes.\r
+  @param[out]     Key               Pointer to the buffer to receive generated key.\r
+  @param[in, out] KeySize           For in, the size of Key buffer in bytes.\r
+                                    For out, the size of data returned in Key\r
+                                    buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval Otherwise                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhComputeKey (\r
+  IN   OUT   UINT8  *DhContext,     \r
+  IN   CONST UINT8  *PeerPublicKey,\r
+  IN         UINTN  PeerPublicKeySize,\r
+       OUT   UINT8  *Key,\r
+  IN   OUT   UINTN  *KeySize\r
+  )\r
+{\r
+  if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in, out]     DhContext         Pointer to the DH context to be freed.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval EFI_INVALID_PARAMETER    The DhContext is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoFreeDh (\r
+  IN   OUT   UINT8  **DhContext\r
+  )\r
+{ \r
+  if (*DhContext == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
   }\r
+\r
+  DhFree (*DhContext);\r
   return EFI_SUCCESS;\r
 }\r
   return EFI_SUCCESS;\r
 }\r
+\r
+/**\r
+  Generates random numbers of specified size.\r
+\r
+  If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.\r
+\r
+  @param[out]  OutBuffer        Pointer to buffer to receive random value.\r
+  @param[in]   Bytes            Size of randome bytes to generate.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval Otherwise                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGenerateRandomBytes (\r
+  OUT UINT8*    OutBuffer,\r
+  IN  UINTN     Bytes\r
+  )\r
+{\r
+  if (!mInitialRandomSeed) {\r
+    RandomSeed (NULL, 0);\r
+    mInitialRandomSeed = TRUE;\r
+  }\r
+  if (RandomBytes (OutBuffer, Bytes)) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+}\r
+\r
+/**\r
+  Authenticate data with the certificate.\r
+\r
+  @param[in]      InData          Pointer to the Data to be signed.\r
+  @param[in]      InDataSize      InData size in bytes.\r
+  @param[in]      PrivateKey      Pointer to the  private key.\r
+  @param[in]      PrivateKeySize  The size of Private Key in bytes.\r
+  @param[in]      KeyPassWord     Pointer to the password for retrieving private key.\r
+  @param[in]      KeyPwdSize      The size of Key Password in bytes.\r
+  @param[out]     OutData         The pointer to the signed data.\r
+  @param[in, out] OutDataSize     Pointer to contain the size of out data.\r
\r
+**/\r
+VOID\r
+IpSecCryptoIoAuthDataWithCertificate (\r
+  IN     UINT8   *InData,\r
+  IN     UINTN   InDataSize,\r
+  IN     UINT8   *PrivateKey,\r
+  IN     UINTN   PrivateKeySize,\r
+  IN     UINT8   *KeyPassWord,\r
+  IN     UINTN   KeyPwdSize,\r
+     OUT UINT8   **OutData,\r
+  IN OUT UINTN   *OutDataSize\r
+  )\r
+{\r
+  UINT8         *RsaContext;\r
+  UINT8         *Signature;\r
+  UINTN         SigSize;\r
+   \r
+  SigSize   = 0;\r
+  RsaContext = NULL;\r
+\r
+  //\r
+  // Retrieve RSA Private Key from password-protected PEM data\r
+  //\r
+  RsaGetPrivateKeyFromPem (\r
+    (CONST UINT8 *)PrivateKey,\r
+    PrivateKeySize,\r
+    (CONST CHAR8 *)KeyPassWord,\r
+    (VOID **) &RsaContext\r
+    );\r
+  if (RsaContext == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Sign data\r
+  //\r
+  Signature = NULL;  \r
+  if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {\r
+    Signature = AllocateZeroPool (SigSize);\r
+  } else {\r
+    return;\r
+  } \r
+\r
+  RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);\r
+\r
+  *OutData     = Signature;\r
+  *OutDataSize = SigSize;\r
+\r
+  if (RsaContext != NULL) {\r
+    RsaFree (RsaContext);\r
+  }\r
+}\r
+\r
+/**\r
+  Verify the singed data with the public key which is contained in a certificate.\r
+\r
+  @param[in]     InCert          Pointer to the Certificate which contains the\r
+                                 public key.\r
+  @param[in]     CertLen         The size of Certificate in bytes.\r
+  @param[in]     InCa            Pointer to the CA certificate\r
+  @param[in]     CaLen           The size of CA certificate in bytes.\r
+  @param[in]     InData          Pointer to octect message hash to be checked.\r
+  @param[in]     InDataSize      Size of the message hash in bytes.\r
+  @param[in]     Singnature      The pointer to the RSA PKCS1-V1_5 signature to be verifed.\r
+  @param[in]     SigSize         Size of signature in bytes.\r
+\r
+  @retval  TRUE   Valid signature encoded in PKCS1-v1_5.\r
+  @retval  FALSE  Invalid signature or invalid RSA context.\r
\r
+**/\r
+BOOLEAN\r
+IpSecCryptoIoVerifySignDataByCertificate (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertLen,\r
+  IN     UINT8   *InCa,\r
+  IN     UINTN   CaLen,\r
+  IN     UINT8   *InData,\r
+  IN     UINTN   InDataSize,\r
+  IN     UINT8   *Singnature,\r
+  IN     UINTN   SigSize\r
+  )\r
+{\r
+  UINT8         *RsaContext;\r
+  BOOLEAN       Status;\r
+\r
+  //\r
+  // Create the RSA Context\r
+  //\r
+  RsaContext = RsaNew ();\r
+  if (RsaContext == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Verify the validity of X509 Certificate\r
+  //\r
+  if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Retrieve the RSA public Key from Certificate\r
+  //\r
+  RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);\r
\r
+  //\r
+  // Verify data\r
+  //\r
+  Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);\r
+\r
+  if (RsaContext != NULL) {\r
+    RsaFree (RsaContext);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the RSA Public Key from one X509 certificate (DER format only).\r
+\r
+  @param[in]     InCert            Pointer to the certificate.\r
+  @param[in]     CertLen           The size of the certificate in bytes.\r
+  @param[out]    PublicKey         Pointer to the retrieved public key.\r
+  @param[out]    PublicKeyLen      Size of Public Key in bytes.\r
+\r
+  @retval  EFI_SUCCESS            Successfully get the public Key.\r
+  @retval  EFI_INVALID_PARAMETER  The certificate is malformed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetPublicKeyFromCert (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertLen,\r
+  OUT    UINT8   **PublicKey,\r
+  OUT    UINTN   *PublicKeyLen\r
+  )\r
+{\r
+  UINT8         *RsaContext;\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Create the RSA Context\r
+  //\r
+  RsaContext = RsaNew ();\r
+\r
+  //\r
+  // Retrieve the RSA public key from CA Certificate\r
+  //\r
+  if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto EXIT;\r
+  }\r
+\r
+  *PublicKeyLen = 0;\r
\r
+  RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);\r
\r
+  *PublicKey = AllocateZeroPool (*PublicKeyLen);\r
+  ASSERT (*PublicKey != NULL);\r
+\r
+  if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+EXIT:\r
+  if (RsaContext != NULL) {\r
+    RsaFree (RsaContext);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the subject name from one X509 certificate (DER format only).\r
+\r
+  @param[in]     InCert            Pointer to the X509 certificate.\r
+  @param[in]     CertSize          The size of the X509 certificate in bytes.\r
+  @param[out]    CertSubject       Pointer to the retrieved certificate subject.\r
+  @param[out]    SubjectSize       The size of Certificate Subject in bytes.\r
+  \r
+  @retval  EFI_SUCCESS            Retrieved the certificate subject successfully.\r
+  @retval  EFI_INVALID_PARAMETER  The certificate is malformed.\r
\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetSubjectFromCert (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertSize,\r
+  OUT    UINT8   **CertSubject,\r
+  OUT    UINTN   *SubjectSize\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  *SubjectSize = 0;\r
+  X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);\r
+\r
+  *CertSubject = AllocateZeroPool (*SubjectSize);\r
+  if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r