]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IpSecDxe/IpSecCryptIo.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecCryptIo.c
index 7011f98b060a502fdb2f93c6b69e1322e48b37d5..54607692aaecf99754c624b77bc93d3db9f89251 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
-  Common operation for Security.\r
+  Common interfaces to call Security library.\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2011, 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
 #include "IpSecCryptIo.h"\r
 //\r
-// Alogrithm's informations for the Encrypt/Decrpt Alogrithm.\r
+// The informations for the supported Encrypt/Decrpt Alogrithm.\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
+// 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
-// Alogrithm's informations for the Authentication algorithm\r
+// The information for the supported Hash aglorithm\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
+BOOLEAN  mInitialRandomSeed = FALSE;\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
-  @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
@@ -48,9 +61,6 @@ IpSecGetEncryptBlockSize (
 \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
@@ -59,9 +69,33 @@ IpSecGetEncryptBlockSize (
 }\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
-  @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
@@ -75,9 +109,6 @@ IpSecGetEncryptIvLength (
 \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
@@ -86,24 +117,53 @@ IpSecGetEncryptIvLength (
 }\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
-  @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
-  IN UINT8  AuthAlgorithmId\r
+  IN UINT8  AlgorithmId\r
   )\r
 {\r
   UINT8 Index;\r
+\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
+\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
-  @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
@@ -124,10 +184,833 @@ IpSecGenerateIv (
   )\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
-    //TODO: return CryptGenerateRandom (IvBuffer, IvSize);\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
+    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
+    // 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
+\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
+  DhFree (*DhContext);\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
+  //\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