geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bben...@apache.org
Subject [geode-native] branch develop updated: Revert "GEODE-7625: Remove broken Diffie-Hellman code"
Date Tue, 07 Jan 2020 23:06:47 GMT
This is an automated email from the ASF dual-hosted git repository.

bbender pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-native.git


The following commit(s) were added to refs/heads/develop by this push:
     new 6b46256  Revert "GEODE-7625: Remove broken Diffie-Hellman code"
6b46256 is described below

commit 6b46256dd03d5406f19c8cb465df03b61a30fb8a
Author: Blake Bender <bbender@pivotal.io>
AuthorDate: Tue Jan 7 15:04:55 2020 -0800

    Revert "GEODE-7625: Remove broken Diffie-Hellman code"
    
    This reverts commit de672d7faded5b17c8c22ecabaa6aaf3deab24cb.
    - Change somehow (???) broke Ubuntu builds of cryptoimpl library.  Looks like something isn't linking in SSL library like it should
    - reverting back to known good state for now, since it'll take a little while to investigate breakage
---
 CMakeLists.txt                                     |   1 +
 clicache/integration-test/test.bat.in              |   2 +
 cppcache/include/geode/SystemProperties.hpp        |  15 +-
 cppcache/integration-test/CMakeLists.txt           |   4 +-
 cppcache/integration-test/test.bat.in              |   1 +
 cppcache/integration-test/test.sh.in               |   1 +
 .../integration-test/testThinClientSecurityDH.cpp  | 471 ++++++++++++++
 .../testThinClientSecurityDH_MU.cpp                | 503 +++++++++++++++
 cppcache/integration/test/CMakeLists.txt           |   2 +-
 cppcache/src/DiffieHellman.cpp                     | 198 ++++++
 cppcache/src/DiffieHellman.hpp                     | 109 ++++
 cppcache/src/DistributedSystem.hpp                 |   1 +
 cppcache/src/DistributedSystemImpl.cpp             |   5 +-
 cppcache/src/DistributedSystemImpl.hpp             |   2 +
 cppcache/src/SystemProperties.cpp                  |   6 +-
 cppcache/src/TcrConnection.cpp                     | 144 ++++-
 cppcache/src/TcrConnection.hpp                     |  23 +
 cppcache/src/TcrMessage.cpp                        |  44 +-
 cppcache/src/TcrMessage.hpp                        |   4 +-
 cppcache/src/ThinClientBaseDM.cpp                  |   8 +-
 cryptoimpl/CMakeLists.txt                          |   2 +
 cryptoimpl/DHImpl.cpp                              | 713 +++++++++++++++++++++
 cryptoimpl/DHImpl.hpp                              | 100 +++
 {templates/security => dhimpl}/CMakeLists.txt      |  21 +-
 dhimpl/DHImpl.cpp                                  | 612 ++++++++++++++++++
 dhimpl/DHImpl.hpp                                  |  69 ++
 .../configuring/sysprops.html.md.erb               |   2 +-
 .../security/security-systemprops.html.md.erb      |   2 +-
 .../configuring/sysprops.html.md.erb               |   2 +-
 .../security/security-systemprops.html.md.erb      |   2 +-
 templates/security/CMakeLists.txt                  |   2 +
 templates/security/PkcsAuthInit.cpp                | 192 ++++++
 templates/security/PkcsAuthInit.hpp                |  96 +++
 tests/cli/CMakeLists.txt                           |   1 +
 tests/cli/NewFwkLib/CacheServer.cs                 |  53 ++
 tests/cli/NewFwkLib/NewFwkLib.csproj.in            |   5 +
 tests/cli/PkcsWrapper/CMakeLists.txt               |  57 ++
 tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp           |  47 ++
 tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp           |  65 ++
 tests/cli/SecurityUtil/CredentialGeneratorN.cs     |   2 +
 tests/cli/SecurityUtil/SecurityUtil.csproj.in      |   5 +
 .../SecurityUtil/XmlAuthzCredentialGeneratorN.cs   |  12 +
 tests/cpp/security/CMakeLists.txt                  |   2 +
 tests/cpp/security/PkcsAuthInit.cpp                | 220 +++++++
 tests/cpp/security/PkcsAuthInit.hpp                | 100 +++
 45 files changed, 3862 insertions(+), 66 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf9c5e4..c1e6b38 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -366,6 +366,7 @@ add_subdirectory(dependencies)
 add_subdirectory(openssl-compat)
 add_subdirectory(cppcache)
 add_subdirectory(cryptoimpl)
+add_subdirectory(dhimpl)
 add_subdirectory(sqliteimpl)
 add_subdirectory(templates/security)
 add_subdirectory(docs/api)
diff --git a/clicache/integration-test/test.bat.in b/clicache/integration-test/test.bat.in
index 87874b1..5c358c4 100644
--- a/clicache/integration-test/test.bat.in
+++ b/clicache/integration-test/test.bat.in
@@ -22,7 +22,9 @@ set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:framework>>;%PATH%
 set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:testobject>>;%PATH%
 set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:SqLiteImpl>>;%PATH%
 set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:cryptoImpl>>;%PATH%
+set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:DHImpl>>;%PATH%
 set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:securityImpl>>;%PATH%
+set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:PkcsWrapper>>;%PATH%
 set PATH=$<JOIN:$<SHELL_PATH:${PATH}>,;>;%PATH%
 
 set PATH=c:\Program Files (x86)\Nunit 2.6.4\bin;%PATH%
diff --git a/cppcache/include/geode/SystemProperties.hpp b/cppcache/include/geode/SystemProperties.hpp
index ab4963e..f00d6aa 100644
--- a/cppcache/include/geode/SystemProperties.hpp
+++ b/cppcache/include/geode/SystemProperties.hpp
@@ -283,12 +283,7 @@ class APACHE_GEODE_EXPORT SystemProperties {
     m_onClientDisconnectClearPdxTypeIds = set;
   }
 
-  /**
-   * @return Empty string
-   * @deprecated Diffie-Hellman based credentials encryption is not supported.
-   */
-  _GEODE_DEPRECATED_(
-      "Diffie-Hellman based credentials encryption is not supported.")
+  /** Return the security Diffie-Hellman secret key algorithm */
   const std::string& securityClientDhAlgo() const {
     return m_securityClientDhAlgo;
   }
@@ -313,12 +308,10 @@ class APACHE_GEODE_EXPORT SystemProperties {
   }
 
   /**
-   * @deprecated Diffie-Hellman based credentials encryption is not supported.
-   * @return false.
+   * Check whether Diffie-Hellman based credentials encryption is on.
+   * @return bool flag to indicate whether DH for credentials is on.
    */
-  _GEODE_DEPRECATED_(
-      "Diffie-Hellman based credentials encryption is not supported.")
-  bool isDhOn() const { return false; }
+  bool isDhOn() const { return !m_securityClientDhAlgo.empty(); }
 
   /**
    * Whether a non durable client starts to receive and process
diff --git a/cppcache/integration-test/CMakeLists.txt b/cppcache/integration-test/CMakeLists.txt
index dc2d6b5..f231bf8 100644
--- a/cppcache/integration-test/CMakeLists.txt
+++ b/cppcache/integration-test/CMakeLists.txt
@@ -124,7 +124,7 @@ foreach(FILE ${SOURCES})
   endif()
 
   # Some tests depend on these library
-  add_dependencies(${TEST} securityImpl cryptoImpl SqLiteImpl)
+  add_dependencies(${TEST} securityImpl cryptoImpl DHImpl SqLiteImpl)
 
   add_clangformat(${TEST})
 
@@ -232,6 +232,8 @@ set_property(TEST testThinClientSecurityAuthentication PROPERTY LABELS OMITTED)
 set_property(TEST testThinClientSecurityAuthenticationMU PROPERTY LABELS OMITTED)
 set_property(TEST testThinClientSecurityAuthorization PROPERTY LABELS OMITTED)
 set_property(TEST testThinClientSecurityAuthorizationMU PROPERTY LABELS OMITTED)
+set_property(TEST testThinClientSecurityDH PROPERTY LABELS OMITTED)
+set_property(TEST testThinClientSecurityDH_MU PROPERTY LABELS OMITTED)
 set_property(TEST testThinClientSecurityDurableCQAuthorizationMU PROPERTY LABELS OMITTED)
 set_property(TEST testThinClientSecurityPostAuthorization PROPERTY LABELS OMITTED)
 set_property(TEST testThinClientTicket303 PROPERTY LABELS OMITTED)
diff --git a/cppcache/integration-test/test.bat.in b/cppcache/integration-test/test.bat.in
index 8bf1f6b..ba99c08 100644
--- a/cppcache/integration-test/test.bat.in
+++ b/cppcache/integration-test/test.bat.in
@@ -22,6 +22,7 @@ set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:framework>>
 set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:testobject>>
 set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:SqLiteImpl>>
 set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:cryptoImpl>>
+set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:DHImpl>>
 set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:securityImpl>>
 set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:unit_test_callbacks>>
 set PATH=%PATH%;$<JOIN:$<SHELL_PATH:${PATH}>,;>
diff --git a/cppcache/integration-test/test.sh.in b/cppcache/integration-test/test.sh.in
index 920cf9b..033d0a1 100644
--- a/cppcache/integration-test/test.sh.in
+++ b/cppcache/integration-test/test.sh.in
@@ -23,6 +23,7 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:framework>
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:testobject>
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:SqLiteImpl>
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:cryptoImpl>
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:DHImpl>
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:securityImpl>
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:unit_test_callbacks>
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<JOIN:${LD_LIBRARY_PATH},:>
diff --git a/cppcache/integration-test/testThinClientSecurityDH.cpp b/cppcache/integration-test/testThinClientSecurityDH.cpp
new file mode 100644
index 0000000..776f584
--- /dev/null
+++ b/cppcache/integration-test/testThinClientSecurityDH.cpp
@@ -0,0 +1,471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "fw_dunit.hpp"
+#include "ThinClientHelper.hpp"
+#include <ace/OS.h>
+#include <ace/High_Res_Timer.h>
+
+#include "ThinClientSecurity.hpp"
+
+/* Test Coverage DH Algo
+BF1 - Blowfish:128 , BF2 - Blowfish:448
+AES1- AES:128,  AES2- AES:192, AES3- AES:256
+DES- DESede:192
+
+ATTENTION:  Blowfish:448, AES:192 and AES:256 needs Unlimited security strength
+policy. For this
+1- Downloaded jce_policy-6.zip from
+http://java.sun.com/javase/downloads/index.jsp.
+2- Unzip and replace 2 jar files in $gfe.dir/jre/lib/security folder.
+   Above mentioned Algo are commented as we can't ship product folder with above
+mentioned Jar files.
+ To test this test fully, please make above changes and uncomment related Algo
+portion in this test.
+*/
+
+#define BF1 "Blowfish:128"
+#define BF2 "Blowfish:448"
+#define AES1 "AES:128"
+#define AES2 "AES:192"
+#define AES3 "AES:256"
+#define DES "DESede"
+
+#define CLIENT1 s1p1
+#define CLIENT2 s1p2
+#define CLIENT3 s2p1
+#define LOCATORSERVER s2p2
+
+#define CORRECT_CREDENTIALS 'C'
+#define INCORRECT_CREDENTIALS 'I'
+
+using apache::geode::client::testframework::security::CredentialGenerator;
+
+const char *locHostPort =
+    CacheHelper::getLocatorHostPort(isLocator, isLocalServer, 1);
+const char *regionNamesAuth[] = {"DistRegionAck", "DistRegionNoAck"};
+std::shared_ptr<CredentialGenerator> credentialGeneratorHandler;
+
+std::string getXmlPath() {
+  char xmlPath[1000] = {'\0'};
+  const char *path = ACE_OS::getenv("TESTSRC");
+  ASSERT(path != nullptr,
+         "Environment variable TESTSRC for test source directory is not set.");
+  strncpy(xmlPath, path, strlen(path) - strlen("cppcache"));
+  strncat(xmlPath, "xml/Security/", sizeof(xmlPath) - strlen(xmlPath) - 1);
+  return std::string(xmlPath);
+}
+
+void initCredentialGenerator() {
+  static int loopNum = 1;
+
+  switch (loopNum) {
+    case 1: {
+      credentialGeneratorHandler = CredentialGenerator::create("DUMMY");
+      LOG("Creating Dummy Credential Generator");
+      break;
+    }
+    case 2: {
+      credentialGeneratorHandler = CredentialGenerator::create("LDAP");
+      LOG("Creating LDAP Credential Generator");
+      break;
+    }
+    default:
+    case 3: {
+      credentialGeneratorHandler = CredentialGenerator::create("PKCS");
+      LOG("Creating PKCS Credential Generator");
+      break;
+    }
+  }
+
+  if (credentialGeneratorHandler == nullptr) {
+    FAIL("credentialGeneratorHandler is nullptr");
+  }
+
+  loopNum++;
+  if (loopNum > 3) loopNum = 1;
+}
+
+void initClientAuth(char credentialsType, const char *dhAlgo) {
+  printf("Initializing Client with %s credential and %s DH Algo\n",
+         credentialsType == CORRECT_CREDENTIALS ? "Valid" : "Invalid", dhAlgo);
+
+  auto config = Properties::create();
+
+  config->insert("security-client-dhalgo", dhAlgo);
+  std::string testsrc = ACE_OS::getenv("TESTSRC");
+  testsrc += "/keystore/geode.pem";
+  printf("KeyStore Path is: %s", testsrc.c_str());
+  config->insert("security-client-kspath", testsrc.c_str());
+
+  if (credentialGeneratorHandler == nullptr) {
+    FAIL("credentialGeneratorHandler is nullptr");
+  }
+  bool insertAuthInit = true;
+  switch (credentialsType) {
+    case CORRECT_CREDENTIALS:
+      credentialGeneratorHandler->getValidCredentials(config);
+      config->insert("security-password",
+                     config->find("security-username")->value().c_str());
+      printf("Username is %s and Password is %s ",
+             config->find("security-username")->value().c_str(),
+             config->find("security-password")->value().c_str());
+      break;
+    case INCORRECT_CREDENTIALS:
+      credentialGeneratorHandler->getInvalidCredentials(config);
+      config->insert("security-password", "junk");
+      printf("Username is %s and Password is %s ",
+             config->find("security-username")->value().c_str(),
+             config->find("security-password")->value().c_str());
+      break;
+    default:
+      insertAuthInit = false;
+      break;
+  }
+  if (insertAuthInit) {
+    credentialGeneratorHandler->getAuthInit(config);
+  }
+
+  try {
+    initClient(true, config);
+  } catch (...) {
+    throw;
+  }
+}
+
+void InitIncorrectClients(const char *dhAlgo) {
+  try {
+    initClientAuth(INCORRECT_CREDENTIALS, dhAlgo);
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+  }
+
+  try {
+    createRegionForSecurity(regionNamesAuth[0], USE_ACK, true);
+    FAIL("Should have thrown AuthenticationFailedException.");
+  } catch (const apache::geode::client::AuthenticationFailedException &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+    FAIL("Only AuthenticationFailedException is expected");
+  }
+  LOG("InitIncorrectClients Completed");
+}
+
+void InitCorrectClients(const char *dhAlgo) {
+  try {
+    initClientAuth(CORRECT_CREDENTIALS, dhAlgo);
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+  }
+  try {
+    createRegionForSecurity(regionNamesAuth[0], USE_ACK, true);
+    createEntry(regionNamesAuth[0], keys[0], vals[0]);
+    updateEntry(regionNamesAuth[0], keys[0], nvals[0]);
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    FAIL(other.what());
+  }
+  LOG("Handshake  and  Authentication successfully completed");
+}
+
+void DoNetSearch() {
+  try {
+    createRegionForSecurity(regionNamesAuth[1], USE_ACK, true);
+    auto regPtr0 = getHelper()->getRegion(regionNamesAuth[0]);
+    auto keyPtr = CacheableKey::create(keys[0]);
+    auto checkPtr =
+        std::dynamic_pointer_cast<CacheableString>(regPtr0->get(keyPtr));
+    if (checkPtr != nullptr && !strcmp(nvals[0], checkPtr->value().c_str())) {
+      LOG("checkPtr is not null");
+      char buf[1024];
+      sprintf(buf, "In net search, get returned %s for key %s",
+              checkPtr->value().c_str(), keys[0]);
+      LOG(buf);
+    } else {
+      LOG("checkPtr is nullptr");
+    }
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    FAIL(other.what());
+  }
+  LOG("Handshake  and  Authentication successfully completed after FailOver");
+}
+
+void initSecurityServer(int instance) {
+  std::string cmdServerAuthenticator;
+  if (credentialGeneratorHandler == nullptr) {
+    FAIL("credentialGeneratorHandler is nullptr");
+  }
+
+  try {
+    if (isLocalServer) {
+      cmdServerAuthenticator = credentialGeneratorHandler->getServerCmdParams(
+          "authenticator", getXmlPath());
+
+      std::string testsrc = ACE_OS::getenv("TESTSRC");
+      if (instance == 1) {
+        testsrc += "/keystore/geode1.keystore";
+        cmdServerAuthenticator += " security-server-kspath=";
+        cmdServerAuthenticator += testsrc;
+        cmdServerAuthenticator +=
+            " security-server-ksalias=geode1 "
+            "security-server-kspasswd=geode";
+      } else if (instance == 2) {
+        testsrc += "/keystore/geode2.keystore";
+        cmdServerAuthenticator += " security-server-kspath=";
+        cmdServerAuthenticator += testsrc;
+        cmdServerAuthenticator +=
+            " security-server-ksalias=geode2 "
+            "security-server-kspasswd=geode";
+      }
+
+      printf("Input to server cmd is -->  %s\n",
+             cmdServerAuthenticator.c_str());
+      CacheHelper::initServer(
+          instance, nullptr, locHostPort,
+          const_cast<char *>(cmdServerAuthenticator.c_str()));
+    }
+  } catch (...) {
+    printf("this is some exception");
+  }
+}
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateLocator)
+  {
+    if (isLocator) CacheHelper::initLocator(1);
+    LOG("Locator1 started");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer1)
+  {
+    initCredentialGenerator();
+    initSecurityServer(1);
+    LOG("Server1 started");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer2)
+  {
+    initSecurityServer(2);
+    LOG("Server2 started");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF1)
+  {
+    initCredentialGenerator();
+    InitIncorrectClients(BF1);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES1)
+  {
+    initCredentialGenerator();
+    InitIncorrectClients(AES1);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectDES)
+  {
+    initCredentialGenerator();
+    InitIncorrectClients(DES);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpCorrectBF1)
+  {
+    InitCorrectClients(BF1);
+    LOG("Client created");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpCorrectAES1)
+  {
+    InitCorrectClients(AES1);
+    LOG("Client created");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpCorrectDES)
+  {
+    InitCorrectClients(DES);
+    LOG("Client created");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF2)
+  {
+    InitIncorrectClients(BF2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES2)
+  {
+    InitIncorrectClients(AES2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectAES3)
+  {
+    InitIncorrectClients(AES3);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownCorrectBF2)
+  {
+    InitCorrectClients(BF2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownCorrectAES2)
+  {
+    InitCorrectClients(AES2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownCorrectAES3)
+  {
+    InitCorrectClients(AES3);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1NetSearch)
+  {
+    SLEEP(1000);
+    DoNetSearch();
+    LOG("StepFive Completed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2NetSearch)
+  {
+    DoNetSearch();
+    LOG("StepFive Completed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3NetSearch)
+  {
+    DoNetSearch();
+    LOG("StepFive Completed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, CloseCache1)
+  { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, CloseCache2)
+  { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, CloseCache3)
+  { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer1)
+  {
+    if (isLocalServer) {
+      CacheHelper::closeServer(1);
+      LOG("SERVER1 stopped");
+    }
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer2)
+  {
+    if (isLocalServer) {
+      CacheHelper::closeServer(2);
+      LOG("SERVER2 stopped");
+    }
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseLocator)
+  {
+    if (isLocator) {
+      CacheHelper::closeLocator(1);
+      LOG("Locator1 stopped");
+    }
+  }
+END_TASK_DEFINITION
+
+void doThinClientSecurityDH() {
+  CALL_TASK(CreateLocator);
+  CALL_TASK(CreateServer1);
+  CALL_TASK(C1UpDownIncorrectBF1);
+  CALL_TASK(C2UpDownIncorrectAES1);
+  CALL_TASK(C3UpDownIncorrectDES);
+  CALL_TASK(C1UpCorrectBF1);
+  CALL_TASK(C2UpCorrectAES1);
+  CALL_TASK(C3UpCorrectDES);
+  CALL_TASK(CreateServer2);
+  CALL_TASK(CloseServer1);
+  CALL_TASK(C1NetSearch);
+  CALL_TASK(C2NetSearch);
+  CALL_TASK(C3NetSearch);
+  CALL_TASK(CloseCache1);
+  CALL_TASK(CloseCache2);
+  CALL_TASK(CloseCache3);
+
+  // Commented for Unlimited Security strength policy : See comment at top of
+  // testThinClientSecurityDH.cpp
+  // CALL_TASK(C1UpDownIncorrectBF2);
+  // CALL_TASK(C2UpDownIncorrectAES2);
+  // CALL_TASK(C3UpDownIncorrectAES3);
+  // CALL_TASK(C1UpDownCorrectBF2);
+  // CALL_TASK(C2UpDownCorrectAES2);
+  // CALL_TASK(C3UpDownCorrectAES3);
+  CALL_TASK(CloseServer2);
+  CALL_TASK(CloseLocator);
+}
+
+DUNIT_MAIN
+  { doThinClientSecurityDH(); }
+END_MAIN
diff --git a/cppcache/integration-test/testThinClientSecurityDH_MU.cpp b/cppcache/integration-test/testThinClientSecurityDH_MU.cpp
new file mode 100644
index 0000000..68a62d0
--- /dev/null
+++ b/cppcache/integration-test/testThinClientSecurityDH_MU.cpp
@@ -0,0 +1,503 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ROOT_NAME "testThinClientSecurityDH_MU"
+
+#include "fw_dunit.hpp"
+#include "ThinClientHelper.hpp"
+#include <ace/OS.h>
+#include <ace/High_Res_Timer.h>
+
+#include "ThinClientSecurity.hpp"
+
+/* Test Coverage DH Algo
+BF1 - Blowfish:128 , BF2 - Blowfish:448
+AES1- AES:128,  AES2- AES:192, AES3- AES:256
+DES- DESede:192
+
+ATTENTION:  Blowfish:448, AES:192 and AES:256 needs Unlimited security strength
+policy. For this
+1- Downloaded jce_policy-6.zip from
+http://java.sun.com/javase/downloads/index.jsp.
+2- Unzip and replace 2 jar files in $gfe.dir/jre/lib/security folder.
+   Above mentioned Algo are commented as we can't ship product folder with above
+mentioned Jar files.
+ To test this test fully, please make above changes and uncomment related Algo
+portion in this test.
+*/
+
+#define BF1 "Blowfish:128"
+#define BF2 "Blowfish:448"
+#define AES1 "AES:128"
+#define AES2 "AES:192"
+#define AES3 "AES:256"
+#define DES "DESede"
+
+#define CLIENT1 s1p1
+#define CLIENT2 s1p2
+#define CLIENT3 s2p1
+#define LOCATORSERVER s2p2
+
+#define CORRECT_CREDENTIALS 'C'
+#define INCORRECT_CREDENTIALS 'I'
+
+using apache::geode::client::testframework::security::CredentialGenerator;
+
+const char *locHostPort =
+    CacheHelper::getLocatorHostPort(isLocator, isLocalServer, 1);
+const char *regionNamesAuth[] = {"DistRegionAck", "DistRegionNoAck"};
+std::shared_ptr<CredentialGenerator> credentialGeneratorHandler;
+
+std::string getXmlPath() {
+  char xmlPath[1000] = {'\0'};
+  const char *path = ACE_OS::getenv("TESTSRC");
+  ASSERT(path != nullptr,
+         "Environment variable TESTSRC for test source directory is not set.");
+  strncpy(xmlPath, path, strlen(path) - strlen("cppcache"));
+  strncat(xmlPath, "xml/Security/", sizeof(xmlPath) - strlen(xmlPath) - 1);
+  return std::string(xmlPath);
+}
+
+void initCredentialGenerator() {
+  static int loopNum = 1;
+
+  switch (loopNum) {
+    case 1: {
+      credentialGeneratorHandler = CredentialGenerator::create("DUMMY");
+      LOG("Creating Dummy Credential Generator");
+      break;
+    }
+    case 2: {
+      credentialGeneratorHandler = CredentialGenerator::create("LDAP");
+      LOG("Creating LDAP Credential Generator");
+      break;
+    }
+    default:
+    case 3: {
+      credentialGeneratorHandler = CredentialGenerator::create("PKCS");
+      LOG("Creating PKCS Credential Generator");
+      break;
+    }
+  }
+
+  if (credentialGeneratorHandler == nullptr) {
+    FAIL("credentialGeneratorHandler is nullptr");
+  }
+
+  loopNum++;
+  if (loopNum > 2) loopNum = 1;
+}
+
+static std::shared_ptr<Properties> userCreds;
+
+void initClientAuth(char credentialsType, const char *dhAlgo) {
+  printf("Initializing Client with %s credential and %s DH Algo\n",
+         credentialsType == CORRECT_CREDENTIALS ? "Valid" : "Invalid", dhAlgo);
+
+  auto config = Properties::create();
+  userCreds = Properties::create();
+
+  config->insert("security-client-dhalgo", dhAlgo);
+  std::string testsrc = ACE_OS::getenv("TESTSRC");
+  testsrc += "/keystore/geode.pem";
+  printf("KeyStore Path is: %s", testsrc.c_str());
+  config->insert("security-client-kspath", testsrc.c_str());
+
+  if (credentialGeneratorHandler == nullptr) {
+    FAIL("credentialGeneratorHandler is nullptr");
+  }
+  bool insertAuthInit = true;
+  switch (credentialsType) {
+    case CORRECT_CREDENTIALS:
+      credentialGeneratorHandler->getValidCredentials(userCreds);
+      userCreds->insert("security-password",
+                        userCreds->find("security-username")->value().c_str());
+      printf("Username is %s and Password is %s ",
+             userCreds->find("security-username")->value().c_str(),
+             userCreds->find("security-password")->value().c_str());
+      break;
+    case INCORRECT_CREDENTIALS:
+      credentialGeneratorHandler->getInvalidCredentials(userCreds);
+      userCreds->insert("security-password", "junk");
+      printf("Username is %s and Password is %s ",
+             userCreds->find("security-username")->value().c_str(),
+             userCreds->find("security-password")->value().c_str());
+      break;
+    default:
+      insertAuthInit = false;
+      break;
+  }
+  if (insertAuthInit) {
+    //  credentialGeneratorHandler->getAuthInit(config);
+  }
+
+  try {
+    initClient(true, config);
+  } catch (...) {
+    throw;
+  }
+}
+
+void InitIncorrectClients(const char *dhAlgo) {
+  try {
+    initClientAuth(INCORRECT_CREDENTIALS, dhAlgo);
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+  }
+
+  try {
+    createRegionForSecurity(regionNamesAuth[0], USE_ACK, false, nullptr, false,
+                            -1, true, 0);
+    auto pool = getPool(regionNamesAuth[0]);
+    LOG(" 6");
+    if (pool != nullptr) {
+      LOG(" 7");
+      auto virtualCache = getVirtualCache(userCreds, pool);
+      LOG(" 8");
+      virtualCache.getRegion(regionNamesAuth[0])->put(keys[0], vals[0]);
+      LOG("Operation allowed, something is wrong.");
+    }
+    FAIL("Should have thrown AuthenticationFailedException.");
+  } catch (const apache::geode::client::AuthenticationFailedException &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+    FAIL("Only AuthenticationFailedException is expected");
+  }
+  LOG("InitIncorrectClients Completed");
+}
+
+void InitCorrectClients(const char *dhAlgo) {
+  try {
+    initClientAuth(CORRECT_CREDENTIALS, dhAlgo);
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    LOG(other.what());
+  }
+  try {
+    createRegionForSecurity(regionNamesAuth[0], USE_ACK, false, nullptr, false,
+                            -1, true, 0);
+    auto pool = getPool(regionNamesAuth[0]);
+    LOG(" 6");
+
+    LOG(" 7");
+    auto virtualCache = getVirtualCache(userCreds, pool);
+    LOG(" 8");
+    auto regionPtr = virtualCache.getRegion(regionNamesAuth[0]);
+
+    for (int i = 0; i < 100; i++) regionPtr->put(keys[0], vals[0]);
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    FAIL(other.what());
+  }
+  LOG("Handshake  and  Authentication successfully completed");
+}
+
+void DoNetSearch() {
+  try {
+    createRegionForSecurity(regionNamesAuth[1], USE_ACK, false, nullptr, false,
+                            -1, true, 0);
+    auto pool = getPool(regionNamesAuth[1]);
+    LOG(" 6");
+
+    LOG(" 7");
+    auto virtualCache = getVirtualCache(userCreds, pool);
+    LOG(" 8");
+    auto regionPtr = virtualCache.getRegion(regionNamesAuth[1]);
+
+    auto keyPtr = CacheableKey::create(keys[0]);
+    auto checkPtr =
+        std::dynamic_pointer_cast<CacheableString>(regionPtr->get(keyPtr));
+    if (checkPtr != nullptr && !strcmp(vals[0], checkPtr->value().c_str())) {
+      LOG("checkPtr is not null");
+      char buf[1024];
+      sprintf(buf, "In net search, get returned %s for key %s",
+              checkPtr->value().c_str(), keys[0]);
+      LOG(buf);
+    } else {
+      LOG("checkPtr is nullptr");
+    }
+  } catch (const apache::geode::client::Exception &other) {
+    LOG(other.getStackTrace());
+    FAIL(other.what());
+  }
+  LOG("Handshake  and  Authentication successfully completed after FailOver");
+}
+
+void initSecurityServer(int instance) {
+  std::string cmdServerAuthenticator;
+  if (credentialGeneratorHandler == nullptr) {
+    FAIL("credentialGeneratorHandler is nullptr");
+  }
+
+  try {
+    if (isLocalServer) {
+      cmdServerAuthenticator = credentialGeneratorHandler->getServerCmdParams(
+          "authenticator", getXmlPath());
+
+      std::string testsrc = ACE_OS::getenv("TESTSRC");
+      if (instance == 1) {
+        testsrc += "/keystore/geode1.keystore";
+        cmdServerAuthenticator += " security-server-kspath=";
+        cmdServerAuthenticator += testsrc;
+        cmdServerAuthenticator +=
+            " security-server-ksalias=geode1 "
+            "security-server-kspasswd=geode";
+      } else if (instance == 2) {
+        testsrc += "/keystore/geode2.keystore";
+        cmdServerAuthenticator += " security-server-kspath=";
+        cmdServerAuthenticator += testsrc;
+        cmdServerAuthenticator +=
+            " security-server-ksalias=geode2 "
+            "security-server-kspasswd=geode";
+      }
+
+      printf("Input to server cmd is -->  %s\n",
+             cmdServerAuthenticator.c_str());
+      CacheHelper::initServer(
+          instance, nullptr, locHostPort,
+          const_cast<char *>(cmdServerAuthenticator.c_str()));
+    }
+  } catch (...) {
+    printf("this is some exception");
+  }
+}
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateLocator)
+  {
+    if (isLocator) CacheHelper::initLocator(1);
+    LOG("Locator1 started");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer1)
+  {
+    initCredentialGenerator();
+    initSecurityServer(1);
+    LOG("Server1 started");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer2)
+  {
+    initSecurityServer(2);
+    LOG("Server2 started");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF1)
+  {
+    initCredentialGenerator();
+    InitIncorrectClients(BF1);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES1)
+  {
+    initCredentialGenerator();
+    InitIncorrectClients(AES1);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectDES)
+  {
+    initCredentialGenerator();
+    InitIncorrectClients(DES);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpCorrectBF1)
+  {
+    InitCorrectClients(BF1);
+    LOG("Client created");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpCorrectAES1)
+  {
+    InitCorrectClients(AES1);
+    LOG("Client created");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpCorrectDES)
+  {
+    InitCorrectClients(DES);
+    LOG("Client created");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF2)
+  {
+    InitIncorrectClients(BF2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES2)
+  {
+    InitIncorrectClients(AES2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectAES3)
+  {
+    InitIncorrectClients(AES3);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownCorrectBF2)
+  {
+    InitCorrectClients(BF2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownCorrectAES2)
+  {
+    InitCorrectClients(AES2);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownCorrectAES3)
+  {
+    InitCorrectClients(AES3);
+    LOG("Client created");
+    cleanProc();
+    LOG("Client closed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1NetSearch)
+  {
+    SLEEP(1000);
+    DoNetSearch();
+    LOG("StepFive Completed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2NetSearch)
+  {
+    DoNetSearch();
+    LOG("StepFive Completed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3NetSearch)
+  {
+    DoNetSearch();
+    LOG("StepFive Completed");
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, CloseCache1)
+  { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, CloseCache2)
+  { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, CloseCache3)
+  { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer1)
+  {
+    if (isLocalServer) {
+      CacheHelper::closeServer(1);
+      LOG("SERVER1 stopped");
+    }
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer2)
+  {
+    if (isLocalServer) {
+      CacheHelper::closeServer(2);
+      LOG("SERVER2 stopped");
+    }
+  }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseLocator)
+  {
+    if (isLocator) {
+      CacheHelper::closeLocator(1);
+      LOG("Locator1 stopped");
+    }
+  }
+END_TASK_DEFINITION
+
+void doThinClientSecurityDH() {
+  CALL_TASK(CreateLocator);
+  CALL_TASK(CreateServer1);
+  CALL_TASK(C1UpDownIncorrectBF1);
+  CALL_TASK(C2UpDownIncorrectAES1);
+  CALL_TASK(C3UpDownIncorrectDES);
+  CALL_TASK(C1UpCorrectBF1);
+  CALL_TASK(C2UpCorrectAES1);
+  CALL_TASK(C3UpCorrectDES);
+  CALL_TASK(CreateServer2);
+  CALL_TASK(CloseServer1);
+  CALL_TASK(C1NetSearch);
+  CALL_TASK(C2NetSearch);
+  CALL_TASK(C3NetSearch);
+  CALL_TASK(CloseCache1);
+  CALL_TASK(CloseCache2);
+  CALL_TASK(CloseCache3);
+
+  // Commented for Unlimited Security strength policy : See comment at top of
+  // testThinClientSecurityDH.cpp
+  // CALL_TASK(C1UpDownIncorrectBF2);
+  // CALL_TASK(C2UpDownIncorrectAES2);
+  // CALL_TASK(C3UpDownIncorrectAES3);
+  // CALL_TASK(C1UpDownCorrectBF2);
+  // CALL_TASK(C2UpDownCorrectAES2);
+  // CALL_TASK(C3UpDownCorrectAES3);
+  CALL_TASK(CloseServer2);
+  CALL_TASK(CloseLocator);
+}
+
+DUNIT_MAIN
+  { doThinClientSecurityDH(); }
+END_MAIN
diff --git a/cppcache/integration/test/CMakeLists.txt b/cppcache/integration/test/CMakeLists.txt
index 4c583ed..f76aab8 100644
--- a/cppcache/integration/test/CMakeLists.txt
+++ b/cppcache/integration/test/CMakeLists.txt
@@ -72,7 +72,7 @@ target_link_libraries(cpp-integration-test
     internal
 )
 
-add_dependencies(cpp-integration-test cryptoImpl)
+add_dependencies(cpp-integration-test cryptoImpl DHImpl)
 
 if(WIN32)
   target_compile_definitions(cpp-integration-test
diff --git a/cppcache/src/DiffieHellman.cpp b/cppcache/src/DiffieHellman.cpp
new file mode 100644
index 0000000..fc0c81d
--- /dev/null
+++ b/cppcache/src/DiffieHellman.cpp
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiffieHellman.hpp"
+
+#include <ace/Guard_T.h>
+
+#include <geode/ExceptionTypes.hpp>
+#include <geode/SystemProperties.hpp>
+
+#include "util/Log.hpp"
+namespace apache {
+namespace geode {
+namespace client {
+
+ACE_DLL DiffieHellman::m_dll;
+
+#define INIT_DH_FUNC_PTR(OrigName) \
+  DiffieHellman::OrigName##_Type DiffieHellman::OrigName##_Ptr = nullptr;
+
+INIT_DH_FUNC_PTR(gf_initDhKeys)
+INIT_DH_FUNC_PTR(gf_clearDhKeys)
+INIT_DH_FUNC_PTR(gf_getPublicKey)
+INIT_DH_FUNC_PTR(gf_setPublicKeyOther)
+INIT_DH_FUNC_PTR(gf_computeSharedSecret)
+INIT_DH_FUNC_PTR(gf_encryptDH)
+INIT_DH_FUNC_PTR(gf_decryptDH)
+INIT_DH_FUNC_PTR(gf_verifyDH)
+
+void* DiffieHellman::getOpenSSLFuncPtr(const char* function_name) {
+  void* func = m_dll.symbol(function_name);
+  if (func == nullptr) {
+    char msg[1000];
+    std::snprintf(msg, 1000, "cannot find function %s in library %s",
+                  function_name, "cryptoImpl");
+    LOGERROR(msg);
+    throw IllegalStateException(msg);
+  }
+  return func;
+}
+
+void DiffieHellman::initOpenSSLFuncPtrs() {
+  static bool inited = false;
+
+  if (inited) {
+    return;
+  }
+
+  const char* libName = "cryptoImpl";
+
+  if (m_dll.open(libName, ACE_DEFAULT_SHLIB_MODE, 0) == -1) {
+    char msg[1000];
+    std::snprintf(msg, 1000, "cannot open library: %s", libName);
+    LOGERROR(msg);
+    throw FileNotFoundException(msg);
+  }
+
+#define ASSIGN_DH_FUNC_PTR(OrigName) \
+  OrigName##_Ptr = (OrigName##_Type)getOpenSSLFuncPtr(#OrigName);
+
+  ASSIGN_DH_FUNC_PTR(gf_initDhKeys)
+  ASSIGN_DH_FUNC_PTR(gf_clearDhKeys)
+  ASSIGN_DH_FUNC_PTR(gf_getPublicKey)
+  ASSIGN_DH_FUNC_PTR(gf_setPublicKeyOther)
+  ASSIGN_DH_FUNC_PTR(gf_computeSharedSecret)
+  ASSIGN_DH_FUNC_PTR(gf_encryptDH)
+  ASSIGN_DH_FUNC_PTR(gf_decryptDH)
+  ASSIGN_DH_FUNC_PTR(gf_verifyDH)
+
+  inited = true;
+}
+
+void DiffieHellman::initDhKeys(const std::shared_ptr<Properties>& props) {
+  m_dhCtx = nullptr;
+
+  const auto& dhAlgo = props->find(SecurityClientDhAlgo);
+  const auto& ksPath = props->find(SecurityClientKsPath);
+
+  // Null check only for DH Algo
+  if (dhAlgo == nullptr) {
+    LOGFINE("DH algo not available");
+    return;
+  }
+
+  int error =
+      gf_initDhKeys_Ptr(&m_dhCtx, dhAlgo->value().c_str(),
+                        ksPath != nullptr ? ksPath->value().c_str() : nullptr);
+
+  if (error == DH_ERR_UNSUPPORTED_ALGO) {  // Unsupported Algorithm
+    char msg[64] = {'\0'};
+    std::snprintf(msg, 64, "Algorithm %s is not supported.",
+                  dhAlgo->value().c_str());
+    throw IllegalArgumentException(msg);
+  } else if (error == DH_ERR_ILLEGAL_KEYSIZE) {  // Illegal Key size
+    char msg[64] = {'\0'};
+    std::snprintf(msg, 64, "Illegal key size for algorithm %s.",
+                  dhAlgo->value().c_str());
+    throw IllegalArgumentException(msg);
+  } else if (m_dhCtx == nullptr) {
+    throw IllegalStateException(
+        "Could not initialize the Diffie-Hellman helper");
+  }
+}
+
+void DiffieHellman::clearDhKeys(void) {
+  // Sanity check for accidental calls
+  if (gf_clearDhKeys_Ptr == nullptr) {
+    return;
+  }
+
+  gf_clearDhKeys_Ptr(m_dhCtx);
+
+  m_dhCtx = nullptr;
+
+  return;
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::getPublicKey(void) {
+  int keyLen = 0;
+  auto pubKeyPtr = gf_getPublicKey_Ptr(m_dhCtx, &keyLen);
+  return CacheableBytes::create(
+      std::vector<int8_t>(pubKeyPtr, pubKeyPtr + keyLen));
+}
+
+void DiffieHellman::setPublicKeyOther(
+    const std::shared_ptr<CacheableBytes>& pubkey) {
+  return gf_setPublicKeyOther_Ptr(
+      m_dhCtx, reinterpret_cast<const uint8_t*>(pubkey->value().data()),
+      pubkey->length());
+}
+
+void DiffieHellman::computeSharedSecret(void) {
+  return gf_computeSharedSecret_Ptr(m_dhCtx);
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::encrypt(
+    const std::shared_ptr<CacheableBytes>& cleartext) {
+  return encrypt(reinterpret_cast<const uint8_t*>(cleartext->value().data()),
+                 cleartext->length());
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::encrypt(const uint8_t* cleartext,
+                                                       int len) {
+  int cipherLen = 0;
+  auto ciphertextPtr = gf_encryptDH_Ptr(m_dhCtx, cleartext, len, &cipherLen);
+  return CacheableBytes::create(
+      std::vector<int8_t>(ciphertextPtr, ciphertextPtr + cipherLen));
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::decrypt(
+    const std::shared_ptr<CacheableBytes>& cleartext) {
+  return decrypt(reinterpret_cast<const uint8_t*>(cleartext->value().data()),
+                 cleartext->length());
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::decrypt(const uint8_t* cleartext,
+                                                       int len) {
+  int cipherLen = 0;
+  auto ciphertextPtr = gf_decryptDH_Ptr(m_dhCtx, cleartext, len, &cipherLen);
+  return CacheableBytes::create(
+      std::vector<int8_t>(ciphertextPtr, ciphertextPtr + cipherLen));
+}
+
+bool DiffieHellman::verify(const std::shared_ptr<CacheableString>& subject,
+                           const std::shared_ptr<CacheableBytes>& challenge,
+                           const std::shared_ptr<CacheableBytes>& response) {
+  int errCode = DH_ERR_NO_ERROR;
+  LOGDEBUG("DiffieHellman::verify");
+  bool result = gf_verifyDH_Ptr(
+      m_dhCtx, subject->value().c_str(),
+      reinterpret_cast<const uint8_t*>(challenge->value().data()),
+      challenge->length(),
+      reinterpret_cast<const uint8_t*>(response->value().data()),
+      response->length(), &errCode);
+  LOGDEBUG("DiffieHellman::verify 2");
+  if (errCode == DH_ERR_SUBJECT_NOT_FOUND) {
+    LOGERROR("Subject name %s not found in imported certificates.",
+             subject->value().c_str());
+  } else if (errCode == DH_ERR_NO_CERTIFICATES) {
+    LOGERROR("No imported certificates.");
+  } else if (errCode == DH_ERR_INVALID_SIGN) {
+    LOGERROR("Signature varification failed.");
+  }
+
+  return result;
+}
+}  // namespace client
+}  // namespace geode
+}  // namespace apache
diff --git a/cppcache/src/DiffieHellman.hpp b/cppcache/src/DiffieHellman.hpp
new file mode 100644
index 0000000..234cac9
--- /dev/null
+++ b/cppcache/src/DiffieHellman.hpp
@@ -0,0 +1,109 @@
+#pragma once
+
+#ifndef GEODE_DIFFIEHELLMAN_H_
+#define GEODE_DIFFIEHELLMAN_H_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string>
+
+#include <ace/DLL.h>
+
+#include <geode/CacheableBuiltins.hpp>
+#include <geode/Properties.hpp>
+
+#define DH_ERR_NO_ERROR 0
+#define DH_ERR_UNSUPPORTED_ALGO 1
+#define DH_ERR_ILLEGAL_KEYSIZE 2
+#define DH_ERR_SUBJECT_NOT_FOUND 3
+#define DH_ERR_NO_CERTIFICATES 4
+#define DH_ERR_INVALID_SIGN 5
+
+const char SecurityClientDhAlgo[] = "security-client-dhalgo";
+const char SecurityClientKsPath[] = "security-client-kspath";
+
+namespace apache {
+namespace geode {
+namespace client {
+
+class DiffieHellman {
+ public:
+  void initDhKeys(const std::shared_ptr<Properties>& props);
+  void clearDhKeys(void);
+  std::shared_ptr<CacheableBytes> getPublicKey(void);
+  void setPublicKeyOther(const std::shared_ptr<CacheableBytes>& pubkey);
+  void computeSharedSecret(void);
+  std::shared_ptr<CacheableBytes> encrypt(
+      const std::shared_ptr<CacheableBytes>& cleartext);
+  std::shared_ptr<CacheableBytes> encrypt(const uint8_t* cleartext, int len);
+  std::shared_ptr<CacheableBytes> decrypt(
+      const std::shared_ptr<CacheableBytes>& cleartext);
+  std::shared_ptr<CacheableBytes> decrypt(const uint8_t* cleartext, int len);
+  bool verify(const std::shared_ptr<CacheableString>& subject,
+              const std::shared_ptr<CacheableBytes>& challenge,
+              const std::shared_ptr<CacheableBytes>& response);
+
+  static void initOpenSSLFuncPtrs();
+
+  DiffieHellman() : m_dhCtx(nullptr) {}
+
+ private:
+  void* m_dhCtx;
+  static void* getOpenSSLFuncPtr(const char* function_name);
+
+  // OpenSSL Func Ptrs: Declare Func Ptr type and a static variable of
+  // std::shared_ptr<Func> type. Convention: <Orig Func Name>_Type and <Orig
+  // Func Name>_Ptr
+  typedef int (*gf_initDhKeys_Type)(void** dhCtx, const char* dhAlgo,
+                                    const char* ksPath);
+  typedef void (*gf_clearDhKeys_Type)(void* dhCtx);
+  typedef unsigned char* (*gf_getPublicKey_Type)(void* dhCtx, int* len);
+  typedef void (*gf_setPublicKeyOther_Type)(void* dhCtx,
+                                            const unsigned char* pubkey,
+                                            int length);
+  typedef void (*gf_computeSharedSecret_Type)(void* dhCtx);
+  typedef unsigned char* (*gf_encryptDH_Type)(void* dhCtx,
+                                              const unsigned char* cleartext,
+                                              int len, int* retLen);
+  typedef unsigned char* (*gf_decryptDH_Type)(void* dhCtx,
+                                              const unsigned char* cleartext,
+                                              int len, int* retLen);
+  typedef bool (*gf_verifyDH_Type)(void* dhCtx, const char* subject,
+                                   const unsigned char* challenge,
+                                   int challengeLen,
+                                   const unsigned char* response,
+                                   int responseLen, int* reason);
+
+#define DECLARE_DH_FUNC_PTR(OrigName) static OrigName##_Type OrigName##_Ptr;
+
+  DECLARE_DH_FUNC_PTR(gf_initDhKeys)
+  DECLARE_DH_FUNC_PTR(gf_clearDhKeys)
+  DECLARE_DH_FUNC_PTR(gf_getPublicKey)
+  DECLARE_DH_FUNC_PTR(gf_setPublicKeyOther)
+  DECLARE_DH_FUNC_PTR(gf_computeSharedSecret)
+  DECLARE_DH_FUNC_PTR(gf_encryptDH)
+  DECLARE_DH_FUNC_PTR(gf_decryptDH)
+  DECLARE_DH_FUNC_PTR(gf_verifyDH)
+
+  static ACE_DLL m_dll;
+
+};  // class DiffieHellman
+}  // namespace client
+}  // namespace geode
+}  // namespace apache
+
+#endif  // GEODE_DIFFIEHELLMAN_H_
diff --git a/cppcache/src/DistributedSystem.hpp b/cppcache/src/DistributedSystem.hpp
index a03ea6c..f3ba16f 100644
--- a/cppcache/src/DistributedSystem.hpp
+++ b/cppcache/src/DistributedSystem.hpp
@@ -48,6 +48,7 @@ namespace client {
 class SystemProperties;
 class DistributedSystemImpl;
 class CacheRegionHelper;
+class DiffieHellman;
 class TcrConnection;
 
 class APACHE_GEODE_EXPORT DistributedSystem {
diff --git a/cppcache/src/DistributedSystemImpl.cpp b/cppcache/src/DistributedSystemImpl.cpp
index 2e20823..a648232 100644
--- a/cppcache/src/DistributedSystemImpl.cpp
+++ b/cppcache/src/DistributedSystemImpl.cpp
@@ -51,6 +51,9 @@ DistributedSystemImpl::DistributedSystemImpl(
       m_implementee(implementee),
       m_sysProps(std::move(sysProps)),
       m_connected(false) {
+  if (!m_sysProps->securityClientDhAlgo().empty()) {
+    DiffieHellman::initOpenSSLFuncPtrs();
+  }
   logSystemInformation();
 }
 
@@ -59,7 +62,7 @@ DistributedSystemImpl::~DistributedSystemImpl() {
 }
 
 void DistributedSystemImpl::connect() {
-  if (m_connected) {
+  if (m_connected == true) {
     throw AlreadyConnectedException(
         "DistributedSystem::connect: already connected, call getInstance to "
         "get it");
diff --git a/cppcache/src/DistributedSystemImpl.hpp b/cppcache/src/DistributedSystemImpl.hpp
index 457c9ea..ff3e2cc 100644
--- a/cppcache/src/DistributedSystemImpl.hpp
+++ b/cppcache/src/DistributedSystemImpl.hpp
@@ -27,6 +27,7 @@
 
 #include <geode/internal/geode_globals.hpp>
 
+#include "DiffieHellman.hpp"
 #include "DistributedSystem.hpp"
 #include "statistics/StatisticsManager.hpp"
 
@@ -67,6 +68,7 @@ class APACHE_GEODE_EXPORT DistributedSystemImpl {
 
   std::string m_name;
   DistributedSystem* m_implementee;
+  DiffieHellman m_dh;
 
   /**
    * @brief constructors
diff --git a/cppcache/src/SystemProperties.cpp b/cppcache/src/SystemProperties.cpp
index 9e86b01..bc69dc9 100644
--- a/cppcache/src/SystemProperties.cpp
+++ b/cppcache/src/SystemProperties.cpp
@@ -268,8 +268,7 @@ void SystemProperties::processProperty(const std::string& property,
     m_securityPropertiesPtr->insert(property, value);
 
     if (property == SecurityClientDhAlgo) {
-      throw IllegalArgumentException(
-          "Diffie-Hellman based credentials encryption is not supported.");
+      m_securityClientDhAlgo = value;
     } else if (property == SecurityClientKsPath) {
       m_securityClientKsPath = value;
     }
@@ -455,6 +454,9 @@ void SystemProperties::logSettings() {
   settings += "\n  redundancy-monitor-interval = ";
   settings += to_string(redundancyMonitorInterval());
 
+  settings += "\n  security-client-dhalgo = ";
+  settings += securityClientDhAlgo();
+
   settings += "\n  security-client-kspath = ";
   settings += securityClientKsPath();
 
diff --git a/cppcache/src/TcrConnection.cpp b/cppcache/src/TcrConnection.cpp
index 51e5c09..d23d5d9 100644
--- a/cppcache/src/TcrConnection.cpp
+++ b/cppcache/src/TcrConnection.cpp
@@ -27,6 +27,7 @@
 
 #include "ClientProxyMembershipID.hpp"
 #include "Connector.hpp"
+#include "DiffieHellman.hpp"
 #include "DistributedSystemImpl.hpp"
 #include "TcpSslConn.hpp"
 #include "TcrConnectionManager.hpp"
@@ -46,10 +47,10 @@ const int8_t LAST_CHUNK_MASK = 0x1;
 const int64_t INITIAL_CONNECTION_ID = 26739;
 
 #define throwException(ex)                            \
-  do {                                                \
+  {                                                   \
     LOGFINEST(ex.getName() + ": " + ex.getMessage()); \
     throw ex;                                         \
-  } while (0)
+  }
 
 struct FinalizeProcessChunk {
  private:
@@ -78,6 +79,7 @@ bool TcrConnection::initTcrConnection(
   // m_connected = isConnected;
   m_hasServerQueue = NON_REDUNDANT_SERVER;
   m_queueSize = 0;
+  m_dh = nullptr;
   // m_chunksProcessSema = 0;
   m_creationTime = clock::now();
   connectionId = INITIAL_CONNECTION_ID;
@@ -190,6 +192,7 @@ bool TcrConnection::initTcrConnection(
   }
   handShakeMsg.writeInt(static_cast<int32_t>(1));
 
+  bool isDhOn = false;
   bool requireServerAuth = false;
   std::shared_ptr<Properties> credentials;
   std::shared_ptr<CacheableBytes> serverChallenge;
@@ -198,18 +201,29 @@ bool TcrConnection::initTcrConnection(
   handShakeMsg.write(getOverrides(&sysProp));
 
   bool tmpIsSecurityOn = nullptr != cacheImpl->getAuthInitialize();
+  isDhOn = sysProp.isDhOn();
 
   if (m_endpointObj) {
-    tmpIsSecurityOn = tmpIsSecurityOn || m_endpointObj->isMultiUserMode();
+    tmpIsSecurityOn = tmpIsSecurityOn || this->m_endpointObj->isMultiUserMode();
+    auto dhalgo =
+        sysProp.getSecurityProperties()->find("security-client-dhalgo");
+
+    LOGDEBUG("TcrConnection this->m_endpointObj->isMultiUserMode() = %d ",
+             this->m_endpointObj->isMultiUserMode());
+    if (this->m_endpointObj->isMultiUserMode()) {
+      if (dhalgo != nullptr && dhalgo->length() > 0) isDhOn = true;
+    }
   }
 
   LOGDEBUG(
-      "TcrConnection tmpIsSecurityOn = %d isNotificationChannel = "
-      "%d ",
-      tmpIsSecurityOn, isNotificationChannel);
+      "TcrConnection algo name %s tmpIsSecurityOn = %d isDhOn = %d "
+      "isNotificationChannel = %d ",
+      sysProp.securityClientDhAlgo().c_str(), tmpIsSecurityOn, isDhOn,
+      isNotificationChannel);
   bool doIneedToSendCreds = true;
   if (isNotificationChannel && m_endpointObj &&
       this->m_endpointObj->isMultiUserMode()) {
+    isDhOn = false;
     tmpIsSecurityOn = false;
     doIneedToSendCreds = false;
   }
@@ -217,6 +231,10 @@ bool TcrConnection::initTcrConnection(
   if (isNotificationChannel && !doIneedToSendCreds) {
     handShakeMsg.write(
         static_cast<uint8_t>(SECURITY_MULTIUSER_NOTIFICATIONCHANNEL));
+  } else if (isDhOn) {
+    m_dh = new DiffieHellman();
+    m_dh->initDhKeys(sysProp.getSecurityProperties());
+    handShakeMsg.write(static_cast<uint8_t>(SECURITY_CREDENTIALS_DHENCRYPT));
   } else if (tmpIsSecurityOn) {
     handShakeMsg.write(static_cast<uint8_t>(SECURITY_CREDENTIALS_NORMAL));
   } else {
@@ -243,9 +261,38 @@ bool TcrConnection::initTcrConnection(
           credentials = tmpAuthIniSecurityProperties;
         }
       }
-      if (isClientNotification) {
-        credentials->toData(handShakeMsg);
-      }
+
+      if (isDhOn) {
+        auto ksPath = tmpSecurityProperties->find("security-client-kspath");
+        requireServerAuth = (ksPath != nullptr && ksPath->length() > 0);
+        handShakeMsg.writeBoolean(requireServerAuth);
+        LOGFINE(
+            "HandShake: Server authentication using RSA signature %s required",
+            requireServerAuth ? "is" : "not");
+
+        // Send the symmetric key algorithm name string
+        handShakeMsg.writeString(sysProp.securityClientDhAlgo());
+
+        // Send the client's DH public key to the server
+        auto dhPubKey = m_dh->getPublicKey();
+        LOGDEBUG("DH pubkey send len is %d", dhPubKey->length());
+        dhPubKey->toData(handShakeMsg);
+
+        if (requireServerAuth) {
+          char serverChallengeBytes[64] = {0};
+          RandGen getrand;
+          for (int pos = 0; pos < 64; pos++) {
+            serverChallengeBytes[pos] = getrand(255);
+          }
+          serverChallenge = CacheableBytes::create(std::vector<int8_t>(
+              serverChallengeBytes, serverChallengeBytes + 64));
+          serverChallenge->toData(handShakeMsg);
+        }
+      } else {                       // if isDhOn
+        if (isClientNotification) {  //:only for backward connection
+          credentials->toData(handShakeMsg);
+        }
+      }  // else isDhOn
     } catch (const AuthenticationRequiredException&) {
       LOGDEBUG("AuthenticationRequiredException got");
       throw;
@@ -283,6 +330,77 @@ bool TcrConnection::initTcrConnection(
       throwException(ex);
     }
 
+    // if diffie-hellman based credential encryption is enabled
+    if (isDhOn && acceptanceCode[0] == REPLY_OK) {
+      // read the server's DH public key
+      auto pubKeyBytes = readHandshakeByteArray(connectTimeout);
+      LOGDEBUG(" Handshake: Got pubKeySize %d", pubKeyBytes->length());
+
+      // set the server's public key on client's DH side
+      // DiffieHellman::setPublicKeyOther(pubKeyBytes);
+      m_dh->setPublicKeyOther(pubKeyBytes);
+
+      // Note: SK Algo is set in DistributedSystem::connect()
+      // DiffieHellman::computeSharedSecret();
+      m_dh->computeSharedSecret();
+
+      if (requireServerAuth) {
+        // Read Subject Name
+        auto subjectName = readHandshakeString(connectTimeout);
+        LOGDEBUG("Got subject %s", subjectName->value().c_str());
+        // read the server's signature bytes
+        auto responseBytes = readHandshakeByteArray(connectTimeout);
+        LOGDEBUG("Handshake: Got response size %d", responseBytes->length());
+        LOGDEBUG("Handshake: Got serverChallenge size %d",
+                 serverChallenge->length());
+        if (!m_dh->verify(subjectName, serverChallenge, responseBytes)) {
+          throwException(AuthenticationFailedException(
+              "Handshake: failed to verify server challenge response"));
+        }
+        LOGFINE("HandShake: Verified server challenge response");
+      }
+
+      // read the challenge bytes from the server
+      auto challengeBytes = readHandshakeByteArray(connectTimeout);
+      LOGDEBUG("Handshake: Got challengeSize %d", challengeBytes->length());
+
+      // encrypt the credentials and challenge bytes
+      auto cleartext = cacheImpl->createDataOutput();
+      if (isClientNotification) {  //:only for backward connection
+        credentials->toData(cleartext);
+      }
+      challengeBytes->toData(cleartext);
+      auto ciphertext = m_dh->encrypt(
+          cleartext.getBuffer(), static_cast<int>(cleartext.getBufferLength()));
+
+      auto sendCreds = cacheImpl->createDataOutput();
+      ciphertext->toData(sendCreds);
+      size_t credLength;
+      auto credData = reinterpret_cast<char*>(
+          const_cast<uint8_t*>(sendCreds.getBuffer(&credLength)));
+      // send the encrypted bytes and check the response
+      error = sendData(credData, credLength, connectTimeout, false);
+
+      if (error == CONN_NOERR) {
+        acceptanceCode = readHandshakeData(1, connectTimeout);
+        LOGDEBUG("Handshake: Got acceptanceCode Finally %d", acceptanceCode[0]);
+      } else {
+        int32_t lastError = ACE_OS::last_error();
+        LOGERROR("Handshake failed, errno: %d, server may not be running",
+                 lastError);
+        GF_SAFE_DELETE_CON(m_conn);
+        if (error & CONN_TIMEOUT) {
+          throwException(TimeoutException(
+              "TcrConnection::TcrConnection: "
+              "connection timed out during diffie-hellman handshake"));
+        } else {
+          throwException(
+              GeodeIOException("TcrConnection::TcrConnection: "
+                               "Handshake failure during diffie-hellman"));
+        }
+      }
+    }
+
     auto serverQueueStatus = readHandshakeData(1, connectTimeout);
 
     //  TESTING: Durable clients - set server queue status.
@@ -567,10 +685,9 @@ char* TcrConnection::sendRequest(const char* buffer, size_t len,
 
   send(timeSpent, buffer, len, sendTimeoutSec);
 
-  if (timeSpent >= receiveTimeoutSec) {
+  if (timeSpent >= receiveTimeoutSec)
     throwException(
         TimeoutException("TcrConnection::send: connection timed out"));
-  }
 
   receiveTimeoutSec -= timeSpent;
   ConnErrType opErr = CONN_NOERR;
@@ -1283,6 +1400,11 @@ TcrConnection::~TcrConnection() {
     m_conn->close();
     GF_SAFE_DELETE_CON(m_conn);
   }
+
+  if (m_dh != nullptr) {
+    m_dh->clearDhKeys();
+    _GEODE_SAFE_DELETE(m_dh);
+  }
 }
 
 bool TcrConnection::setAndGetBeingUsed(volatile bool isBeingUsed,
diff --git a/cppcache/src/TcrConnection.hpp b/cppcache/src/TcrConnection.hpp
index 18969e1..c3d09cf 100644
--- a/cppcache/src/TcrConnection.hpp
+++ b/cppcache/src/TcrConnection.hpp
@@ -30,6 +30,7 @@
 #include <geode/internal/geode_globals.hpp>
 
 #include "Connector.hpp"
+#include "DiffieHellman.hpp"
 #include "TcrMessage.hpp"
 #include "util/synchronized_set.hpp"
 
@@ -40,6 +41,7 @@
 #define UNSUCCESSFUL_SERVER_TO_CLIENT 106
 #define CLIENT_TO_SERVER 100
 #define REPLY_OK 59
+#define REPLY_OK_CS43 58
 #define REPLY_REFUSED 60
 #define REPLY_INVALID 61
 #define REPLY_SSL_ENABLED 21
@@ -49,6 +51,7 @@
 
 #define SECURITY_CREDENTIALS_NONE 0
 #define SECURITY_CREDENTIALS_NORMAL 1
+#define SECURITY_CREDENTIALS_DHENCRYPT 2
 #define SECURITY_MULTIUSER_NOTIFICATIONCHANNEL 3
 
 /** Closes and Deletes connection only if it exists */
@@ -132,6 +135,7 @@ class APACHE_GEODE_EXPORT TcrConnection {
                 volatile const bool& isConnected)
       : connectionId(0),
         m_connectionManager(&connectionManager),
+        m_dh(nullptr),
         m_endpoint(nullptr),
         m_endpointObj(nullptr),
         m_connected(isConnected),
@@ -304,9 +308,28 @@ class APACHE_GEODE_EXPORT TcrConnection {
     return *m_connectionManager;
   }
 
+  std::shared_ptr<CacheableBytes> encryptBytes(
+      std::shared_ptr<CacheableBytes> data) {
+    if (m_dh != nullptr) {
+      return m_dh->encrypt(data);
+    } else {
+      return data;
+    }
+  }
+
+  std::shared_ptr<CacheableBytes> decryptBytes(
+      std::shared_ptr<CacheableBytes> data) {
+    if (m_dh != nullptr) {
+      return m_dh->decrypt(data);
+    } else {
+      return data;
+    }
+  }
+
  private:
   int64_t connectionId;
   const TcrConnectionManager* m_connectionManager;
+  DiffieHellman* m_dh;
 
   std::chrono::microseconds calculateHeaderTimeout(
       std::chrono::microseconds receiveTimeout, bool retry);
diff --git a/cppcache/src/TcrMessage.cpp b/cppcache/src/TcrMessage.cpp
index aa8361d..aeb3917 100644
--- a/cppcache/src/TcrMessage.cpp
+++ b/cppcache/src/TcrMessage.cpp
@@ -604,11 +604,11 @@ void TcrMessage::readUniqueIDObjectPart(DataInput& input) {
   }
 }
 
-int64_t TcrMessage::getConnectionId() {
-  if (m_connectionIDBytes) {
+int64_t TcrMessage::getConnectionId(TcrConnection* conn) {
+  if (m_connectionIDBytes != nullptr) {
+    auto tmp = conn->decryptBytes(m_connectionIDBytes);
     auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
-        reinterpret_cast<const uint8_t*>(m_connectionIDBytes->value().data()),
-        m_connectionIDBytes->length());
+        reinterpret_cast<const uint8_t*>(tmp->value().data()), tmp->length());
     return di.readInt64();
   } else {
     LOGWARN("Returning 0 as internal connection ID msgtype = %d ", m_msgType);
@@ -616,12 +616,14 @@ int64_t TcrMessage::getConnectionId() {
   }
 }
 
-int64_t TcrMessage::getUniqueId() {
-  if (auto cacheableBytes =
-          std::dynamic_pointer_cast<CacheableBytes>(m_value)) {
+int64_t TcrMessage::getUniqueId(TcrConnection* conn) {
+  if (m_value != nullptr) {
+    auto encryptBytes = std::dynamic_pointer_cast<CacheableBytes>(m_value);
+
+    auto tmp = conn->decryptBytes(encryptBytes);
+
     auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
-        reinterpret_cast<const uint8_t*>(cacheableBytes->value().data()),
-        cacheableBytes->length());
+        reinterpret_cast<const uint8_t*>(tmp->value().data()), tmp->length());
     return di.readInt64();
   }
   return 0;
@@ -2785,7 +2787,7 @@ TcrMessageRemoveUserAuth::TcrMessageRemoveUserAuth(
                .c_str());
 }
 
-void TcrMessage::createUserCredentialMessage(TcrConnection*) {
+void TcrMessage::createUserCredentialMessage(TcrConnection* conn) {
   m_request->reset();
   m_isSecurityHeaderAdded = false;
   writeHeader(m_msgType, 1);
@@ -2797,7 +2799,8 @@ void TcrMessage::createUserCredentialMessage(TcrConnection*) {
 
   auto credBytes = CacheableBytes::create(std::vector<int8_t>(
       dOut.getBuffer(), dOut.getBuffer() + dOut.getBufferLength()));
-  writeObjectPart(credBytes);
+  auto encryptBytes = conn->encryptBytes(credBytes);
+  writeObjectPart(encryptBytes);
 
   writeMessageLength();
   LOGDEBUG("TcrMessage::createUserCredentialMessage  msg = %s ",
@@ -2828,18 +2831,21 @@ void TcrMessage::addSecurityPart(int64_t connectionId, int64_t unique_id,
   auto bytes = CacheableBytes::create(std::vector<int8_t>(
       dOutput.getBuffer(), dOutput.getBuffer() + dOutput.getBufferLength()));
 
+  auto encryptBytes = conn->encryptBytes(bytes);
+
   LOGDEBUG("TcrMessage::addSecurityPart [%p] length = %" PRId32
            ", encrypted ID = %s ",
-           conn, bytes->length(),
-           Utils::convertBytesToString(bytes->value().data(), bytes->length())
+           conn, encryptBytes->length(),
+           Utils::convertBytesToString(encryptBytes->value().data(),
+                                       encryptBytes->length())
                .c_str());
 
-  writeObjectPart(bytes);
+  writeObjectPart(encryptBytes);
   writeMessageLength();
-  m_securityHeaderLength = 4 + 1 + bytes->length();
+  m_securityHeaderLength = 4 + 1 + encryptBytes->length();
 }
 
-void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection*) {
+void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection* conn) {
   LOGDEBUG("TcrMessage::addSecurityPart m_isSecurityHeaderAdded = %d ",
            m_isSecurityHeaderAdded);
   if (m_isSecurityHeaderAdded) {
@@ -2859,9 +2865,11 @@ void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection*) {
   auto bytes = CacheableBytes::create(std::vector<int8_t>(
       dOutput.getBuffer(), dOutput.getBuffer() + dOutput.getBufferLength()));
 
-  writeObjectPart(bytes);
+  auto encryptBytes = conn->encryptBytes(bytes);
+
+  writeObjectPart(encryptBytes);
   writeMessageLength();
-  m_securityHeaderLength = 4 + 1 + bytes->length();
+  m_securityHeaderLength = 4 + 1 + encryptBytes->length();
   LOGDEBUG("TcrMessage addspCC = %s ",
            Utils::convertBytesToString(m_request->getBuffer(),
                                        m_request->getBufferLength())
diff --git a/cppcache/src/TcrMessage.hpp b/cppcache/src/TcrMessage.hpp
index 007dbd1..89d4870 100644
--- a/cppcache/src/TcrMessage.hpp
+++ b/cppcache/src/TcrMessage.hpp
@@ -302,9 +302,9 @@ class TcrMessage {
 
   void addSecurityPart(int64_t connectionId, TcrConnection* conn);
 
-  int64_t getConnectionId();
+  int64_t getConnectionId(TcrConnection* conn);
 
-  int64_t getUniqueId();
+  int64_t getUniqueId(TcrConnection* conn);
 
   void createUserCredentialMessage(TcrConnection* conn);
 
diff --git a/cppcache/src/ThinClientBaseDM.cpp b/cppcache/src/ThinClientBaseDM.cpp
index 82bcea0..a1d741a 100644
--- a/cppcache/src/ThinClientBaseDM.cpp
+++ b/cppcache/src/ThinClientBaseDM.cpp
@@ -300,17 +300,17 @@ void ThinClientBaseDM::afterSendingRequest(const TcrMessage& request,
       if (TcrMessage::RESPONSE == reply.getMessageType()) {
         if (this->isMultiUserMode()) {
           UserAttributes::threadLocalUserAttributes->setConnectionAttributes(
-              conn->getEndpointObject(), reply.getUniqueId());
+              conn->getEndpointObject(), reply.getUniqueId(conn));
         } else {
-          conn->getEndpointObject()->setUniqueId(reply.getUniqueId());
+          conn->getEndpointObject()->setUniqueId(reply.getUniqueId(conn));
         }
       }
-      conn->setConnectionId(reply.getConnectionId());
+      conn->setConnectionId(reply.getConnectionId(conn));
     } else if (TcrMessage::isUserInitiativeOps(request)) {
       // bugfix: if noack op then reuse previous security token.
       conn->setConnectionId(reply.getMessageType() == TcrMessage::INVALID
                                 ? conn->getConnectionId()
-                                : reply.getConnectionId());
+                                : reply.getConnectionId(conn));
     }
   }
 }
diff --git a/cryptoimpl/CMakeLists.txt b/cryptoimpl/CMakeLists.txt
index 3852e2b..22a3856 100644
--- a/cryptoimpl/CMakeLists.txt
+++ b/cryptoimpl/CMakeLists.txt
@@ -17,6 +17,8 @@ project(cryptoImpl LANGUAGES CXX)
 
 add_library(cryptoImpl SHARED
   ${CMAKE_CURRENT_BINARY_DIR}/cryptoimpl_export.h
+  DHImpl.hpp
+  DHImpl.cpp
   Ssl.hpp
   SSLImpl.hpp
   SSLImpl.cpp
diff --git a/cryptoimpl/DHImpl.cpp b/cryptoimpl/DHImpl.cpp
new file mode 100644
index 0000000..1365d32
--- /dev/null
+++ b/cryptoimpl/DHImpl.cpp
@@ -0,0 +1,713 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DHImpl.hpp"
+
+#include <openssl-compat.h>
+#include <openssl/aes.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include <cctype>
+#include <cstring>
+#include <memory>
+
+/*
+static DH * m_dh = nullptr;
+static string m_skAlgo;
+static int    m_keySize = 0;
+static BIGNUM * m_pubKeyOther = nullptr;
+static unsigned char m_key[128] = {0};
+static std::vector<X509*> m_serverCerts;
+*/
+
+static const char *dhP =
+    "13528702063991073999718992897071702177131142188276542919088770094024269"
+    "73079899070080419278066109785292538223079165925365098181867673946"
+    "34756714063947534092593553024224277712367371302394452615862654308"
+    "11180902979719649450105660478776364198726078338308557022096810447"
+    "3500348898008043285865193451061481841186553";
+
+static const char *dhG =
+    "13058345680719715096166513407513969537624553636623932169016704425008150"
+    "56576152779768716554354314319087014857769741104157332735258102835"
+    "93126577393912282416840649805564834470583437473176415335737232689"
+    "81480201869671811010996732593655666464627559582258861254878896534"
+    "1273697569202082715873518528062345259949959";
+
+static const int dhL = 1023;
+
+static int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey);
+static EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key);
+/*
+static const EVP_CIPHER* getCipherFunc();
+static int setSkAlgo(const char * skalgo);
+*/
+
+ASN1_SEQUENCE(
+    DH_PUBKEY) = {ASN1_SIMPLE(DH_PUBKEY, algor, X509_ALGOR),
+                  ASN1_SIMPLE(DH_PUBKEY, public_key,
+                              ASN1_BIT_STRING)} ASN1_SEQUENCE_END(DH_PUBKEY)
+
+    // This gives us the i2d/d2i x.509 (ASN1 DER) encode/decode functions
+    IMPLEMENT_ASN1_FUNCTIONS(DH_PUBKEY)
+
+    // Returns Error code
+    int gf_initDhKeys(void **dhCtx, const char *dhAlgo, const char *ksPath) {
+  int errorCode = DH_ERR_NO_ERROR;  // No error;
+
+  auto dhimpl = new DHImpl();
+  *dhCtx = dhimpl;
+
+  // ksPath can be null
+  if (dhimpl->m_dh || !dhAlgo || strlen(dhAlgo) == 0) {
+    return errorCode;
+  }
+
+  // set the symmetric cipher algorithm name
+  errorCode = dhimpl->setSkAlgo(dhAlgo);
+  if (errorCode != DH_ERR_NO_ERROR) {
+    return errorCode;
+  }
+
+  // do add-all here or outside in DS::connect?
+  if (!DHImpl::m_init) {
+    OpenSSL_add_all_algorithms();
+    ERR_load_crypto_strings();
+    DHImpl::m_init = true;
+  }
+
+  dhimpl->m_dh = DH_new();
+
+  BIGNUM *pbn = nullptr;
+  BIGNUM *gbn = nullptr;
+  DH_get0_pqg(dhimpl->m_dh, const_cast<const BIGNUM **>(&pbn), nullptr,
+              const_cast<const BIGNUM **>(&gbn));
+  BN_dec2bn(&pbn, dhP);
+
+  LOGDH(" DHInit: P ptr is %p", pbn);
+  LOGDH(" DHInit: G ptr is %p", gbn);
+  LOGDH(" DHInit: length is %d", DH_get_length(dhimpl->m_dh));
+
+  BN_dec2bn(&gbn, dhG);
+
+  DH_set_length(dhimpl->m_dh, dhL);
+
+  DH_generate_key(dhimpl->m_dh);
+
+  const BIGNUM *pub_key, *priv_key;
+  DH_get0_key(dhimpl->m_dh, &pub_key, &priv_key);
+  BN_num_bits(priv_key);
+
+  BN_num_bits(pub_key);
+
+  int codes = 0;
+  DH_check(dhimpl->m_dh, &codes);
+  LOGDH(" DHInit: DH_check codes is 0x%04X", codes);
+  LOGDH(" DHInit: DH_size is %d", DH_size(dhimpl->m_dh));
+
+  // load the server's RSA public key for server authentication
+  // note that OpenSSL 0.9.8g has a bug where it can read only the first one in
+  // the keystore
+
+  LOGDH(" Loading keystore...");
+
+  if (ksPath == nullptr || strlen(ksPath) == 0) {
+    LOGDH("Property \"security-client-kspath\" 's value is nullptr.");
+    return errorCode;
+  }
+  FILE *keyStoreFP = nullptr;
+  keyStoreFP = fopen(ksPath, "r");
+
+  LOGDH(" kspath is [%s]", ksPath);
+  LOGDH(" keystore FILE ptr is %p", keyStoreFP);
+
+  // Read from pem file and put into.
+  X509 *cert = nullptr;
+  do {
+    cert = PEM_read_X509(keyStoreFP, nullptr, nullptr, nullptr);
+
+    if (cert != nullptr) {
+      dhimpl->m_serverCerts.push_back(cert);
+    }
+  } while (cert != nullptr);
+
+  LOGDH(" Total certificats imported # %zd", dhimpl->m_serverCerts.size());
+
+  fclose(keyStoreFP);
+
+  return errorCode;
+}
+
+void gf_clearDhKeys(void *dhCtx) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  if (dhimpl->m_dh != nullptr) {
+    DH_free(dhimpl->m_dh);
+    dhimpl->m_dh = nullptr;
+  }
+
+  std::vector<X509 *>::const_iterator iter;
+  for (iter = dhimpl->m_serverCerts.begin();
+       iter != dhimpl->m_serverCerts.end(); ++iter) {
+    X509_free(*iter);
+  }
+
+  dhimpl->m_serverCerts.clear();
+
+  if (dhimpl->m_pubKeyOther != nullptr) {
+    BN_free(dhimpl->m_pubKeyOther);
+    dhimpl->m_pubKeyOther = nullptr;
+  }
+
+  memset(dhimpl->m_key, 0, 128);
+
+  // EVP_cleanup();
+}
+
+unsigned char *gf_getPublicKey(void *dhCtx, int *pLen) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  const BIGNUM *pub_key, *priv_key;
+  DH_get0_key(dhimpl->m_dh, &pub_key, &priv_key);
+
+  if (pub_key == nullptr || pLen == nullptr) {
+    return nullptr;
+  }
+
+  int numBytes = BN_num_bytes(pub_key);
+
+  if (numBytes <= 0) {
+    return nullptr;
+  }
+
+  EVP_PKEY *evppubkey = EVP_PKEY_new();
+  LOGDH(" before assign DH ptr is %p\n", dhimpl->m_dh);
+  EVP_PKEY_assign_DH(evppubkey, dhimpl->m_dh);
+  LOGDH(" after assign DH ptr is %p\n", dhimpl->m_dh);
+  DH_PUBKEY *dhpubkey = nullptr;
+  DH_PUBKEY_set(&dhpubkey, evppubkey);
+  int len = i2d_DH_PUBKEY(dhpubkey, nullptr);
+  unsigned char *pubkey = new unsigned char[len];
+  unsigned char *temp = pubkey;
+  //
+  //  Note, this temp pointer is needed because OpenSSL increments the pointer
+  //  passed in
+  // so that following encoding can be done at the current output location, this
+  // will cause a
+  // problem if we try to free the pointer which has been moved by OpenSSL.
+  //
+  i2d_DH_PUBKEY(dhpubkey, &temp);
+
+  //  TODO: uncomment this - causing problem in computeSecret?
+  // DH_PUBKEY_free(dhpubkey);
+  // EVP_PKEY_free(evppubkey);
+
+  LOGDH(" after evp free DH ptr is %p\n", dhimpl->m_dh);
+  *pLen = len;
+  return pubkey;
+}
+
+void gf_setPublicKeyOther(void *dhCtx, const unsigned char *pubkey,
+                          int length) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  if (dhimpl->m_pubKeyOther != nullptr) {
+    BN_free(dhimpl->m_pubKeyOther);
+    dhimpl->m_pubKeyOther = nullptr;
+  }
+
+  const unsigned char *temp = pubkey;
+  DH_PUBKEY *dhpubkey = d2i_DH_PUBKEY(nullptr, &temp, length);
+  LOGDH(" setPubKeyOther: after d2i_dhpubkey ptr is %p\n", dhpubkey);
+  EVP_PKEY *evppkey = DH_PUBKEY_get(dhpubkey);
+  LOGDH(" setPubKeyOther: after dhpubkey get evp ptr is %p\n", evppkey);
+  LOGDH(" setPubKeyOther: before BNdup ptr is %p\n", dhimpl->m_pubKeyOther);
+
+  const BIGNUM *pub_key, *priv_key;
+  DH *dh = EVP_PKEY_get1_DH(evppkey);
+  DH_get0_key(dh, &pub_key, &priv_key);
+  dhimpl->m_pubKeyOther = BN_dup(pub_key);
+  LOGDH(" setPubKeyOther: after BNdup ptr is %p\n", dhimpl->m_pubKeyOther);
+  EVP_PKEY_free(evppkey);
+  DH_PUBKEY_free(dhpubkey);
+
+  int codes = 0;
+  DH_check_pub_key(dhimpl->m_dh, dhimpl->m_pubKeyOther, &codes);
+  LOGDH(" DHInit: DH check_pub_key codes is 0x%04X\n", codes);
+}
+
+void gf_computeSharedSecret(void *dhCtx) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  LOGDH("COMPUTE: DH ptr %p, pubkeyOther ptr %p", dhimpl->m_dh,
+        dhimpl->m_pubKeyOther);
+
+  LOGDH("DHcomputeKey DHSize is %d", DH_size(dhimpl->m_dh));
+  DH_compute_key(dhimpl->m_key, dhimpl->m_pubKeyOther, dhimpl->m_dh);
+  LOGDH("DHcomputeKey : Compute err(%d): %s", ERR_get_error(),
+        ERR_error_string(ERR_get_error(), nullptr));
+}
+
+int DHImpl::setSkAlgo(const char *skalgo) {
+  int errCode = DH_ERR_NO_ERROR;
+
+  std::string inAlgo(skalgo);
+  size_t colIdx = inAlgo.find(':');
+  std::string algoStr =
+      (colIdx == std::string::npos) ? inAlgo : inAlgo.substr(0, colIdx);
+  int keySize = 0;
+
+  // Convert input algo to lower case to support case insensitivity
+  for (unsigned int i = 0; i < algoStr.size(); i++) {
+    algoStr[i] = tolower(algoStr[i]);
+  }
+
+  if (algoStr == "aes") {
+    keySize = (colIdx == std::string::npos)
+                  ? 128
+                  : atoi(inAlgo.substr(colIdx + 1).c_str());
+    if (keySize == 128 || keySize == 192 || keySize == 256) {
+      m_skAlgo = "AES";
+      m_keySize = keySize;
+    } else {
+      return DH_ERR_ILLEGAL_KEYSIZE;
+    }
+  } else if (algoStr == "blowfish") {
+    keySize = (colIdx == std::string::npos)
+                  ? 128
+                  : atoi(inAlgo.substr(colIdx + 1).c_str());
+    if (keySize >= 128 && keySize <= 448) {
+      m_skAlgo = "Blowfish";
+      m_keySize = keySize;
+    } else {
+      return DH_ERR_ILLEGAL_KEYSIZE;
+    }
+  } else if (algoStr == "desede") {  // No keysize should be given
+    if (colIdx == std::string::npos) {
+      m_skAlgo = "DESede";
+      m_keySize = 192;
+    } else {
+      return DH_ERR_ILLEGAL_KEYSIZE;
+    }
+  } else {
+    return DH_ERR_UNSUPPORTED_ALGO;
+  }
+
+  LOGDH(" DH: Got SK algo as %s", m_skAlgo.c_str());
+  LOGDH(" DH: Got keySize as %d", m_keySize);
+
+  return errCode;
+}
+
+const EVP_CIPHER *DHImpl::getCipherFunc() {
+  if (m_skAlgo == "AES") {
+    if (m_keySize == 192) {
+      return EVP_aes_192_cbc();
+    } else if (m_keySize == 256) {
+      return EVP_aes_256_cbc();
+    } else {  // Default
+      return EVP_aes_128_cbc();
+    }
+  } else if (m_skAlgo == "Blowfish") {
+    return EVP_bf_cbc();
+  } else if (m_skAlgo == "DESede") {
+    return EVP_des_ede3_cbc();
+  } else {
+    LOGDH("ERROR: Unsupported DH Algorithm");
+    return nullptr;
+  }
+}
+
+unsigned char *gf_encryptDH(void *dhCtx, const unsigned char *cleartext,
+                            int len, int *retLen) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  // Validation
+  if (cleartext == nullptr || len < 1 || retLen == nullptr) {
+    return nullptr;
+  }
+
+  LOGDH(" DH: gf_encryptDH using sk algo: %s, Keysize: %d",
+        dhimpl->m_skAlgo.c_str(), dhimpl->m_keySize);
+
+  auto ciphertext = std::unique_ptr<unsigned char[]>(
+      new unsigned char[len + 50]);  // give enough room for padding
+  int outlen, tmplen;
+  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+  const EVP_CIPHER *cipherFunc = dhimpl->getCipherFunc();
+
+  // init openssl cipher context
+  if (dhimpl->m_skAlgo == "AES") {
+    int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+    EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+                       dhimpl->m_key + keySize);
+  } else if (dhimpl->m_skAlgo == "Blowfish") {
+    int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+    EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, nullptr,
+                       dhimpl->m_key + keySize);
+    EVP_CIPHER_CTX_set_key_length(ctx, keySize);
+    LOGDH("DHencrypt: BF keysize is %d", keySize);
+    EVP_EncryptInit_ex(ctx, nullptr, nullptr, dhimpl->m_key, nullptr);
+  } else if (dhimpl->m_skAlgo == "DESede") {
+    EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+                       dhimpl->m_key + 24);
+  }
+
+  if (!EVP_EncryptUpdate(ctx, ciphertext.get(), &outlen, cleartext, len)) {
+    LOGDH(" DHencrypt: enc update ret nullptr");
+    return nullptr;
+  }
+  /* Buffer passed to EVP_EncryptFinal() must be after data just
+   * encrypted to avoid overwriting it.
+   */
+  tmplen = 0;
+
+  if (!EVP_EncryptFinal_ex(ctx, ciphertext.get() + outlen, &tmplen)) {
+    LOGDH("DHencrypt: enc final ret nullptr");
+    return nullptr;
+  }
+
+  outlen += tmplen;
+
+  EVP_CIPHER_CTX_free(ctx);
+
+  LOGDH("DHencrypt: in len is %d, out len is %d", len, outlen);
+
+  *retLen = outlen;
+  return ciphertext.release();
+}
+
+unsigned char *gf_decryptDH(void *dhCtx, const unsigned char *cleartext,
+                            int len, int *retLen) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  // Validation
+  if (cleartext == nullptr || len < 1 || retLen == nullptr) {
+    return nullptr;
+  }
+
+  LOGDH(" DH: gf_encryptDH using sk algo: %s, Keysize: %d",
+        dhimpl->m_skAlgo.c_str(), dhimpl->m_keySize);
+
+  auto ciphertext = std::unique_ptr<unsigned char[]>(
+      new unsigned char[len + 50]);  // give enough room for padding
+  int outlen, tmplen;
+  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+  auto cipherFunc = dhimpl->getCipherFunc();
+
+  // init openssl cipher context
+  if (dhimpl->m_skAlgo == "AES") {
+    int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+    EVP_DecryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+                       dhimpl->m_key + keySize);
+  } else if (dhimpl->m_skAlgo == "Blowfish") {
+    int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+    EVP_DecryptInit_ex(ctx, cipherFunc, nullptr, nullptr,
+                       dhimpl->m_key + keySize);
+    EVP_CIPHER_CTX_set_key_length(ctx, keySize);
+    LOGDH("DHencrypt: BF keysize is %d", keySize);
+    EVP_DecryptInit_ex(ctx, nullptr, nullptr, dhimpl->m_key, nullptr);
+  } else if (dhimpl->m_skAlgo == "DESede") {
+    EVP_DecryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+                       dhimpl->m_key + 24);
+  }
+
+  if (!EVP_DecryptUpdate(ctx, ciphertext.get(), &outlen, cleartext, len)) {
+    LOGDH(" DHencrypt: enc update ret nullptr");
+    return nullptr;
+  }
+  /* Buffer passed to EVP_EncryptFinal() must be after data just
+   * encrypted to avoid overwriting it.
+   */
+  tmplen = 0;
+
+  if (!EVP_DecryptFinal_ex(ctx, ciphertext.get() + outlen, &tmplen)) {
+    LOGDH("DHencrypt: enc final ret nullptr");
+    return nullptr;
+  }
+
+  outlen += tmplen;
+
+  EVP_CIPHER_CTX_free(ctx);
+
+  LOGDH("DHencrypt: in len is %d, out len is %d", len, outlen);
+
+  *retLen = outlen;
+  return ciphertext.release();
+}
+
+// std::shared_ptr<CacheableBytes> decrypt(const uint8_t * ciphertext, int len)
+// {
+//  LOGDH("DH: Used unimplemented decrypt!");
+//  return nullptr;
+//}
+
+bool gf_verifyDH(void *dhCtx, const char *subject,
+                 const unsigned char *challenge, int challengeLen,
+                 const unsigned char *response, int responseLen, int *reason) {
+  DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+  LOGDH(" In Verify - looking for subject %s", subject);
+
+  EVP_PKEY *evpkey = nullptr;
+  X509 *cert = nullptr;
+
+  char *certsubject = nullptr;
+
+  int32_t count = static_cast<int32_t>(dhimpl->m_serverCerts.size());
+  if (count == 0) {
+    *reason = DH_ERR_NO_CERTIFICATES;
+    return false;
+  }
+
+  for (int item = 0; item < count; item++) {
+    certsubject = X509_NAME_oneline(
+        X509_get_subject_name(dhimpl->m_serverCerts[item]), nullptr, 0);
+
+    // Ignore first letter for comparision, openssl adds / before subject name
+    // e.g. /CN=geode1
+    if (strcmp(certsubject + 1, subject) == 0) {
+      evpkey = X509_get_pubkey(dhimpl->m_serverCerts[item]);
+      cert = dhimpl->m_serverCerts[item];
+      LOGDH("Found subject [%s] in stored certificates", certsubject);
+      break;
+    }
+  }
+
+  if (evpkey == nullptr || cert == nullptr) {
+    *reason = DH_ERR_SUBJECT_NOT_FOUND;
+    LOGDH("Certificate not found!");
+    return false;
+  }
+
+  const ASN1_OBJECT *macobj;
+  const X509_ALGOR *algorithm = nullptr;
+  X509_ALGOR_get0(&macobj, nullptr, nullptr, algorithm);
+  if (algorithm == nullptr) {
+    LOGDH("algo is null \n");
+  }
+
+  const EVP_MD *signatureDigest = EVP_get_digestbyobj(macobj);
+  LOGDH("after EVP_get_digestbyobj  :  err(%d): %s", ERR_get_error(),
+        ERR_error_string(ERR_get_error(), nullptr));
+  EVP_MD_CTX *signatureCtx = EVP_MD_CTX_new();
+
+  int result1 = EVP_VerifyInit_ex(signatureCtx, signatureDigest, nullptr);
+  LOGDH("after EVP_VerifyInit_ex ret %d : err(%d): %s", result1,
+        ERR_get_error(), ERR_error_string(ERR_get_error(), nullptr));
+  LOGDH(" Result of VerifyInit is %s \n", ERR_lib_error_string(result1));
+  LOGDH(" Result of VerifyInit is %s \n", ERR_func_error_string(result1));
+  LOGDH(" Result of VerifyInit is %s \n", ERR_reason_error_string(result1));
+
+  LOGDH(" Result of VerifyInit is %d", result1);
+
+  int result2 = EVP_VerifyUpdate(signatureCtx, challenge, challengeLen);
+  LOGDH(" Result of VerifyUpdate is %d", result2);
+
+  int result3 = EVP_VerifyFinal(signatureCtx, response, responseLen, evpkey);
+  LOGDH(" Result of VerifyFinal is %d", result3);
+
+  bool result = (result1 == 1 && result2 == 1 && result3 == 1);
+
+  EVP_MD_CTX_free(signatureCtx);
+
+  if (result == false) {
+    *reason = DH_ERR_INVALID_SIGN;
+  }
+
+  return result;
+}
+
+int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey) {
+  DH_PUBKEY *pk = nullptr;
+  X509_ALGOR *a;
+  ASN1_OBJECT *o;
+  unsigned char *s, *p = nullptr;
+  int i;
+  ASN1_INTEGER *asn1int = nullptr;
+  DH *dh = EVP_PKEY_get1_DH(pkey);
+
+  if (x == nullptr) return (0);
+
+  if ((pk = DH_PUBKEY_new()) == nullptr) goto err;
+  a = pk->algor;
+
+  LOGDH(" key type for OBJ NID is %d", EVP_PKEY_base_id(pkey));
+
+  /* set the algorithm id */
+  if ((o = OBJ_nid2obj(EVP_PKEY_base_id(pkey))) == nullptr) goto err;
+  ASN1_OBJECT_free(a->algorithm);
+  a->algorithm = o;
+
+  /* Set the parameter list */
+  if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
+    if ((a->parameter == nullptr) || (a->parameter->type != V_ASN1_NULL)) {
+      ASN1_TYPE_free(a->parameter);
+      if (!(a->parameter = ASN1_TYPE_new())) {
+        X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+        goto err;
+      }
+      a->parameter->type = V_ASN1_NULL;
+    }
+  } else if (EVP_PKEY_base_id(pkey) == EVP_PKEY_DH) {
+    unsigned char *pp;
+    ASN1_TYPE_free(a->parameter);
+    if ((i = i2d_DHparams(dh, nullptr)) <= 0) goto err;
+    if (!(p = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i)))) {
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    pp = p;
+    i2d_DHparams(dh, &pp);
+    if (!(a->parameter = ASN1_TYPE_new())) {
+      OPENSSL_free(p);
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    a->parameter->type = V_ASN1_SEQUENCE;
+    if (!(a->parameter->value.sequence = ASN1_STRING_new())) {
+      OPENSSL_free(p);
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    if (!ASN1_STRING_set(a->parameter->value.sequence, p, i)) {
+      OPENSSL_free(p);
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    OPENSSL_free(p);
+  } else if (1) {
+    X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM);
+    goto err;
+  }
+
+  const BIGNUM *pub_key, *priv_key;
+  DH_get0_key(dh, &pub_key, &priv_key);
+
+  asn1int = BN_to_ASN1_INTEGER(pub_key, nullptr);
+  if ((i = i2d_ASN1_INTEGER(asn1int, nullptr)) <= 0) goto err;
+  if ((s = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i + 1))) ==
+      nullptr) {
+    X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+  p = s;
+  i2d_ASN1_INTEGER(asn1int, &p);
+  if (!ASN1_BIT_STRING_set(static_cast<ASN1_STRING *>(pk->public_key), s, i)) {
+    X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+  /* Set number of unused bits to zero */
+  pk->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+  pk->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+  OPENSSL_free(s);
+
+  if (*x != nullptr) DH_PUBKEY_free(*x);
+
+  *x = pk;
+
+  return 1;
+err:
+  if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+  if (pk != nullptr) DH_PUBKEY_free(pk);
+  return 0;
+}
+
+EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key) {
+  EVP_PKEY *ret = nullptr;
+  decltype(asn1_string_st::length) j;
+  const unsigned char *p;
+  const unsigned char *cp;
+  X509_ALGOR *a;
+  ASN1_INTEGER *asn1int = nullptr;
+
+  if (key == nullptr) {
+    if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+    if (ret != nullptr) EVP_PKEY_free(ret);
+    return (nullptr);
+  }
+
+  if (key->pkey != nullptr) {
+    EVP_PKEY_up_ref(key->pkey);
+    return (key->pkey);
+  }
+
+  if (key->public_key == nullptr) {
+    if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+    if (ret != nullptr) EVP_PKEY_free(ret);
+    return (nullptr);
+  }
+
+  if ((ret = EVP_PKEY_new()) == nullptr) {
+    X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+    if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+    if (ret != nullptr) EVP_PKEY_free(ret);
+    return (nullptr);
+  }
+
+  LOGDH(" DHPUBKEY evppkey type is %d", EVP_PKEY_base_id(ret));
+
+  /* the parameters must be extracted before the public key */
+
+  a = key->algor;
+
+  if (EVP_PKEY_base_id(ret) == EVP_PKEY_DH) {
+    if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) {
+      if ((EVP_PKEY_set1_DH(ret, DH_new())) == 0) {
+        X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+        if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+        if (ret != nullptr) EVP_PKEY_free(ret);
+        return (nullptr);
+      }
+      cp = p = a->parameter->value.sequence->data;
+      j = a->parameter->value.sequence->length;
+      DH *dh = EVP_PKEY_get1_DH(ret);
+      if (!d2i_DHparams(&dh, &cp, j)) {
+        if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+        if (ret != nullptr) EVP_PKEY_free(ret);
+        return (nullptr);
+      }
+    }
+  }
+
+  p = key->public_key->data;
+  j = key->public_key->length;
+
+  asn1int = d2i_ASN1_INTEGER(nullptr, &p, j);
+  LOGDH("after d2i asn1 integer ptr is %p", asn1int);
+
+  DH *dh = EVP_PKEY_get1_DH(ret);
+  DH_set0_key(dh, ASN1_INTEGER_to_BN(asn1int, nullptr), nullptr);
+  // LOGDH(" after asn1int to bn ptr is %p", ret->pkey.dh->pub_key);
+
+  key->pkey = ret;
+  EVP_PKEY_up_ref(ret);
+
+  if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+  return (ret);
+}
diff --git a/cryptoimpl/DHImpl.hpp b/cryptoimpl/DHImpl.hpp
new file mode 100644
index 0000000..94b49a5
--- /dev/null
+++ b/cryptoimpl/DHImpl.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+#ifndef GEODE_CRYPTOIMPL_DHIMPL_H_
+#define GEODE_CRYPTOIMPL_DHIMPL_H_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openssl/asn1t.h>
+#include <openssl/dh.h>
+#include <openssl/x509.h>
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "cryptoimpl_export.h"
+
+#define DH_ERR_NO_ERROR 0
+#define DH_ERR_UNSUPPORTED_ALGO 1
+#define DH_ERR_ILLEGAL_KEYSIZE 2
+#define DH_ERR_SUBJECT_NOT_FOUND 3
+#define DH_ERR_NO_CERTIFICATES 4
+#define DH_ERR_INVALID_SIGN 5
+
+#ifdef _DEBUG
+#define LOGDH printf
+#else
+#define LOGDH(...)
+#endif
+
+//  We need to declare our own structures and macros for
+// DH public key x509 encoding because it's not available in
+// OpenSSL yet.
+typedef struct DH_pubkey_st {
+  X509_ALGOR* algor;
+  ASN1_BIT_STRING* public_key;
+  EVP_PKEY* pkey;
+} DH_PUBKEY;
+
+extern "C" {
+CRYPTOIMPL_EXPORT int gf_initDhKeys(void** dhCtx, const char* dhAlgo,
+                                    const char* ksPath);
+CRYPTOIMPL_EXPORT void gf_clearDhKeys(void* dhCtx);
+CRYPTOIMPL_EXPORT unsigned char* gf_getPublicKey(void* dhCtx, int* len);
+CRYPTOIMPL_EXPORT void gf_setPublicKeyOther(void* dhCtx,
+                                            const unsigned char* pubkey,
+                                            int length);
+CRYPTOIMPL_EXPORT void gf_computeSharedSecret(void* dhCtx);
+CRYPTOIMPL_EXPORT unsigned char* gf_encryptDH(void* dhCtx,
+                                              const unsigned char* cleartext,
+                                              int len, int* retLen);
+CRYPTOIMPL_EXPORT unsigned char* gf_decryptDH(void* dhCtx,
+                                              const unsigned char* cleartext,
+                                              int len, int* retLen);
+CRYPTOIMPL_EXPORT bool gf_verifyDH(void* dhCtx, const char* subject,
+                                   const unsigned char* challenge,
+                                   int challengeLen,
+                                   const unsigned char* response,
+                                   int responseLen, int* reason);
+}
+
+class DHImpl {
+ public:
+  DH* m_dh;
+  std::string m_skAlgo;
+  int m_keySize;
+  BIGNUM* m_pubKeyOther;
+  unsigned char m_key[128];
+  std::vector<X509*> m_serverCerts;
+
+  const EVP_CIPHER* getCipherFunc();
+  int setSkAlgo(const char* skalgo);
+
+  DHImpl() : m_dh(nullptr), m_keySize(0), m_pubKeyOther(nullptr) {
+    /* adongre
+     * CID 28924: Uninitialized scalar field (UNINIT_CTOR)
+     */
+    std::memset(m_key, 0, sizeof(m_key));
+  }
+  static bool m_init;
+};
+
+bool DHImpl::m_init = false;
+
+#endif  // GEODE_CRYPTOIMPL_DHIMPL_H_
diff --git a/templates/security/CMakeLists.txt b/dhimpl/CMakeLists.txt
similarity index 72%
copy from templates/security/CMakeLists.txt
copy to dhimpl/CMakeLists.txt
index 36ce124..538b9f9 100644
--- a/templates/security/CMakeLists.txt
+++ b/dhimpl/CMakeLists.txt
@@ -13,34 +13,33 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-cmake_minimum_required(VERSION 3.10)
-project(templates.security LANGUAGES CXX)
+project(DHImpl LANGUAGES CXX)
 
-add_library(securityImpl SHARED
-  UserPasswordAuthInit.cpp
-  UserPasswordAuthInit.hpp
-  CMakeLists.txt.forInstall
+add_library(DHImpl SHARED
+  DHImpl.cpp
+  DHImpl.hpp
 )
 
-set_target_properties(securityImpl PROPERTIES
+set_target_properties(DHImpl PROPERTIES
   FOLDER cpp/test/integration
 )
 
 include(GenerateExportHeader)
-generate_export_header(securityImpl)
+generate_export_header(DHImpl)
 
-target_include_directories(securityImpl
+target_include_directories(DHImpl
   PUBLIC
     $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
 )
 
-target_link_libraries(securityImpl
+target_link_libraries(DHImpl
   PUBLIC
     apache-geode
     OpenSSL::Crypto
+    c++11
   PRIVATE
     openssl-compat
     _WarningsAsError
 )
 
-add_clangformat(securityImpl)
+add_clangformat(DHImpl)
diff --git a/dhimpl/DHImpl.cpp b/dhimpl/DHImpl.cpp
new file mode 100644
index 0000000..3b7ea74
--- /dev/null
+++ b/dhimpl/DHImpl.cpp
@@ -0,0 +1,612 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DHImpl.hpp"
+
+#include <openssl/aes.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include <cctype>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+
+static DH *m_dh = nullptr;
+static std::string m_skAlgo;
+static int m_keySize = 0;
+static BIGNUM *m_pubKeyOther = nullptr;
+static unsigned char m_key[128] = {0};
+static std::vector<X509 *> m_serverCerts;
+
+static const char *dhP =
+    "13528702063991073999718992897071702177131142188276542919088770094024269"
+    "73079899070080419278066109785292538223079165925365098181867673946"
+    "34756714063947534092593553024224277712367371302394452615862654308"
+    "11180902979719649450105660478776364198726078338308557022096810447"
+    "3500348898008043285865193451061481841186553";
+
+static const int dhL = 1023;
+
+static int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey);
+static EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key);
+static const EVP_CIPHER *getCipherFunc();
+static int setSkAlgo(const char *skalgo);
+
+ASN1_SEQUENCE(
+    DH_PUBKEY) = {ASN1_SIMPLE(DH_PUBKEY, algor, X509_ALGOR),
+                  ASN1_SIMPLE(DH_PUBKEY, public_key,
+                              ASN1_BIT_STRING)} ASN1_SEQUENCE_END(DH_PUBKEY)
+
+    // This gives us the i2d/d2i x.509 (ASN1 DER) encode/decode functions
+    IMPLEMENT_ASN1_FUNCTIONS(DH_PUBKEY)
+
+    // Returns Error code
+    int gf_initDhKeys(const char *dhAlgo, const char *ksPath) {
+  int errorCode = DH_ERR_NO_ERROR;  // No error;
+
+  // ksPath can be null
+  if (m_dh || !dhAlgo || strlen(dhAlgo) == 0) {
+    return errorCode;
+  }
+
+  // set the symmetric cipher algorithm name
+  errorCode = setSkAlgo(dhAlgo);
+  if (errorCode != DH_ERR_NO_ERROR) {
+    return errorCode;
+  }
+
+  // do add-all here or outside in DS::connect?
+  OpenSSL_add_all_algorithms();
+  ERR_load_crypto_strings();
+
+  m_dh = DH_new();
+
+  BIGNUM *pbn = nullptr;
+  BIGNUM *gbn = nullptr;
+  DH_get0_pqg(m_dh, const_cast<const BIGNUM **>(&pbn), nullptr,
+              const_cast<const BIGNUM **>(&gbn));
+  BN_dec2bn(&pbn, dhP);
+
+  LOGDH(" DHInit: P ptr is %p", pbn);
+  LOGDH(" DHInit: G ptr is %p", gbn);
+  LOGDH(" DHInit: length is %d", DH_get_length(m_dh));
+
+  BN_dec2bn(&gbn, dhP);
+
+  DH_set_length(m_dh, dhL);
+
+  DH_generate_key(m_dh);
+
+  const BIGNUM *pub_key, *priv_key;
+  DH_get0_key(m_dh, &pub_key, &priv_key);
+
+  int codes = 0;
+  DH_check(m_dh, &codes);
+  LOGDH(" DHInit: DH_check codes is 0x%04X", codes);
+  LOGDH(" DHInit: DH_size is %d", DH_size(m_dh));
+
+  // load the server's RSA public key for server authentication
+  // note that OpenSSL 0.9.8g has a bug where it can read only the first one in
+  // the keystore
+
+  LOGDH(" Loading keystore...");
+
+  if (ksPath == nullptr || strlen(ksPath) == 0) {
+    LOGDH("Property \"security-client-kspath\" 's value is nullptr.");
+    return errorCode;
+  }
+  FILE *keyStoreFP = nullptr;
+  keyStoreFP = fopen(ksPath, "r");
+
+  LOGDH(" kspath is [%s]", ksPath);
+  LOGDH(" keystore FILE ptr is %p", keyStoreFP);
+
+  // Read from pem file and put into.
+  X509 *cert = nullptr;
+  do {
+    cert = PEM_read_X509(keyStoreFP, nullptr, nullptr, nullptr);
+
+    if (cert != nullptr) {
+      m_serverCerts.push_back(cert);
+    }
+  } while (cert != nullptr);
+
+  LOGDH(" Total certificats imported # %zd", m_serverCerts.size());
+
+  fclose(keyStoreFP);
+
+  return errorCode;
+}
+
+void gf_clearDhKeys(void) {
+  if (m_dh != nullptr) {
+    DH_free(m_dh);
+    m_dh = nullptr;
+  }
+
+  std::vector<X509 *>::const_iterator iter;
+  for (iter = m_serverCerts.begin(); iter != m_serverCerts.end(); ++iter) {
+    X509_free(*iter);
+  }
+
+  m_serverCerts.clear();
+
+  if (m_pubKeyOther != nullptr) {
+    BN_free(m_pubKeyOther);
+    m_pubKeyOther = nullptr;
+  }
+
+  memset(m_key, 0, 128);
+
+  EVP_cleanup();
+}
+
+unsigned char *gf_getPublicKey(int *pLen) {
+  const BIGNUM *pub_key, *priv_key;
+  DH_get0_key(m_dh, &pub_key, &priv_key);
+
+  if (pub_key == nullptr || pLen == nullptr) {
+    return nullptr;
+  }
+
+  int numBytes = BN_num_bytes(pub_key);
+
+  if (numBytes <= 0) {
+    return nullptr;
+  }
+
+  EVP_PKEY *evppubkey = EVP_PKEY_new();
+  LOGDH(" before assign DH ptr is %p", m_dh);
+  EVP_PKEY_assign_DH(evppubkey, m_dh);
+  LOGDH(" after assign DH ptr is %p", m_dh);
+  DH_PUBKEY *dhpubkey = nullptr;
+  DH_PUBKEY_set(&dhpubkey, evppubkey);
+  int len = i2d_DH_PUBKEY(dhpubkey, nullptr);
+  unsigned char *pubkey = new unsigned char[len];
+  unsigned char *temp = pubkey;
+  //
+  //  Note, this temp pointer is needed because OpenSSL increments the pointer
+  //  passed in
+  // so that following encoding can be done at the current output location,
+  // this will cause a problem if we try to free the pointer which has been
+  // moved by OpenSSL.
+  //
+  i2d_DH_PUBKEY(dhpubkey, &temp);
+
+  //  TODO: uncomment this - causing problem in computeSecret?
+  // DH_PUBKEY_free(dhpubkey);
+  // EVP_PKEY_free(evppubkey);
+
+  LOGDH(" after evp free DH ptr is %p", m_dh);
+  *pLen = len;
+  return pubkey;
+}
+
+void gf_setPublicKeyOther(const unsigned char *pubkey, int length) {
+  if (m_pubKeyOther != nullptr) {
+    BN_free(m_pubKeyOther);
+    m_pubKeyOther = nullptr;
+  }
+
+  const unsigned char *temp = pubkey;
+  DH_PUBKEY *dhpubkey = d2i_DH_PUBKEY(nullptr, &temp, length);
+  LOGDH(" setPubKeyOther: after d2i_dhpubkey ptr is %p", dhpubkey);
+  EVP_PKEY *evppkey = DH_PUBKEY_get(dhpubkey);
+  LOGDH(" setPubKeyOther: after dhpubkey get evp ptr is %p", evppkey);
+  LOGDH(" setPubKeyOther: before BNdup ptr is %p", m_pubKeyOther);
+
+  const BIGNUM *pub_key, *priv_key;
+  DH *dh = EVP_PKEY_get1_DH(evppkey);
+  DH_get0_key(dh, &pub_key, &priv_key);
+  m_pubKeyOther = BN_dup(pub_key);
+  LOGDH(" setPubKeyOther: after BNdup ptr is %p", m_pubKeyOther);
+  EVP_PKEY_free(evppkey);
+  DH_PUBKEY_free(dhpubkey);
+
+#ifdef _DEBUG
+  int codes = 0;
+  int ret = DH_check_pub_key(m_dh, m_pubKeyOther, &codes);
+  LOGDH(" DHInit: DH_check_pub_key ret %d", ret);
+  LOGDH(" DHInit: DH check_pub_key codes is 0x%04X", codes);
+#endif
+}
+
+void gf_computeSharedSecret() {
+  LOGDH("COMPUTE: DH ptr %p, pubkeyOther ptr %p", m_dh, m_pubKeyOther);
+
+  LOGDH("DHcomputeKey DHSize is %d", DH_size(m_dh));
+#ifdef _DEBUG
+  int ret = DH_compute_key(m_key, m_pubKeyOther, m_dh);
+  LOGDH("DHcomputeKey ret %d : Compute err(%d): %s", ret, ERR_get_error(),
+        ERR_error_string(ERR_get_error(), nullptr));
+#endif
+}
+
+int setSkAlgo(const char *skalgo) {
+  int errCode = DH_ERR_NO_ERROR;
+
+  std::string inAlgo(skalgo);
+  size_t colIdx = inAlgo.find(':');
+  std::string algoStr =
+      (colIdx == std::string::npos) ? inAlgo : inAlgo.substr(0, colIdx);
+  int keySize = 0;
+
+  // Convert input algo to lower case to support case insensitivity
+  for (unsigned int i = 0; i < algoStr.size(); i++) {
+    algoStr[i] = tolower(algoStr[i]);
+  }
+
+  if (algoStr == "aes") {
+    keySize = (colIdx == std::string::npos)
+                  ? 128
+                  : atoi(inAlgo.substr(colIdx + 1).c_str());
+    if (keySize == 128 || keySize == 192 || keySize == 256) {
+      m_skAlgo = "AES";
+      m_keySize = keySize;
+    } else {
+      return DH_ERR_ILLEGAL_KEYSIZE;
+    }
+  } else if (algoStr == "blowfish") {
+    keySize = (colIdx == std::string::npos)
+                  ? 128
+                  : atoi(inAlgo.substr(colIdx + 1).c_str());
+    if (keySize >= 128 && keySize <= 448) {
+      m_skAlgo = "Blowfish";
+      m_keySize = keySize;
+    } else {
+      return DH_ERR_ILLEGAL_KEYSIZE;
+    }
+  } else if (algoStr == "desede") {  // No keysize should be given
+    if (colIdx == std::string::npos) {
+      m_skAlgo = "DESede";
+      m_keySize = 192;
+    } else {
+      return DH_ERR_ILLEGAL_KEYSIZE;
+    }
+  } else {
+    return DH_ERR_UNSUPPORTED_ALGO;
+  }
+
+  LOGDH(" DH: Got SK algo as %s", m_skAlgo.c_str());
+  LOGDH(" DH: Got keySize as %d", m_keySize);
+
+  return errCode;
+}
+
+const EVP_CIPHER *getCipherFunc() {
+  if (m_skAlgo == "AES") {
+    if (m_keySize == 192) {
+      return EVP_aes_192_cbc();
+    } else if (m_keySize == 256) {
+      return EVP_aes_256_cbc();
+    } else {  // Default
+      return EVP_aes_128_cbc();
+    }
+  } else if (m_skAlgo == "Blowfish") {
+    return EVP_bf_cbc();
+  } else if (m_skAlgo == "DESede") {
+    return EVP_des_ede3_cbc();
+  } else {
+    LOGDH("ERROR: Unsupported DH Algorithm");
+    return nullptr;
+  }
+}
+
+unsigned char *gf_encryptDH(const unsigned char *cleartext, int len,
+                            int *retLen) {
+  // Validation
+  if (cleartext == nullptr || len < 1 || retLen == nullptr) {
+    return nullptr;
+  }
+
+  LOGDH(" DH: gf_encryptDH using sk algo: %s, Keysize: %d", m_skAlgo.c_str(),
+        m_keySize);
+
+  auto ciphertext = std::unique_ptr<unsigned char[]>(
+      new unsigned char[len + 50]);  // give enough room for padding
+  int outlen, tmplen;
+  auto ctx = EVP_CIPHER_CTX_new();
+
+  auto cipherFunc = getCipherFunc();
+
+  // init openssl cipher context
+  if (m_skAlgo == "AES") {
+    int keySize = m_keySize > 128 ? m_keySize / 8 : 16;
+    EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, m_key, m_key + keySize);
+  } else if (m_skAlgo == "Blowfish") {
+    int keySize = m_keySize > 128 ? m_keySize / 8 : 16;
+    EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, nullptr, m_key + keySize);
+    EVP_CIPHER_CTX_set_key_length(ctx, keySize);
+    LOGDH("DHencrypt: BF keysize is %d", keySize);
+    EVP_EncryptInit_ex(ctx, nullptr, nullptr, m_key, nullptr);
+  } else if (m_skAlgo == "DESede") {
+    EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, m_key, m_key + 24);
+  }
+
+  if (!EVP_EncryptUpdate(ctx, ciphertext.get(), &outlen, cleartext, len)) {
+    LOGDH(" DHencrypt: enc update ret nullptr");
+    return nullptr;
+  }
+  /* Buffer passed to EVP_EncryptFinal() must be after data just
+   * encrypted to avoid overwriting it.
+   */
+  tmplen = 0;
+
+  if (!EVP_EncryptFinal_ex(ctx, ciphertext.get() + outlen, &tmplen)) {
+    LOGDH("DHencrypt: enc final ret nullptr");
+    return nullptr;
+  }
+
+  outlen += tmplen;
+
+  EVP_CIPHER_CTX_cleanup(ctx);
+
+  LOGDH("DHencrypt: in len is %d, out len is %d", len, outlen);
+
+  *retLen = outlen;
+  return ciphertext.release();
+}
+
+// std::shared_ptr<CacheableBytes> decrypt(const uint8_t * ciphertext, int
+// len)
+// {
+//  LOGDH("DH: Used unimplemented decrypt!");
+//  return nullptr;
+//}
+
+bool gf_verifyDH(const char *subject, const unsigned char *challenge,
+                 int challengeLen, const unsigned char *response,
+                 int responseLen, int *reason) {
+  LOGDH(" In Verify - looking for subject %s", subject);
+
+  EVP_PKEY *evpkey = nullptr;
+  X509 *cert = nullptr;
+
+  char *certsubject = nullptr;
+
+  int32_t count = static_cast<int32_t>(m_serverCerts.size());
+  if (count == 0) {
+    *reason = DH_ERR_NO_CERTIFICATES;
+    return false;
+  }
+
+  for (int item = 0; item < count; item++) {
+    certsubject = X509_NAME_oneline(X509_get_subject_name(m_serverCerts[item]),
+                                    nullptr, 0);
+
+    // Ignore first letter for comparision, openssl adds / before subject name
+    // e.g. /CN=geode1
+    if (strcmp(certsubject + 1, subject) == 0) {
+      evpkey = X509_get_pubkey(m_serverCerts[item]);
+      cert = m_serverCerts[item];
+      LOGDH("Found subject [%s] in stored certificates", certsubject);
+      break;
+    }
+  }
+
+  if (evpkey == nullptr || cert == nullptr) {
+    *reason = DH_ERR_SUBJECT_NOT_FOUND;
+    LOGDH("Certificate not found!");
+    return false;
+  }
+
+  const ASN1_OBJECT *macobj;
+  const X509_ALGOR *algorithm = nullptr;
+  X509_ALGOR_get0(&macobj, nullptr, nullptr, algorithm);
+
+  const EVP_MD *signatureDigest = EVP_get_digestbyobj(macobj);
+  EVP_MD_CTX *signatureCtx = EVP_MD_CTX_new();
+
+  int result1 = EVP_VerifyInit_ex(signatureCtx, signatureDigest, nullptr);
+  LOGDH(" Result of VerifyInit is %d", result1);
+
+  int result2 = EVP_VerifyUpdate(signatureCtx, challenge, challengeLen);
+  LOGDH(" Result of VerifyUpdate is %d", result2);
+
+  int result3 = EVP_VerifyFinal(signatureCtx, response, responseLen, evpkey);
+  LOGDH(" Result of VerifyFinal is %d", result3);
+
+  bool result = (result1 == 1 && result2 == 1 && result3 == 1);
+
+  EVP_MD_CTX_free(signatureCtx);
+
+  if (result == false) {
+    *reason = DH_ERR_INVALID_SIGN;
+  }
+
+  return result;
+}
+
+int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey) {
+  DH_PUBKEY *pk = nullptr;
+  X509_ALGOR *a;
+  ASN1_OBJECT *o;
+  unsigned char *s, *p = nullptr;
+  int i;
+  ASN1_INTEGER *asn1int = nullptr;
+  DH *dh = EVP_PKEY_get1_DH(pkey);
+
+  if (x == nullptr) return (0);
+
+  if ((pk = DH_PUBKEY_new()) == nullptr) goto err;
+  a = pk->algor;
+
+  LOGDH(" key type for OBJ NID is %d", EVP_PKEY_base_id(pkey));
+
+  /* set the algorithm id */
+  if ((o = OBJ_nid2obj(EVP_PKEY_base_id(pkey))) == nullptr) goto err;
+  ASN1_OBJECT_free(a->algorithm);
+  a->algorithm = o;
+
+  /* Set the parameter list */
+  if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
+    if ((a->parameter == nullptr) || (a->parameter->type != V_ASN1_NULL)) {
+      ASN1_TYPE_free(a->parameter);
+      if (!(a->parameter = ASN1_TYPE_new())) {
+        X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+        goto err;
+      }
+      a->parameter->type = V_ASN1_NULL;
+    }
+  } else if (EVP_PKEY_base_id(pkey) == EVP_PKEY_DH) {
+    unsigned char *pp;
+
+    const BIGNUM *pub_key, *priv_key;
+    DH_get0_key(dh, &pub_key, &priv_key);
+    ASN1_TYPE_free(a->parameter);
+    if ((i = i2d_DHparams(dh, nullptr)) <= 0) goto err;
+    if (!(p = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i)))) {
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    pp = p;
+    i2d_DHparams(dh, &pp);
+    if (!(a->parameter = ASN1_TYPE_new())) {
+      OPENSSL_free(p);
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    a->parameter->type = V_ASN1_SEQUENCE;
+    if (!(a->parameter->value.sequence = ASN1_STRING_new())) {
+      OPENSSL_free(p);
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    if (!ASN1_STRING_set(a->parameter->value.sequence, p, i)) {
+      OPENSSL_free(p);
+      X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    OPENSSL_free(p);
+  } else if (1) {
+    X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM);
+    goto err;
+  }
+
+  const BIGNUM *pub_key, *priv_key;
+  DH_get0_key(dh, &pub_key, &priv_key);
+
+  asn1int = BN_to_ASN1_INTEGER(pub_key, nullptr);
+  if ((i = i2d_ASN1_INTEGER(asn1int, nullptr)) <= 0) goto err;
+  if ((s = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i + 1))) ==
+      nullptr) {
+    X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+  p = s;
+  i2d_ASN1_INTEGER(asn1int, &p);
+  if (!ASN1_BIT_STRING_set(pk->public_key, s, i)) {
+    X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+  /* Set number of unused bits to zero */
+  pk->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+  pk->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+  OPENSSL_free(s);
+
+  if (*x != nullptr) DH_PUBKEY_free(*x);
+
+  *x = pk;
+
+  return 1;
+err:
+  if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+  if (pk != nullptr) DH_PUBKEY_free(pk);
+  return 0;
+}
+
+EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key) {
+  EVP_PKEY *ret = nullptr;
+  decltype(asn1_string_st::length) j;
+  const unsigned char *p;
+  const unsigned char *cp;
+  X509_ALGOR *a;
+  ASN1_INTEGER *asn1int = nullptr;
+
+  if (key == nullptr) {
+    return (nullptr);
+  }
+
+  if (key->pkey != nullptr) {
+    EVP_PKEY_up_ref(key->pkey);
+    return (key->pkey);
+  }
+
+  if (key->public_key == nullptr) {
+    if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+    if (ret != nullptr) EVP_PKEY_free(ret);
+    return (nullptr);
+  }
+
+  if ((ret = EVP_PKEY_new()) == nullptr) {
+    X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+    if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+    if (ret != nullptr) EVP_PKEY_free(ret);
+    return (nullptr);
+  }
+
+  LOGDH(" DHPUBKEY evppkey type is %d", EVP_PKEY_base_id(ret));
+
+  /* the parameters must be extracted before the public key */
+
+  a = key->algor;
+
+  if (EVP_PKEY_base_id(ret) == EVP_PKEY_DH) {
+    if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) {
+      if ((EVP_PKEY_set1_DH(ret, DH_new())) == 0) {
+        X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+        if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+        if (ret != nullptr) EVP_PKEY_free(ret);
+        return (nullptr);
+      }
+      cp = p = a->parameter->value.sequence->data;
+      j = a->parameter->value.sequence->length;
+      DH *dh = EVP_PKEY_get1_DH(ret);
+      if (!d2i_DHparams(&dh, &cp, j)) {
+        if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+        if (ret != nullptr) EVP_PKEY_free(ret);
+        return (nullptr);
+      }
+    }
+  }
+
+  p = key->public_key->data;
+  j = key->public_key->length;
+
+  asn1int = d2i_ASN1_INTEGER(nullptr, &p, j);
+  LOGDH("after d2i asn1 integer ptr is %p", asn1int);
+
+  DH *dh = EVP_PKEY_get1_DH(ret);
+  DH_set0_key(dh, ASN1_INTEGER_to_BN(asn1int, nullptr), nullptr);
+
+  key->pkey = ret;
+  EVP_PKEY_up_ref(key->pkey);
+
+  if (asn1int) {
+    ASN1_INTEGER_free(asn1int);
+  }
+  return (ret);
+}
diff --git a/dhimpl/DHImpl.hpp b/dhimpl/DHImpl.hpp
new file mode 100644
index 0000000..38ba3c8
--- /dev/null
+++ b/dhimpl/DHImpl.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#ifndef GEODE_DHIMPL_DHIMPL_H_
+#define GEODE_DHIMPL_DHIMPL_H_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openssl-compat.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+
+#include <string>
+#include <vector>
+
+#include "dhimpl_export.h"
+
+#define DH_ERR_NO_ERROR 0
+#define DH_ERR_UNSUPPORTED_ALGO 1
+#define DH_ERR_ILLEGAL_KEYSIZE 2
+#define DH_ERR_SUBJECT_NOT_FOUND 3
+#define DH_ERR_NO_CERTIFICATES 4
+#define DH_ERR_INVALID_SIGN 5
+
+#ifdef _DEBUG
+#define LOGDH printf
+#else
+#define LOGDH(...)
+#endif
+
+//  We need to declare our own structures and macros for
+// DH public key x509 encoding because it's not available in
+// OpenSSL yet.
+typedef struct DH_pubkey_st {
+  X509_ALGOR* algor;
+  ASN1_BIT_STRING* public_key;
+  EVP_PKEY* pkey;
+} DH_PUBKEY;
+
+extern "C" {
+DHIMPL_EXPORT int gf_initDhKeys(const char* dhAlgo, const char* ksPath);
+DHIMPL_EXPORT void gf_clearDhKeys(void);
+DHIMPL_EXPORT unsigned char* gf_getPublicKey(int* len);
+DHIMPL_EXPORT void gf_setPublicKeyOther(const unsigned char* pubkey,
+                                        int length);
+DHIMPL_EXPORT void gf_computeSharedSecret(void);
+DHIMPL_EXPORT unsigned char* gf_encryptDH(const unsigned char* cleartext,
+                                          int len, int* retLen);
+DHIMPL_EXPORT bool gf_verifyDH(const char* subject,
+                               const unsigned char* challenge, int challengeLen,
+                               const unsigned char* response, int responseLen,
+                               int* reason);
+}
+
+#endif  // GEODE_DHIMPL_DHIMPL_H_
diff --git a/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb b/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb
index c9314f5..caa55ad 100644
--- a/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb
+++ b/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb
@@ -256,7 +256,7 @@ See [SSL Client/Server Communication](../security/sslclientserver.html).
 </tr>
 <tr class="odd">
 <td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
 <td>null</td>
 </tr>
 <tr class="even">
diff --git a/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb b/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb
index b7f73c6..81eba0e 100644
--- a/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb
+++ b/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb
@@ -32,7 +32,7 @@ The table describes the security-related system properties in the `geode.propert
 <tbody>
 <tr class="odd">
 <td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
 </tr>
 <tr class="even">
 <td><code class="ph codeph">security-client-kspath</code></td>
diff --git a/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb b/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb
index 6191c59..ae58777 100644
--- a/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb
+++ b/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb
@@ -256,7 +256,7 @@ See [SSL Client/Server Communication](../security/sslclientserver.html).
 </tr>
 <tr class="odd">
 <td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
 <td>null</td>
 </tr>
 <tr class="even">
diff --git a/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb b/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb
index b7f73c6..81eba0e 100644
--- a/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb
+++ b/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb
@@ -32,7 +32,7 @@ The table describes the security-related system properties in the `geode.propert
 <tbody>
 <tr class="odd">
 <td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
 </tr>
 <tr class="even">
 <td><code class="ph codeph">security-client-kspath</code></td>
diff --git a/templates/security/CMakeLists.txt b/templates/security/CMakeLists.txt
index 36ce124..0bf308e 100644
--- a/templates/security/CMakeLists.txt
+++ b/templates/security/CMakeLists.txt
@@ -17,6 +17,8 @@ cmake_minimum_required(VERSION 3.10)
 project(templates.security LANGUAGES CXX)
 
 add_library(securityImpl SHARED
+  PkcsAuthInit.cpp
+  PkcsAuthInit.hpp
   UserPasswordAuthInit.cpp
   UserPasswordAuthInit.hpp
   CMakeLists.txt.forInstall
diff --git a/templates/security/PkcsAuthInit.cpp b/templates/security/PkcsAuthInit.cpp
new file mode 100644
index 0000000..1150289
--- /dev/null
+++ b/templates/security/PkcsAuthInit.cpp
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PkcsAuthInit.hpp"
+
+#include <openssl-compat.h>
+
+#include <cstdio>
+#include <string>
+
+#include <geode/CacheableBuiltins.hpp>
+#include <geode/ExceptionTypes.hpp>
+#include <geode/Properties.hpp>
+
+#include "geode/CacheableBuiltins.hpp"
+#include "geode/ExceptionTypes.hpp"
+#include "geode/Properties.hpp"
+#include "securityimpl_export.h"
+
+namespace apache {
+namespace geode {
+namespace client {
+
+extern "C" {
+SECURITYIMPL_EXPORT AuthInitialize* createPKCSAuthInitInstance() {
+  return new PKCSAuthInit();
+}
+
+uint8_t* createSignature(EVP_PKEY* key, X509* cert,
+                         const unsigned char* inputBuffer,
+                         uint32_t inputBufferLen, unsigned int* signatureLen) {
+  if (!key || !cert || !inputBuffer) {
+    return nullptr;
+  }
+
+  const ASN1_OBJECT* macobj;
+  X509_ALGOR_get0(&macobj, nullptr, nullptr, nullptr);
+  const EVP_MD* signatureDigest = EVP_get_digestbyobj(macobj);
+
+  EVP_MD_CTX* signatureCtx = EVP_MD_CTX_new();
+  uint8_t* signatureData = new uint8_t[EVP_PKEY_size(key)];
+
+  bool result = (EVP_SignInit_ex(signatureCtx, signatureDigest, nullptr) &&
+                 EVP_SignUpdate(signatureCtx, inputBuffer, inputBufferLen) &&
+                 EVP_SignFinal(signatureCtx, signatureData, signatureLen, key));
+
+  EVP_MD_CTX_free(signatureCtx);
+  if (result) {
+    return signatureData;
+  }
+  return nullptr;
+}
+
+bool readPKCSPublicPrivateKey(FILE* keyStoreFP, const char* keyStorePassword,
+                              EVP_PKEY** outPrivateKey, X509** outCertificate) {
+  PKCS12* p12;
+
+  if (!keyStoreFP || !keyStorePassword || (keyStorePassword[0] == '\0')) {
+    return (false);
+  }
+
+  p12 = d2i_PKCS12_fp(keyStoreFP, nullptr);
+
+  if (p12) {
+    return (false);
+  }
+
+  if (!PKCS12_parse(p12, keyStorePassword, outPrivateKey, outCertificate,
+                    nullptr)) {
+    return (false);
+  }
+
+  PKCS12_free(p12);
+
+  return (outPrivateKey && outCertificate);
+}
+
+bool openSSLInit() {
+  OpenSSL_add_all_algorithms();
+  ERR_load_crypto_strings();
+
+  return true;
+}
+
+static bool s_initDone = openSSLInit();
+}
+// end of extern "C"
+
+std::shared_ptr<Properties> PKCSAuthInit::getCredentials(
+    const std::shared_ptr<Properties>& securityprops, const std::string&) {
+  if (!s_initDone) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "OpenSSL initialization failed.");
+  }
+  if (securityprops == nullptr || securityprops->getSize() <= 0) {
+    throw AuthenticationRequiredException(
+        "PKCSAuthInit::getCredentials: "
+        "No security-* properties are set.");
+  }
+
+  auto keyStoreptr = securityprops->find(KEYSTORE_FILE_PATH);
+
+  const char* keyStorePath = keyStoreptr->value().c_str();
+
+  if (!keyStorePath) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "key-store file path property KEYSTORE_FILE_PATH not set.");
+  }
+
+  auto aliasptr = securityprops->find(KEYSTORE_ALIAS);
+
+  const char* alias = aliasptr->value().c_str();
+
+  if (!alias) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "key-store alias property KEYSTORE_ALIAS not set.");
+  }
+
+  auto keyStorePassptr = securityprops->find(KEYSTORE_PASSWORD);
+
+  const char* keyStorePass = keyStorePassptr->value().c_str();
+
+  if (!keyStorePass) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "key-store password property KEYSTORE_PASSWORD not set.");
+  }
+
+  FILE* keyStoreFP = fopen(keyStorePath, "r");
+  if (!keyStoreFP) {
+    char msg[1024];
+    sprintf(msg, "PKCSAuthInit::getCredentials: Unable to open keystore %s",
+            keyStorePath);
+    throw AuthenticationFailedException(msg);
+  }
+
+  EVP_PKEY* privateKey = nullptr;
+  X509* cert = nullptr;
+
+  /* Read the Public and Private Key from keystore in file */
+  if (!readPKCSPublicPrivateKey(keyStoreFP, keyStorePass, &privateKey, &cert)) {
+    fclose(keyStoreFP);
+    char msg[1024];
+    sprintf(msg,
+            "PKCSAuthInit::getCredentials: Unable to read PKCS "
+            "public key from %s",
+            keyStorePath);
+    throw AuthenticationFailedException(msg);
+  }
+
+  fclose(keyStoreFP);
+
+  unsigned int lengthEncryptedData = 0;
+
+  auto signatureData = createSignature(
+      privateKey, cert, reinterpret_cast<const unsigned char*>(alias),
+      static_cast<uint32_t>(strlen(alias)), &lengthEncryptedData);
+  EVP_PKEY_free(privateKey);
+  X509_free(cert);
+  if (signatureData == nullptr) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "Unable to create signature");
+  }
+  auto signatureValPtr = CacheableBytes::create(
+      std::vector<int8_t>(signatureData, signatureData + lengthEncryptedData));
+
+  auto credentials = Properties::create();
+  credentials->insert(KEYSTORE_ALIAS, alias);
+  credentials->insert(CacheableString::create(SIGNATURE_DATA), signatureValPtr);
+  return credentials;
+}
+}  // namespace client
+}  // namespace geode
+}  // namespace apache
diff --git a/templates/security/PkcsAuthInit.hpp b/templates/security/PkcsAuthInit.hpp
new file mode 100644
index 0000000..5e3c94a
--- /dev/null
+++ b/templates/security/PkcsAuthInit.hpp
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PKCSAUTHINIT__
+#define __PKCSAUTHINIT__
+
+#include <cstdio>
+#include <cstdlib>
+
+#pragma error_messages(off, macroredef)
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#pragma error_messages(on, macroredef)
+
+#include <geode/AuthInitialize.hpp>
+
+/**
+ * @file
+ */
+
+const char KEYSTORE_FILE_PATH[] = "security-keystorepath";
+
+const char KEYSTORE_ALIAS[] = "security-alias";
+
+const char KEYSTORE_PASSWORD[] = "security-keystorepass";
+
+const char SIGNATURE_DATA[] = "security-signature";
+
+namespace apache {
+namespace geode {
+namespace client {
+
+/**
+ * @class PKCSAuthInit Implementation PKCSAuthInit.hpp
+ * PKCSAuthInit API for getCredentials.
+ * The PKCSAuthInit class derives from AuthInitialize base class.
+ * It uses the provided alias, password and corresponding keystore to obtain the
+ * private key and
+ * encrypts data. This data is sent to server for authentication.
+ *
+ */
+
+class PKCSAuthInit : public AuthInitialize {
+ public:
+  PKCSAuthInit() = default;
+  ~PKCSAuthInit() noexcept override = default;
+
+  /**@brief initialize with the given set of security properties
+   * and return the credentials for the client as properties.
+   * @param props the set of security properties provided to the
+   * <code>DistributedSystem.connect</code> method
+   * @param server it is the ID of the current endpoint.
+   * The format expected is "host:port".
+   * @returns the credentials to be used for the given <code>server</code>
+   */
+  std::shared_ptr<Properties> getCredentials(
+      const std::shared_ptr<Properties>& securityprops,
+      const std::string& server) override;
+
+  /**
+   * @brief Invoked before the cache goes down.
+   */
+  void close() override { return; }
+
+  /**
+   * @brief private members
+   */
+
+ private:
+};
+}  // namespace client
+}  // namespace geode
+}  // namespace apache
+#endif  //__PKCSAUTHINIT__
diff --git a/tests/cli/CMakeLists.txt b/tests/cli/CMakeLists.txt
index 1d81e62..973a690 100644
--- a/tests/cli/CMakeLists.txt
+++ b/tests/cli/CMakeLists.txt
@@ -16,6 +16,7 @@
 cmake_minimum_required(VERSION 3.10)
 project(nativeclient.tests LANGUAGES NONE)
 
+add_subdirectory(PkcsWrapper)
 add_subdirectory(QueryHelper)
 add_subdirectory(PdxClassLibrary)
 
diff --git a/tests/cli/NewFwkLib/CacheServer.cs b/tests/cli/NewFwkLib/CacheServer.cs
index afa1025..8365786 100644
--- a/tests/cli/NewFwkLib/CacheServer.cs
+++ b/tests/cli/NewFwkLib/CacheServer.cs
@@ -4351,6 +4351,59 @@ private void checkUpdatedValue(TKey key, TVal value)
           };
         }
       }
+     else
+      {
+        FwkInfo("Security Scheme is {0}", SecurityCode);
+        for (Int32 i = 0; i < userSize; i++)
+        {
+          Properties<string, string> userProp = new Properties<string, string>();
+          PkcsAuthInit pkcs = new PkcsAuthInit();
+          if (pkcs == null) {
+            FwkException("NULL PKCS Credential Generator");
+          }
+          userName = (String)userList[i];
+          string dataDir = Util.GetFwkLogDir(Util.SystemType) + "/data";
+          userProp.Insert(KeyStoreFileProp, GetKeyStoreDir(dataDir) +
+            userName + ".keystore");
+          userProp.Insert(KeyStoreAliasProp, userName);
+          userProp.Insert(KeyStorePasswordProp, "geode");
+          //mu_cache = pool.CreateSecureUserCache(userProp);
+          //IRegionService mu_cache = CacheHelper<TKey, TVal>.DCache.CreateAuthenticatedView(userProp, pool.Name);
+          IRegionService mu_cache = CacheHelper<TKey, TVal>.DCache.CreateAuthenticatedView(
+            CacheHelper<TKey, TVal>.GetPkcsCredentialsForMU(
+              pkcs.GetCredentials(userProp, "0:0")), pool.Name);
+          authCacheMap.Add(userName, mu_cache);
+          IRegion<TKey, TVal> m_region = mu_cache.GetRegion<TKey, TVal>(regionName);
+          proxyRegionMap.Add(userName, m_region);
+          Dictionary<string, int> opMAP = new Dictionary<string, int>();
+          Dictionary<string, int> expMAP = new Dictionary<string, int>();
+          operationMap[userName] =  opMAP;
+          exceptionMap[userName] = expMAP;
+          Utility.GetClientProperties(gen.AuthInit, null, ref userProp);
+          FwkInfo("Security properties entries: {0}", userProp);
+         switch (i)
+          {
+            case 0:
+            case 1:
+              setAdminRole(userName);
+              break;
+            case 2:
+            case 3:
+            case 4:
+              setReaderRole(userName);
+              break;
+            case 5:
+            case 6:
+            case 7:
+              setWriterRole(userName);
+              break;
+            case 8:
+            case 9:
+              setQueryRole(userName);
+              break;
+          };
+        }
+      }
     }
 
     public string GetKeyStoreDir(string dataDir)
diff --git a/tests/cli/NewFwkLib/NewFwkLib.csproj.in b/tests/cli/NewFwkLib/NewFwkLib.csproj.in
index 71abeff..f64d801 100644
--- a/tests/cli/NewFwkLib/NewFwkLib.csproj.in
+++ b/tests/cli/NewFwkLib/NewFwkLib.csproj.in
@@ -125,6 +125,11 @@
       <Project>{5055633B-6D1C-488D-B934-1AC482C915F7}</Project>
       <Name>PdxVersion2Lib</Name>
     </ProjectReference>
+    <ProjectReference Include="..\PkcsWrapper\PkcsWrapper.vcxproj">
+      <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+      <Name>PkcsWrapper</Name>
+    </ProjectReference>
     <ProjectReference Include="..\QueryHelper\QueryWrapper.vcxproj">
       <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
       <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
diff --git a/tests/cli/PkcsWrapper/CMakeLists.txt b/tests/cli/PkcsWrapper/CMakeLists.txt
new file mode 100644
index 0000000..366f185
--- /dev/null
+++ b/tests/cli/PkcsWrapper/CMakeLists.txt
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+cmake_minimum_required(VERSION 3.10)
+project(PkcsWrapper LANGUAGES CXX)
+
+add_library(PkcsWrapper SHARED 
+  PkcsAuthInitMN.cpp
+  PkcsAuthInitMN.hpp
+)
+
+target_compile_options(${PROJECT_NAME}
+  PRIVATE
+	# disabled warnings
+	/wd4947
+)
+
+set_target_properties(PkcsWrapper PROPERTIES
+  VS_GLOBAL_CLRSupport "true"
+  VS_GLOBAL_KEYWORD "ManagedCProj"
+  VS_GLOBAL_PROJECT_TYPES "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
+  VS_GLOBAL_ROOTNAMESPACE "Apache.Geode.Client.Tests"
+  VS_DOTNET_REFERENCES "System;System.Xml"
+)
+
+target_link_libraries(PkcsWrapper
+  PUBLIC 
+    # Apache.Geode #- Causes include of .lib
+  PRIVATE
+	c++cli
+    c++11
+    security
+)
+
+# Makes project only reference, no .lib.
+add_dependencies(PkcsWrapper Apache.Geode)
+
+include_directories(${CMAKE_SOURCE_DIR}/clicache/src)
+include_directories(${CMAKE_SOURCE_DIR}/tests/cpp/security)
+
+string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SHARED_LINKER_FLAGS_STRONG_KEY}")
+
+# For Visual Studio organization
+set_target_properties(PkcsWrapper PROPERTIES FOLDER cli/test/integration)
diff --git a/tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp b/tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp
new file mode 100644
index 0000000..86c1772
--- /dev/null
+++ b/tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PkcsAuthInitMN.hpp"
+#include "begin_native.hpp"
+#include <geode/Properties.hpp>
+#include "end_native.hpp"
+
+using namespace System;
+using namespace Apache::Geode::Client::Tests;
+using namespace Apache::Geode::Client;
+
+PkcsAuthInit::PkcsAuthInit() 
+{
+
+}
+
+PkcsAuthInit::~PkcsAuthInit() 
+{
+
+}
+
+void PkcsAuthInit::Close() 
+{
+}
+
+//generic <class TPropKey, class TPropValue>
+Apache::Geode::Client::Properties<String^, Object^>^
+PkcsAuthInit::GetCredentials(
+  Apache::Geode::Client::Properties<String^, String^> ^props, System::String ^server)
+{
+  throw gcnew System::NotImplementedException();
+}
diff --git a/tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp b/tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp
new file mode 100644
index 0000000..249863a
--- /dev/null
+++ b/tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include "native_shared_ptr.hpp"
+#include "PkcsAuthInit.hpp"
+
+using namespace System;
+
+using namespace Apache::Geode::Client;
+
+namespace Apache
+{
+  namespace Geode
+  {
+    namespace Client
+    {
+      namespace Tests
+      {
+        public ref class PkcsAuthInit sealed
+          : public Apache::Geode::Client::IAuthInitialize
+        {
+        public:
+
+          PkcsAuthInit();
+
+          ~PkcsAuthInit();
+
+          //generic <class TPropKey, class TPropValue>
+          virtual Apache::Geode::Client::Properties<String^, Object^> ^
+            GetCredentials(
+            Apache::Geode::Client::Properties<String^, String^>^ props, String^ server);
+
+          virtual void Close();
+
+        internal:
+          PkcsAuthInit(const std::shared_ptr<apache::geode::client::PKCSAuthInitInternal>& nativeptr)
+          {
+            m_nativeptr = gcnew native_shared_ptr<apache::geode::client::PKCSAuthInitInternal>(nativeptr);
+          }
+
+        private:
+          native_shared_ptr<apache::geode::client::PKCSAuthInitInternal>^ m_nativeptr;
+        };
+      }
+    }
+  }
+}
+
diff --git a/tests/cli/SecurityUtil/CredentialGeneratorN.cs b/tests/cli/SecurityUtil/CredentialGeneratorN.cs
index 3f5185c..0471ea2 100644
--- a/tests/cli/SecurityUtil/CredentialGeneratorN.cs
+++ b/tests/cli/SecurityUtil/CredentialGeneratorN.cs
@@ -112,6 +112,8 @@ namespace Apache.Geode.Client.Tests
           return null;
         case ClassCode.LDAP:
           return new LDAPCredentialGenerator();
+        case ClassCode.PKCS:
+          return new PKCSCredentialGenerator(isMultiUser);
         case ClassCode.SSL:
           // return new SSLCredentialGenerator();
           return null;
diff --git a/tests/cli/SecurityUtil/SecurityUtil.csproj.in b/tests/cli/SecurityUtil/SecurityUtil.csproj.in
index a6ae959..0ecf164 100644
--- a/tests/cli/SecurityUtil/SecurityUtil.csproj.in
+++ b/tests/cli/SecurityUtil/SecurityUtil.csproj.in
@@ -110,6 +110,7 @@
     <Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\CredentialGeneratorN.cs" />
     <Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\DummyAuthorization3N.cs" />
     <Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\LdapCredentialGeneratorN.cs" />
+    <Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\PKCSCredentialGeneratorN.cs" />
     <Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\XmlAuthzCredentialGeneratorN.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -117,6 +118,10 @@
       <Project>{796727E8-3A6A-46BE-A2DB-584A4774CD51}</Project>
       <Name>DUnitFramework</Name>
     </ProjectReference>
+    <ProjectReference Include="..\PkcsWrapper\PkcsWrapper.vcxproj">
+      <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
diff --git a/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs b/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs
index 29b1f7f..e10160a 100644
--- a/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs
+++ b/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs
@@ -143,6 +143,8 @@ namespace Apache.Geode.Client.Tests
           return GetDummyPrincipal(roleType, index);
         case CredentialGenerator.ClassCode.LDAP:
           return GetLdapPrincipal(roleType, index);
+        case CredentialGenerator.ClassCode.PKCS:
+          return GetPKCSPrincipal(roleType, index);
       }
       return null;
     }
@@ -174,6 +176,8 @@ namespace Apache.Geode.Client.Tests
           return GetDummyPrincipal(disallowedRoleType, index);
         case CredentialGenerator.ClassCode.LDAP:
           return GetLdapPrincipal(disallowedRoleType, index);
+        case CredentialGenerator.ClassCode.PKCS:
+          return GetPKCSPrincipal(disallowedRoleType, index);
       }
       return null;
     }
@@ -208,6 +212,14 @@ namespace Apache.Geode.Client.Tests
       return GetUserPrincipal(GetLdapUser(roleType, index));
     }
 
+    private Properties<string, string> GetPKCSPrincipal(Role roleType, int index)
+    {
+      string userName = GetLdapUser(roleType, index);
+      Properties<string, string> props = new Properties<string, string>();
+      props.Insert(PKCSCredentialGenerator.KeyStoreAliasProp, userName);
+      return props;
+    }
+
     private string GetLdapUser(Role roleType, int index)
     {
       const string userPrefix = "geode";
diff --git a/tests/cpp/security/CMakeLists.txt b/tests/cpp/security/CMakeLists.txt
index 8396cc2..cee20a6 100644
--- a/tests/cpp/security/CMakeLists.txt
+++ b/tests/cpp/security/CMakeLists.txt
@@ -24,6 +24,8 @@ add_library(security STATIC
   DummyCredentialGenerator3.hpp
   LdapUserCredentialGenerator.hpp
   NoopCredentialGenerator.hpp
+  PkcsAuthInit.cpp
+  PkcsAuthInit.hpp
   PkcsCredentialGenerator.hpp
   typedefs.hpp
   XmlAuthzCredentialGenerator.hpp
diff --git a/tests/cpp/security/PkcsAuthInit.cpp b/tests/cpp/security/PkcsAuthInit.cpp
new file mode 100644
index 0000000..9f75914
--- /dev/null
+++ b/tests/cpp/security/PkcsAuthInit.cpp
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PkcsAuthInit.hpp"
+
+#include <openssl-compat.h>
+
+#include <cstdio>
+#include <string>
+#include <util/Log.hpp>
+
+#include <geode/CacheableBuiltins.hpp>
+#include <geode/ExceptionTypes.hpp>
+#include <geode/Properties.hpp>
+
+#include "SerializationRegistry.hpp"
+#include "security_export.h"
+
+namespace apache {
+namespace geode {
+namespace client {
+std::shared_ptr<CacheableString> convertBytesToString(const uint8_t* bytes,
+                                                      int32_t length,
+                                                      size_t maxLength) {
+  if (bytes) {
+    std::string str;
+    size_t totalBytes = 0;
+    char byteStr[20];
+    for (int32_t index = 0; index < length; ++index) {
+      int len = sprintf(byteStr, "%d ", bytes[index]);
+      totalBytes += len;
+      // no use going beyond maxLength since LOG* methods will truncate
+      // in any case
+      if (maxLength > 0 && totalBytes > maxLength) {
+        break;
+      }
+      str.append(byteStr, len);
+    }
+    return CacheableString::create(str);
+  }
+  return CacheableString::create("");
+}
+
+extern "C" {
+SECURITY_EXPORT AuthInitialize* createPKCSAuthInitInstance() {
+  return new PKCSAuthInitInternal();
+}
+
+uint8_t* createSignature(EVP_PKEY* key, X509* cert,
+                         const unsigned char* inputBuffer,
+                         uint32_t inputBufferLen, unsigned int* signatureLen) {
+  if (!key || !cert || !inputBuffer) {
+    return nullptr;
+  }
+  const ASN1_OBJECT* macobj;
+  const X509_ALGOR* algorithm = nullptr;
+  X509_ALGOR_get0(&macobj, nullptr, nullptr, algorithm);
+  const EVP_MD* signatureDigest = EVP_get_digestbyobj(macobj);
+  EVP_MD_CTX* signatureCtx = EVP_MD_CTX_new();
+  auto signatureData =
+      std::unique_ptr<uint8_t[]>(new uint8_t[EVP_PKEY_size(key)]);
+  bool result =
+      (EVP_SignInit_ex(signatureCtx, signatureDigest, nullptr) &&
+       EVP_SignUpdate(signatureCtx, inputBuffer, inputBufferLen) &&
+       EVP_SignFinal(signatureCtx, signatureData.get(), signatureLen, key));
+  EVP_MD_CTX_free(signatureCtx);
+  if (result) {
+    return signatureData.release();
+  }
+  return nullptr;
+}
+
+bool readPKCSPublicPrivateKey(FILE* keyStoreFP, const char* keyStorePassword,
+                              EVP_PKEY** outPrivateKey, X509** outCertificate) {
+  PKCS12* p12;
+
+  if (!keyStoreFP || !keyStorePassword || (keyStorePassword[0] == '\0')) {
+    return (false);
+  }
+
+  p12 = d2i_PKCS12_fp(keyStoreFP, nullptr);
+
+  if (!p12) {
+    return (false);
+  }
+
+  if (!PKCS12_parse(p12, keyStorePassword, outPrivateKey, outCertificate,
+                    nullptr)) {
+    return (false);
+  }
+
+  PKCS12_free(p12);
+
+  return (outPrivateKey && outCertificate);
+}
+
+bool openSSLInit() {
+  OpenSSL_add_all_algorithms();
+  ERR_load_crypto_strings();
+
+  return true;
+}
+
+static bool s_initDone = openSSLInit();
+}
+// end of extern "C"
+std::shared_ptr<Properties> PKCSAuthInitInternal::getCredentials(
+    const std::shared_ptr<Properties>& securityprops, const std::string&) {
+  if (!s_initDone) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "OpenSSL initialization failed.");
+  }
+  if (securityprops == nullptr || securityprops->getSize() <= 0) {
+    throw AuthenticationRequiredException(
+        "PKCSAuthInit::getCredentials: "
+        "No security-* properties are set.");
+  }
+
+  auto keyStoreptr = securityprops->find(KEYSTORE_FILE_PATH1);
+
+  const char* keyStorePath = keyStoreptr->value().c_str();
+
+  if (!keyStorePath) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "key-store file path property KEYSTORE_FILE_PATH not set.");
+  }
+
+  auto aliasptr = securityprops->find(KEYSTORE_ALIAS1);
+
+  const char* alias = aliasptr->value().c_str();
+
+  if (!alias) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "key-store alias property KEYSTORE_ALIAS not set.");
+  }
+
+  auto keyStorePassptr = securityprops->find(KEYSTORE_PASSWORD1);
+
+  const char* keyStorePass = keyStorePassptr->value().c_str();
+
+  if (!keyStorePass) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "key-store password property KEYSTORE_PASSWORD not set.");
+  }
+
+  FILE* keyStoreFP = fopen(keyStorePath, "r");
+  if (!keyStoreFP) {
+    char msg[1024];
+    sprintf(msg, "PKCSAuthInit::getCredentials: Unable to open keystore %s",
+            keyStorePath);
+    throw AuthenticationFailedException(msg);
+  }
+
+  EVP_PKEY* privateKey = nullptr;
+  X509* cert = nullptr;
+
+  /* Read the Public and Private Key from keystore in file */
+  if (!readPKCSPublicPrivateKey(keyStoreFP, keyStorePass, &privateKey, &cert)) {
+    fclose(keyStoreFP);
+    char msg[1024];
+    sprintf(msg,
+            "PKCSAuthInit::getCredentials: Unable to read PKCS "
+            "public key from %s",
+            keyStorePath);
+    throw AuthenticationFailedException(msg);
+  }
+
+  fclose(keyStoreFP);
+  unsigned int lengthEncryptedData = 0;
+
+  auto signatureData = std::unique_ptr<uint8_t[]>(createSignature(
+      privateKey, cert, reinterpret_cast<const unsigned char*>(alias),
+      static_cast<uint32_t>(strlen(alias)), &lengthEncryptedData));
+  EVP_PKEY_free(privateKey);
+  X509_free(cert);
+  if (!signatureData) {
+    throw AuthenticationFailedException(
+        "PKCSAuthInit::getCredentials: "
+        "Unable to create signature");
+  }
+  std::shared_ptr<Cacheable> signatureValPtr;
+  if (m_stringCredentials) {
+    // convert signature bytes to base64
+    signatureValPtr =
+        convertBytesToString(signatureData.get(), lengthEncryptedData, 2048);
+    LOGINFO(" Converting CREDS to STRING: %s",
+            signatureValPtr->toString().c_str());
+  } else {
+    signatureValPtr = CacheableBytes::create(std::vector<int8_t>(
+        signatureData.get(), signatureData.get() + lengthEncryptedData));
+    LOGINFO(" Converting CREDS to BYTES: %s",
+            signatureValPtr->toString().c_str());
+  }
+  auto credentials = Properties::create();
+  credentials->insert(KEYSTORE_ALIAS1, alias);
+  credentials->insert(CacheableString::create(SIGNATURE_DATA1),
+                      signatureValPtr);
+  return credentials;
+}
+}  // namespace client
+}  // namespace geode
+}  // namespace apache
diff --git a/tests/cpp/security/PkcsAuthInit.hpp b/tests/cpp/security/PkcsAuthInit.hpp
new file mode 100644
index 0000000..3eb03da
--- /dev/null
+++ b/tests/cpp/security/PkcsAuthInit.hpp
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef GEODE_SECURITY_PKCSAUTHINIT_H_
+#define GEODE_SECURITY_PKCSAUTHINIT_H_
+
+#include <cstdio>
+#include <cstdlib>
+
+#pragma error_messages(off, macroredef)
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#pragma error_messages(on, macroredef)
+
+#include <geode/AuthInitialize.hpp>
+
+/**
+ * @file
+ */
+const char KEYSTORE_FILE_PATH1[] = "security-keystorepath";
+
+const char KEYSTORE_ALIAS1[] = "security-alias";
+
+const char KEYSTORE_PASSWORD1[] = "security-keystorepass";
+
+const char SIGNATURE_DATA1[] = "security-signature";
+
+namespace apache {
+namespace geode {
+namespace client {
+
+/**
+ * @class PKCSAuthInit Implementation PKCSAuthInit.hpp
+ * PKCSAuthInit API for getCredentials.
+ * The PKCSAuthInit class derives from AuthInitialize base class.
+ * It uses the provided alias, password and corresponding keystore to obtain the
+ * private key and
+ * encrypts data. This data is sent to server for authentication.
+ *
+ */
+
+class PKCSAuthInitInternal : public AuthInitialize {
+ public:
+  explicit PKCSAuthInitInternal(bool makeString = false)
+      : m_stringCredentials(makeString) {}
+  ~PKCSAuthInitInternal() noexcept override = default;
+
+  /**@brief initialize with the given set of security properties
+   * and return the credentials for the client as properties.
+   * @param props the set of security properties provided to the
+   * <code>DistributedSystem.connect</code> method
+   * @param server it is the ID of the current endpoint.
+   * The format expected is "host:port".
+   * @returns the credentials to be used for the given <code>server</code>
+   */
+  std::shared_ptr<Properties> getCredentials(
+      const std::shared_ptr<Properties>& securityprops,
+      const std::string& server) override;
+
+  /**
+   * @brief Invoked before the cache goes down.
+   */
+  void close() override { return; }
+
+  /**
+   * @brief private members
+   */
+
+ private:
+  bool m_stringCredentials;
+};
+}  // namespace client
+}  // namespace geode
+}  // namespace apache
+
+#endif  // GEODE_SECURITY_PKCSAUTHINIT_H_


Mime
View raw message