diff --git a/.github/workflows/build_and_test_clang_debug.yml b/.github/workflows/build_and_test_clang_debug.yml index ad46288759..3f3e4805eb 100644 --- a/.github/workflows/build_and_test_clang_debug.yml +++ b/.github/workflows/build_and_test_clang_debug.yml @@ -59,9 +59,6 @@ jobs: -DUSE_OPENTRACING=ON \ -DOMIT_TEST_OUTPUT=OFF\ -DKEEP_APOLLO_LOGS=TRUE\ - -DUSE_CRYPTOPP_HASH=TRUE\ - -DUSE_OPENSSL_SHA_256=FALSE\ - -DUSE_OPENSSL_SHA3_256=FALSE\ -DUSE_FAKE_CLOCK_IN_TIME_SERVICE=TRUE\" "\ && script -q -e -c "make test" - name: Prepare artifacts diff --git a/.github/workflows/build_and_test_clang_release.yml b/.github/workflows/build_and_test_clang_release.yml index e1ade905a1..65e6a0e50b 100644 --- a/.github/workflows/build_and_test_clang_release.yml +++ b/.github/workflows/build_and_test_clang_release.yml @@ -60,9 +60,6 @@ jobs: -DUSE_OPENTRACING=ON \ -DOMIT_TEST_OUTPUT=OFF\ -DKEEP_APOLLO_LOGS=TRUE\ - -DUSE_CRYPTOPP_HASH=TRUE\ - -DUSE_OPENSSL_SHA_256=FALSE\ - -DUSE_OPENSSL_SHA3_256=FALSE\ -DUSE_FAKE_CLOCK_IN_TIME_SERVICE=TRUE\" "\ && script -q -e -c "make test" - name: Prepare artifacts diff --git a/.github/workflows/build_and_test_gcc_debug.yml b/.github/workflows/build_and_test_gcc_debug.yml index f55ea78f1d..96a068ec6c 100644 --- a/.github/workflows/build_and_test_gcc_debug.yml +++ b/.github/workflows/build_and_test_gcc_debug.yml @@ -59,9 +59,6 @@ jobs: -DOMIT_TEST_OUTPUT=OFF\ -DKEEP_APOLLO_LOGS=TRUE\ -DRUN_APOLLO_TESTS=FALSE\ - -DUSE_CRYPTOPP_HASH=TRUE\ - -DUSE_OPENSSL_SHA_256=FALSE\ - -DUSE_OPENSSL_SHA3_256=FALSE\ -DUSE_FAKE_CLOCK_IN_TIME_SERVICE=TRUE\" "\ && script -q -e -c "make test" - name: Prepare artifacts diff --git a/.github/workflows/build_and_test_gcc_release.yml b/.github/workflows/build_and_test_gcc_release.yml index 20e71606c2..b7bfe63eb3 100644 --- a/.github/workflows/build_and_test_gcc_release.yml +++ b/.github/workflows/build_and_test_gcc_release.yml @@ -59,9 +59,6 @@ jobs: -DOMIT_TEST_OUTPUT=OFF\ -DKEEP_APOLLO_LOGS=TRUE\ -DRUN_APOLLO_TESTS=FALSE\ - -DUSE_CRYPTOPP_HASH=TRUE\ - -DUSE_OPENSSL_SHA_256=FALSE\ - -DUSE_OPENSSL_SHA3_256=FALSE\ -DUSE_FAKE_CLOCK_IN_TIME_SERVICE=TRUE\" "\ && script -q -e -c "make test" - name: Prepare artifacts diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index bcbcd734af..cffc519666 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -37,9 +37,6 @@ jobs: -DUSE_S3_OBJECT_STORE=TRUE \ -DUSE_OPENTRACING=ON \ -DOMIT_TEST_OUTPUT=OFF\ - -DUSE_CRYPTOPP_HASH=TRUE\ - -DUSE_OPENSSL_SHA_256=FALSE\ - -DUSE_OPENSSL_SHA3_256=FALSE\ -DUSE_FAKE_CLOCK_IN_TIME_SERVICE=TRUE\" "\ - name: Print failure info if: failure() diff --git a/CMakeLists.txt b/CMakeLists.txt index f03a0f30a2..5689c5d5bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,19 +114,6 @@ if(CODECOVERAGE) message( "-- Building with llvm Code Coverage Tools") endif() -if(USE_CRYPTOPP_HASH) - message("-- USE_CRYPTOPP_HASH Enabled") - string(APPEND CMAKE_CXX_FLAGS " -DUSE_CRYPTOPP_HASH") -elseif(USE_OPENSSL_SHA_256) - message("-- USE_OPENSSL_SHA_256 Enabled") - string(APPEND CMAKE_CXX_FLAGS " -DUSE_OPENSSL_SHA_256") -elseif(USE_OPENSSL_SHA3_256) - message("-- USE_OPENSSL_SHA3_256 Enabled") - string(APPEND CMAKE_CXX_FLAGS " -DUSE_OPENSSL_SHA3_256") -else() - message(FATAL_ERROR "None of the cryptographic hashing libraries are enabled.") -endif() - if(USE_S3_OBJECT_STORE) add_compile_definitions(USE_S3_OBJECT_STORE=1) endif() diff --git a/Makefile b/Makefile index 9d1af32722..c048fea1e0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CONCORD_BFT_DOCKER_REPO?=concordbft/ CONCORD_BFT_DOCKER_IMAGE?=concord-bft -CONCORD_BFT_DOCKER_IMAGE_VERSION?=0.41 +CONCORD_BFT_DOCKER_IMAGE_VERSION?=0.43 CONCORD_BFT_DOCKER_CONTAINER?=concord-bft CONCORD_BFT_DOCKERFILE?=Dockerfile @@ -57,9 +57,6 @@ CONCORD_BFT_CMAKE_TSAN?=FALSE CONCORD_BFT_CMAKE_CODECOVERAGE?=FALSE CONCORD_BFT_CMAKE_USE_FAKE_CLOCK_IN_TIME_SERVICE?=FALSE ENABLE_RESTART_RECOVERY_TESTS?=FALSE -CONCORD_BFT_CMAKE_USE_CRYPTOPP_HASH?=TRUE -CONCORD_BFT_CMAKE_USE_OPENSSL_SHA_256?=FALSE -CONCORD_BFT_CMAKE_USE_OPENSSL_SHA3_256?=FALSE ifeq (${CONCORD_BFT_CMAKE_ASAN},TRUE) CONCORD_BFT_CMAKE_CXX_FLAGS_RELEASE='-O0 -g' @@ -95,9 +92,6 @@ CONCORD_BFT_CMAKE_FLAGS?= \ -DCODECOVERAGE=${CONCORD_BFT_CMAKE_CODECOVERAGE} \ -DTXN_SIGNING_ENABLED=${CONCORD_BFT_CMAKE_TRANSACTION_SIGNING_ENABLED} \ -DENABLE_RESTART_RECOVERY_TESTS=${ENABLE_RESTART_RECOVERY_TESTS} - -DUSE_OPENSSL_SHA_256=${CONCORD_BFT_CMAKE_USE_OPENSSL_SHA_256} \ - -DUSE_OPENSSL_SHA3_256=${CONCORD_BFT_CMAKE_USE_OPENSSL_SHA3_256} \ - -DUSE_CRYPTOPP_HASH=${CONCORD_BFT_CMAKE_USE_CRYPTOPP_HASH} # The consistency parameter makes sense only at MacOS. # It is ignored at all other platforms. diff --git a/bftengine/src/bftengine/KeyExchangeManager.cpp b/bftengine/src/bftengine/KeyExchangeManager.cpp index ee48f89758..34e7093234 100644 --- a/bftengine/src/bftengine/KeyExchangeManager.cpp +++ b/bftengine/src/bftengine/KeyExchangeManager.cpp @@ -24,6 +24,8 @@ namespace bftEngine::impl { +using concord::util::crypto::KeyFormat; + KeyExchangeManager::KeyExchangeManager(InitData* id) : repID_{ReplicaConfig::instance().getreplicaId()}, clusterSize_{ReplicaConfig::instance().getnumReplicas()}, @@ -155,9 +157,8 @@ void KeyExchangeManager::exchangeTlsKeys(const std::string& type, const SeqNum& const std::string base_path = bftEngine::ReplicaConfig::instance().certificatesRootPath + "/" + std::to_string(repID_); std::string root_path = (use_unified_certs) ? base_path : base_path + "/" + type; - std::string cert_path = (use_unified_certs) ? root_path + "/node.cert" : root_path + "/" + type + ".cert"; - std::string prev_key_pem = concord::util::crypto::Crypto::instance() + std::string prev_key_pem = concord::util::cryptopp_utils::Crypto::instance() .RsaHexToPem(std::make_pair(SigManager::instance()->getSelfPrivKey(), "")) .first; auto cert = @@ -297,9 +298,7 @@ void KeyExchangeManager::onPublishClientsKeys(const std::string& keys, std::opti if (save) saveClientsPublicKeys(keys); } -void KeyExchangeManager::onClientPublicKeyExchange(const std::string& key, - concord::util::crypto::KeyFormat fmt, - NodeIdType clientId) { +void KeyExchangeManager::onClientPublicKeyExchange(const std::string& key, KeyFormat fmt, NodeIdType clientId) { LOG_INFO(KEY_EX_LOG, "key: " << key << " fmt: " << (uint16_t)fmt << " client: " << clientId); // persist a new key clientPublicKeyStore_->setClientPublicKey(clientId, key, fmt); @@ -308,7 +307,7 @@ void KeyExchangeManager::onClientPublicKeyExchange(const std::string& key, } void KeyExchangeManager::loadClientPublicKey(const std::string& key, - concord::util::crypto::KeyFormat fmt, + KeyFormat fmt, NodeIdType clientId, bool saveToReservedPages) { LOG_INFO(KEY_EX_LOG, "key: " << key << " fmt: " << (uint16_t)fmt << " client: " << clientId); diff --git a/bftengine/src/bftengine/SigManager.cpp b/bftengine/src/bftengine/SigManager.cpp index 271aa2cd57..00147626bd 100644 --- a/bftengine/src/bftengine/SigManager.cpp +++ b/bftengine/src/bftengine/SigManager.cpp @@ -20,14 +20,20 @@ #include "hex_tools.h" using namespace std; -// using concord::util::cryptopp_utils::RSASigner; -// using concord::util::cryptopp_utils::RSAVerifier; -using concord::util::openssl_utils::EdDSA_Signer; -using concord::util::openssl_utils::EdDSA_Verifier; namespace bftEngine { namespace impl { +#define RSA_Algo false + +#if RSA_Algo +using concord::util::cryptopp_utils::RSASigner; +using concord::util::cryptopp_utils::RSAVerifier; +#else +using concord::util::openssl_utils::EdDSA_Signer; +using concord::util::openssl_utils::EdDSA_Verifier; +#endif + concord::messages::keys_and_signatures::ClientsPublicKeys clientsPublicKeys_; std::string SigManager::getClientsPublicKeys() { @@ -140,8 +146,13 @@ SigManager::SigManager(PrincipalId myId, size_t numPublickeys = publickeys.size(); ConcordAssert(publicKeysMapping.size() >= numPublickeys); - if (!mySigPrivateKey.first.empty()) - mySigner_.reset(new concord::util::crypto::RSASigner(mySigPrivateKey.first.c_str(), mySigPrivateKey.second)); + if (!mySigPrivateKey.first.empty()) { +#if RSA_Algo + mySigner_.reset(new RSASigner(mySigPrivateKey.first.c_str(), mySigPrivateKey.second)); +#else + mySigner_.reset(new EdDSA_Signer(mySigPrivateKey.first, mySigPrivateKey.second)); +#endif + } for (const auto& p : publicKeysMapping) { ConcordAssert(verifiers_.count(p.first) == 0); ConcordAssert(p.second < numPublickeys); @@ -149,8 +160,11 @@ SigManager::SigManager(PrincipalId myId, auto iter = publicKeyIndexToVerifier.find(p.second); const auto& [key, format] = publickeys[p.second]; if (iter == publicKeyIndexToVerifier.end()) { +#if RSA_Algo + verifiers_[p.first] = std::make_shared(key.c_str(), format); +#else verifiers_[p.first] = std::make_shared(key, format); - // verifiers_[p.first] = std::make_shared(key.c_str(), format); +#endif publicKeyIndexToVerifier[p.second] = verifiers_[p.first]; } else { verifiers_[p.first] = iter->second; @@ -246,8 +260,7 @@ bool SigManager::verifySig( void SigManager::sign(const char* data, size_t dataLength, char* outSig, uint16_t outSigLength) const { std::string str_data(data, dataLength); - std::string sig; - sig = mySigner_->sign(str_data); + std::string sig = mySigner_->sign(str_data); outSigLength = sig.size(); std::memcpy(outSig, sig.c_str(), outSigLength); } @@ -259,8 +272,11 @@ void SigManager::setClientPublicKey(const std::string& key, PrincipalId id, conc if (replicasInfo_.isIdOfExternalClient(id) || replicasInfo_.isIdOfClientService(id)) { try { std::unique_lock lock(mutex_); - // verifiers_.insert_or_assign(id, std::make_shared(key.c_str(), format)); +#if RSA_Algo + verifiers_.insert_or_assign(id, std::make_shared(key.c_str(), format)); +#else verifiers_.insert_or_assign(id, std::make_shared(key, format)); +#endif } catch (const std::exception& e) { LOG_ERROR(KEY_EX_LOG, "failed to add a key for client: " << id << " reason: " << e.what()); throw; diff --git a/bftengine/src/preprocessor/tests/preprocessor_test.cpp b/bftengine/src/preprocessor/tests/preprocessor_test.cpp index 5bae8d0b97..28347b5f94 100644 --- a/bftengine/src/preprocessor/tests/preprocessor_test.cpp +++ b/bftengine/src/preprocessor/tests/preprocessor_test.cpp @@ -155,19 +155,20 @@ class DummyPreProcessor : public PreProcessor { }; // clang-format off -const vector eddsaPrivateKey = { //use different keys pair. - {"09a30490ebf6f6685556046f2497fd9c7df4a552998c9a9b6ebec742e8183174"}, - {"09a30490ebf6f6685556046f2497fd9c7df4a552998c9a9b6ebec742e8183174"}, - {"09a30490ebf6f6685556046f2497fd9c7df4a552998c9a9b6ebec742e8183174"}, - {"09a30490ebf6f6685556046f2497fd9c7df4a552998c9a9b6ebec742e8183174"}, - {"09a30490ebf6f6685556046f2497fd9c7df4a552998c9a9b6ebec742e8183174"} +const vector eddsaPrivateKey = { + {"61498efe1764b89357a02e2887d224154006ceacf26269f8695a4af561453eef"}, + {"247a74ab3620ec6b9f5feab9ee1f86521da3fa2804ad45bb5bf2c5b21ef105bc"}, + {"fb539bc3d66deda55524d903da26dbec1f4b6abf41ec5db521e617c64eb2c341"}, + {"55ea66e855b83ec4a02bd8fcce6bb4426ad3db2a842fa2a2a6777f13e40a4717"}, + {"f2f3d43da68329bfe31419636072e27cfd1a8fff259be4bfada667080eb00556"} }; + const vector eddsaPublicKey = { - {"7363bc5ab96d7f85e71a5ffe0b284405ae38e2e0f032fb3ffe805d9f0e2d117b"}, - {"7363bc5ab96d7f85e71a5ffe0b284405ae38e2e0f032fb3ffe805d9f0e2d117b"}, - {"7363bc5ab96d7f85e71a5ffe0b284405ae38e2e0f032fb3ffe805d9f0e2d117b"}, - {"7363bc5ab96d7f85e71a5ffe0b284405ae38e2e0f032fb3ffe805d9f0e2d117b"}, - {"7363bc5ab96d7f85e71a5ffe0b284405ae38e2e0f032fb3ffe805d9f0e2d117b"} + {"386f4fb049a5d8bb0706d3793096c8f91842ce380dfc342a2001d50dfbc901f4"}, + {"3f9e7dbde90477c24c1bacf14e073a356c1eca482d352d9cc0b16560a4e7e469"}, + {"2311c6013ff657844669d8b803b2e1ed33fe06eed445f966a800a8fbb8d790e8"}, + {"1ba7449655784fc9ce193a7887de1e4d3d35f7c82b802440c4f28bf678a34b34"}, + {"c426c524c92ad9d0b740f68ee312abf0298051a7e0364a867b940e9693ae6095"} }; const vector privateKeys = { diff --git a/bftengine/tests/SigManager/SigManager_test.cpp b/bftengine/tests/SigManager/SigManager_test.cpp index 29b168c6ec..21b93627c6 100644 --- a/bftengine/tests/SigManager/SigManager_test.cpp +++ b/bftengine/tests/SigManager/SigManager_test.cpp @@ -84,7 +84,7 @@ void corrupt(char* data, size_t len) { } } -TEST(RsaSignerAndRsaVerifierTest, LoadSignVerifyFromPemfiles) { +TEST(SignerAndVerifierTest, LoadSignVerifyFromPemfiles) { string publicKeyFullPath({string(KEYS_BASE_PATH) + string("/1/") + PUB_KEY_NAME}); string privateKeyFullPath({string(KEYS_BASE_PATH) + string("/1/") + PRIV_KEY_NAME}); @@ -103,7 +103,7 @@ TEST(RsaSignerAndRsaVerifierTest, LoadSignVerifyFromPemfiles) { auto signer_ = unique_ptr(new EdDSA_Signer(privKey, KeyFormat::PemFormat)); #endif - // sign with RSASigner + // sign with RSASigner/EdDSA_Signer size_t expectedSignerSigLen = signer_->signatureLength(); sig.reserve(expectedSignerSigLen); size_t lenRetData; @@ -112,7 +112,7 @@ TEST(RsaSignerAndRsaVerifierTest, LoadSignVerifyFromPemfiles) { lenRetData = sig.size(); ASSERT_EQ(lenRetData, expectedSignerSigLen); - // validate with RSAVerifier + // validate with RSAVerifier/EdDSA_Verifier ASSERT_TRUE(verifier_->verify(str_data, sig)); // change data randomally, expect failure @@ -182,7 +182,7 @@ TEST(SigManagerTest, ReplicasOnlyCheckVerify) { if (i == myId) continue; - // sign with RSASigner (other replicas, mock) + // sign with RSASigner/EdDSA_Signer (other replicas, mock) expectedSignerSigLen = signer->signatureLength(); sig.reserve(expectedSignerSigLen); generateRandomData(data, RANDOM_DATA_SIZE); diff --git a/bftengine/tests/clientsManager/ClientsManager_test.cpp b/bftengine/tests/clientsManager/ClientsManager_test.cpp index 9ee5e294cd..9026801375 100644 --- a/bftengine/tests/clientsManager/ClientsManager_test.cpp +++ b/bftengine/tests/clientsManager/ClientsManager_test.cpp @@ -25,11 +25,7 @@ using bftEngine::impl::SigManager; using bftEngine::ReplicaConfig; using bftEngine::ReservedPagesClientBase; using bftEngine::test::ReservedPagesMock; -// using concord::util::cryptopp_utils::Crypto; -using concord::util::openssl_utils::Crypto; using concord::util::crypto::KeyFormat; -// using concord::util::cryptopp_utils::RSASigner; -using concord::util::openssl_utils::EdDSA_Signer; using concord::secretsmanager::ISecretsManagerImpl; using concordUtil::Timers; using std::chrono::milliseconds; @@ -46,6 +42,16 @@ using std::this_thread::sleep_for; using std::unique_ptr; using std::vector; +#define RSA_Algo false + +#if RSA_Algo +using concord::util::cryptopp_utils::RSASigner; +using concord::util::cryptopp_utils::Crypto; +#else +using concord::util::openssl_utils::EdDSA_Signer; +using concord::util::openssl_utils::Crypto; +#endif + // Testing values to be used for certain Concord-BFT configuration that ClientsManager and/or its dependencies may // reference. const ReplicaId kReplicaIdForTesting = 0; @@ -228,8 +234,12 @@ static bool verifyClientPublicKeyLoadedToKEM(NodeIdType client_id, const pairhasVerifier(client_id))) { return false; } - // RSASigner signer(expected_key.first, kKeyFormatForTesting); + +#if RSA_Algo + RSASigner signer(expected_key.first, kKeyFormatForTesting); +#else EdDSA_Signer signer(expected_key.first, kKeyFormatForTesting); +#endif string signature = signer.sign(kArbitraryMessageForTestingKeyAgreement); return SigManager::instance()->verifySig(client_id, kArbitraryMessageForTestingKeyAgreement.data(), diff --git a/client/bftclient/src/bft_client.cpp b/client/bftclient/src/bft_client.cpp index ecce5d8f2f..3764ab7765 100644 --- a/client/bftclient/src/bft_client.cpp +++ b/client/bftclient/src/bft_client.cpp @@ -23,8 +23,14 @@ using namespace concord::secretsmanager; using namespace bftEngine; using namespace bftEngine::impl; using concord::util::crypto::KeyFormat; + +#define RSA_Algo false + +#if RSA_Algo +using concord::util::cryptopp_utils::RSASigner; +#else using concord::util::openssl_utils::EdDSA_Signer; -// using concord::util::cryptopp_utils::RSASigner; +#endif namespace bft::client { diff --git a/client/bftclient/test/bft_client_api_tests.cpp b/client/bftclient/test/bft_client_api_tests.cpp index b3d7e35e87..353e4e43f5 100644 --- a/client/bftclient/test/bft_client_api_tests.cpp +++ b/client/bftclient/test/bft_client_api_tests.cpp @@ -182,7 +182,7 @@ TEST_P(ClientApiTestParametrizedFixture, print_received_messages_and_timeout) { test_config_.secrets_manager_config = sd; } - // initialize the test's RSAVerifier + // initialize the test's RSAVerifier/EdDSA_Verifier string public_key_full_path({keypair_path + PUB_KEY_NAME}); std::ifstream file(public_key_full_path); std::stringstream stream; diff --git a/client/reconfiguration/src/default_handlers.cpp b/client/reconfiguration/src/default_handlers.cpp index 07dc72f271..8c5f66d6e3 100644 --- a/client/reconfiguration/src/default_handlers.cpp +++ b/client/reconfiguration/src/default_handlers.cpp @@ -12,7 +12,8 @@ #include "client/reconfiguration/default_handlers.hpp" #include "bftclient/StateControl.hpp" #include "concord.cmf.hpp" -#include "crypto_utils.hpp" +#include "cryptopp_utils.hpp" +#include "openssl_utils.hpp" #include "ReplicaConfig.hpp" #include diff --git a/communication/src/AsyncTlsConnection.cpp b/communication/src/AsyncTlsConnection.cpp index 0a16dcf449..50d5b30ec7 100644 --- a/communication/src/AsyncTlsConnection.cpp +++ b/communication/src/AsyncTlsConnection.cpp @@ -430,7 +430,7 @@ std::pair AsyncTlsConnection::checkCertificate(X509* received_cer uint32_t peerId = UINT32_MAX; std::string conn_type; // (1) First, try to verify the certificate against the latest saved certificate - bool res = concord::util::crypto::CertificateUtils::verifyCertificate( + bool res = concord::util::openssl_utils::CertificateUtils::verifyCertificate( received_cert, config_.certificatesRootPath_, peerId, conn_type, config_.useUnifiedCertificates_); if (expected_peer_id.has_value() && peerId != expected_peer_id.value()) return std::make_pair(false, peerId); if (res) return std::make_pair(res, peerId); diff --git a/install_deps.sh b/install_deps.sh index adbb2d40d7..2fe86a8bc2 100755 --- a/install_deps.sh +++ b/install_deps.sh @@ -67,7 +67,7 @@ apt-get ${APT_GET_FLAGS} install \ libz-dev \ libzstd-dev -pip3 install --upgrade wheel && pip3 install --upgrade trio +pip3 install --upgrade wheel && pip3 install --upgrade trio && pip3 install --upgrade pip pip3 install \ eliot eliot-tree \ tatsu==4.4.0 \ @@ -76,7 +76,8 @@ pip3 install \ ecdsa \ protobuf==3.15.8 \ grpcio==1.37.1 \ - grpcio-tools==1.37.1 + grpcio-tools==1.37.1 \ + cryptography==3.3.2 # Build 3rd parties wget ${WGET_FLAGS} -O cmake-linux.sh \ diff --git a/kvbc/include/pruning_handler.hpp b/kvbc/include/pruning_handler.hpp index 41d8ced110..046d5c0309 100644 --- a/kvbc/include/pruning_handler.hpp +++ b/kvbc/include/pruning_handler.hpp @@ -28,17 +28,17 @@ namespace concord::kvbc::pruning { // This class signs pruning messages via the replica's private key that it gets // through the configuration. Message contents used to generate the signature // are generated via the mechanisms provided in pruning_serialization.hpp/cpp . -class RSAPruningSigner { +class PruningSigner { public: // Construct by passing the configuration for the node the signer is running // on. - RSAPruningSigner(const std::string &key); + PruningSigner(const std::string &key); // Sign() methods sign the passed message and store the signature in the // 'signature' field of the message. An exception is thrown on error. // - // Note RSAPruningSigner does not handle signing of PruneRequest messages on + // Note PruningSigner does not handle signing of PruneRequest messages on // behalf of the operator, as the operator's signature is a dedicated-purpose - // application-level signature rather than a Concord-BFT Principal's RSA + // application-level signature rather than a Concord-BFT Principal's RSA/EdDSA // signature. void sign(concord::messages::LatestPrunableBlock &); @@ -52,20 +52,20 @@ class RSAPruningSigner { // // Idea is to use the principal_id as an ID that identifies senders in pruning // messages since it is unique across clients and replicas. -class RSAPruningVerifier { +class PruningVerifier { public: // Construct by passing the system configuration. - RSAPruningVerifier(const std::set> &replicasPublicKeys); + PruningVerifier(const std::set> &replicasPublicKeys); // Verify() methods verify that the message comes from the advertised sender. // Methods return true on successful verification and false on unsuccessful. // An exception is thrown on error. // - // Note RSAPruningVerifier::Verify(const com::vmware::concord::PruneRequest&) + // Note PruningVerifier::Verify(const com::vmware::concord::PruneRequest&) // handles verification of the LatestPrunableBlock message(s) contained within // the PruneRequest, but does not itself handle verification of the issuing // operator's signature of the pruning command, as the operator's signature is // a dedicated application-level signature rather than one of the Concord-BFT - // Principal's RSA signatures. + // Principal's RSA/EdDSA signatures. bool verify(const concord::messages::LatestPrunableBlock &) const; bool verify(const concord::messages::PruneRequest &) const; @@ -167,8 +167,8 @@ class PruningHandler : public concord::reconfiguration::BftReconfigurationHandle void pruneThroughBlockId(kvbc::BlockId block_id) const; uint64_t getBlockBftSequenceNumber(kvbc::BlockId) const; logging::Logger logger_; - RSAPruningSigner signer_; - RSAPruningVerifier verifier_; + PruningSigner signer_; + PruningVerifier verifier_; kvbc::IReader &ro_storage_; kvbc::IBlockAdder &blocks_adder_; kvbc::IBlocksDeleter &blocks_deleter_; @@ -231,7 +231,7 @@ class ReadOnlyReplicaPruningHandler : public concord::reconfiguration::BftReconf private: IReader &ro_storage_; - RSAPruningSigner signer_; + PruningSigner signer_; bool pruning_enabled_{false}; std::uint64_t replica_id_{0}; }; diff --git a/kvbc/src/pruning_handler.cpp b/kvbc/src/pruning_handler.cpp index c03e941b5b..ede5cbd295 100644 --- a/kvbc/src/pruning_handler.cpp +++ b/kvbc/src/pruning_handler.cpp @@ -16,10 +16,22 @@ #include "pruning_handler.hpp" #include "categorization/versioned_kv_category.h" #include "kvbc_key_types.hpp" +#include "openssl_utils.hpp" namespace concord::kvbc::pruning { -void RSAPruningSigner::sign(concord::messages::LatestPrunableBlock& block) { +#define RSA_Algo false + +using concord::util::crypto::KeyFormat; +#if RSA_Algo +using concord::util::cryptopp_utils::RSASigner; +using concord::util::cryptopp_utils::RSAVerifier; +#else +using concord::util::openssl_utils::EdDSA_Signer; +using concord::util::openssl_utils::EdDSA_Verifier; +#endif + +void PruningSigner::sign(concord::messages::LatestPrunableBlock& block) { std::ostringstream oss; std::string ser; oss << block.replica << block.block_id; @@ -28,19 +40,30 @@ void RSAPruningSigner::sign(concord::messages::LatestPrunableBlock& block) { block.signature = std::vector(signature.begin(), signature.end()); } -RSAPruningSigner::RSAPruningSigner(const std::string& key) - : signer_{std::make_unique( - key, concord::util::crypto::KeyFormat::HexaDecimalStrippedFormat)} {} +PruningSigner::PruningSigner(const std::string& key) + : +#if RSA_Algo + signer_ { + std::make_unique(key, KeyFormat::HexaDecimalStrippedFormat) +} +#else + signer_ { + std::make_unique(key, KeyFormat::HexaDecimalStrippedFormat) +} +#endif +{} -RSAPruningVerifier::RSAPruningVerifier(const std::set>& replicasPublicKeys) { +PruningVerifier::PruningVerifier(const std::set>& replicasPublicKeys) { auto i = 0u; for (auto& [idx, pkey] : replicasPublicKeys) { - replicas_.push_back(Replica{idx, - std::make_unique( - pkey, concord::util::crypto::KeyFormat::HexaDecimalStrippedFormat)}); +#if RSA_Algo + replicas_.push_back(Replica{idx, std::make_unique(pkey, KeyFormat::HexaDecimalStrippedFormat)}); +#else + replicas_.push_back(Replica{idx, std::make_unique(pkey, KeyFormat::HexaDecimalStrippedFormat)}); +#endif const auto ins_res = replica_ids_.insert(replicas_.back().principal_id); if (!ins_res.second) { - throw std::runtime_error{"RSAPruningVerifier found duplicate replica principal_id: " + + throw std::runtime_error{"PruningVerifier found duplicate replica principal_id: " + std::to_string(replicas_.back().principal_id)}; } @@ -50,7 +73,7 @@ RSAPruningVerifier::RSAPruningVerifier(const std::set(replica_ids_.size())) { return false; } @@ -78,7 +101,7 @@ bool RSAPruningVerifier::verify(const concord::messages::PruneRequest& request) return false; } - // Note RSAPruningVerifier does not handle verification of the operator's + // Note PruningVerifier does not handle verification of the operator's // signature authorizing this pruning order, as the operator's signature is a // dedicated application-level signature rather than one of the Concord-BFT // principals' RSA signatures. @@ -98,7 +121,7 @@ bool RSAPruningVerifier::verify(const concord::messages::PruneRequest& request) return replica_ids_to_verify.empty(); } -bool RSAPruningVerifier::verify(std::uint64_t sender, const std::string& ser, const std::string& signature) const { +bool PruningVerifier::verify(std::uint64_t sender, const std::string& ser, const std::string& signature) const { auto it = principal_to_replica_idx_.find(sender); if (it == std::cend(principal_to_replica_idx_)) { return false; @@ -107,7 +130,7 @@ bool RSAPruningVerifier::verify(std::uint64_t sender, const std::string& ser, co return getReplica(it->second).verifier->verify(ser, signature); } -const RSAPruningVerifier::Replica& RSAPruningVerifier::getReplica(ReplicaVector::size_type idx) const { +const PruningVerifier::Replica& PruningVerifier::getReplica(ReplicaVector::size_type idx) const { return replicas_[idx]; } diff --git a/kvbc/test/pruning_test.cpp b/kvbc/test/pruning_test.cpp index c7129d2746..11698f9d1e 100644 --- a/kvbc/test/pruning_test.cpp +++ b/kvbc/test/pruning_test.cpp @@ -38,10 +38,13 @@ using namespace concord::kvbc; using namespace concord::kvbc::categorization; using namespace concord::kvbc::pruning; namespace { +#define RSA_Algo false const NodeIdType replica_0 = 0; const NodeIdType replica_1 = 1; const NodeIdType replica_2 = 2; const NodeIdType replica_3 = 3; + +#if RSA_Algo std::string privateKey_0 = "308204BA020100300D06092A864886F70D0101010500048204A4308204A00201000282010100C55B8F7979BF24B335017082BF33EE2960E3" "A0" @@ -322,6 +325,19 @@ std::string publicKey_4 = "BF2EA16F58773514249B03A4775C6A10561AFC8CF54B551A43FD014F3C5FE12D96AC5F117645E26D125DC7430114FA60577BF7C9AA1224D1" "90" "B2D8A83B020111"; +#else +const std::string privateKey_0 = "61498efe1764b89357a02e2887d224154006ceacf26269f8695a4af561453eef"; +const std::string privateKey_1 = "247a74ab3620ec6b9f5feab9ee1f86521da3fa2804ad45bb5bf2c5b21ef105bc"; +const std::string privateKey_2 = "fb539bc3d66deda55524d903da26dbec1f4b6abf41ec5db521e617c64eb2c341"; +const std::string privateKey_3 = "55ea66e855b83ec4a02bd8fcce6bb4426ad3db2a842fa2a2a6777f13e40a4717"; +const std::string privateKey_4 = "f2f3d43da68329bfe31419636072e27cfd1a8fff259be4bfada667080eb00556"; + +const std::string publicKey_0 = "386f4fb049a5d8bb0706d3793096c8f91842ce380dfc342a2001d50dfbc901f4"; +const std::string publicKey_1 = "3f9e7dbde90477c24c1bacf14e073a356c1eca482d352d9cc0b16560a4e7e469"; +const std::string publicKey_2 = "2311c6013ff657844669d8b803b2e1ed33fe06eed445f966a800a8fbb8d790e8"; +const std::string publicKey_3 = "1ba7449655784fc9ce193a7887de1e4d3d35f7c82b802440c4f28bf678a34b34"; +const std::string publicKey_4 = "c426c524c92ad9d0b740f68ee312abf0298051a7e0364a867b940e9693ae6095"; +#endif bftEngine::ReplicaConfig &replicaConfig = bftEngine::ReplicaConfig::instance(); std::map private_keys_of_replicas; @@ -466,7 +482,7 @@ TestStateTransfer state_transfer; void CheckLatestPrunableResp(const concord::messages::LatestPrunableBlock &latest_prunable_resp, int replica_idx, - const RSAPruningVerifier &verifier) { + const PruningVerifier &verifier) { ASSERT_EQ(latest_prunable_resp.replica, replica_idx); ASSERT_TRUE(verifier.verify(latest_prunable_resp)); } @@ -527,7 +543,7 @@ concord::messages::PruneRequest ConstructPruneRequest(std::size_t client_idx, // Send different block IDs. latest_block.block_id = min_prunable_block_id + i; - auto block_signer = RSAPruningSigner{pkey}; + auto block_signer = PruningSigner{pkey}; block_signer.sign(latest_block); i++; } @@ -540,11 +556,11 @@ TEST_F(test_rocksdb, sign_verify_correct) { const auto replica_count = 4; uint64_t sending_id = 0; uint64_t client_proxy_count = 4; - const auto verifier = RSAPruningVerifier{replicaConfig.publicKeysOfReplicas}; - std::vector signers; + const auto verifier = PruningVerifier{replicaConfig.publicKeysOfReplicas}; + std::vector signers; signers.reserve(replica_count); for (auto i = 0; i < replica_count; ++i) { - signers.emplace_back(RSAPruningSigner{private_keys_of_replicas[i]}); + signers.emplace_back(PruningSigner{private_keys_of_replicas[i]}); } // Sign and verify a LatestPrunableBlock message. @@ -577,11 +593,11 @@ TEST_F(test_rocksdb, verify_malformed_messages) { const auto replica_count = 4; const auto client_proxy_count = replica_count; const auto sending_id = 1; - const auto verifier = RSAPruningVerifier{replicaConfig.publicKeysOfReplicas}; - std::vector signers; + const auto verifier = PruningVerifier{replicaConfig.publicKeysOfReplicas}; + std::vector signers; signers.reserve(replica_count); for (auto i = 0; i < replica_count; ++i) { - signers.emplace_back(RSAPruningSigner{private_keys_of_replicas[i]}); + signers.emplace_back(PruningSigner{private_keys_of_replicas[i]}); } // Break verification of LatestPrunableBlock messages. @@ -691,7 +707,7 @@ TEST_F(test_rocksdb, sm_latest_prunable_request_correct_num_bocks_to_keep) { replicaConfig.pruningEnabled_ = true; TestStorage storage(db); auto &blocks_deleter = storage; - const auto verifier = RSAPruningVerifier{replicaConfig.publicKeysOfReplicas}; + const auto verifier = PruningVerifier{replicaConfig.publicKeysOfReplicas}; replicaConfig.replicaPrivateKey = privateKey_1; InitBlockchainStorage(replica_count, storage); @@ -716,7 +732,7 @@ TEST_F(test_rocksdb, sm_latest_prunable_request_big_num_blocks_to_keep) { replicaConfig.replicaPrivateKey = privateKey_1; TestStorage storage(db); auto &blocks_deleter = storage; - const auto verifier = RSAPruningVerifier{replicaConfig.publicKeysOfReplicas}; + const auto verifier = PruningVerifier{replicaConfig.publicKeysOfReplicas}; auto sm = PruningHandler{storage, storage, blocks_deleter, false}; @@ -741,7 +757,7 @@ TEST_F(test_rocksdb, sm_latest_prunable_request_no_pruning_conf) { replicaConfig.replicaPrivateKey = privateKey_1; TestStorage storage(db); auto &blocks_deleter = storage; - const auto verifier = RSAPruningVerifier{replicaConfig.publicKeysOfReplicas}; + const auto verifier = PruningVerifier{replicaConfig.publicKeysOfReplicas}; InitBlockchainStorage(replica_count, storage); @@ -768,7 +784,7 @@ TEST_F(test_rocksdb, sm_latest_prunable_request_pruning_disabled) { replicaConfig.replicaPrivateKey = privateKey_1; auto storage = TestStorage(db); auto &blocks_deleter = storage; - const auto verifier = RSAPruningVerifier{replicaConfig.publicKeysOfReplicas}; + const auto verifier = PruningVerifier{replicaConfig.publicKeysOfReplicas}; InitBlockchainStorage(replica_count, storage); diff --git a/reconfiguration/src/reconfiguration_handler.cpp b/reconfiguration/src/reconfiguration_handler.cpp index a7bbadbff3..5f2e2f1227 100644 --- a/reconfiguration/src/reconfiguration_handler.cpp +++ b/reconfiguration/src/reconfiguration_handler.cpp @@ -21,10 +21,21 @@ #include "communication/StateControl.hpp" #include "secrets_manager_plain.h" #include "bftengine/DbCheckpointManager.hpp" +#include "openssl_utils.hpp" #include +#define ECDSA_Algo true + using namespace concord::messages; +using concord::util::crypto::KeyFormat; + +#if ECDSA_Algo +using concord::util::cryptopp_utils::ECDSAVerifier; +#else +using concord::util::openssl_utils::EdDSA_Verifier; +#endif + namespace concord::reconfiguration { bool ReconfigurationHandler::handle(const WedgeCommand& cmd, @@ -329,8 +340,11 @@ BftReconfigurationHandler::BftReconfigurationHandler() { key_str.append(buf, 0, key_content.gcount()); } key_str.append(buf, 0, key_content.gcount()); - verifier_.reset( - new concord::util::cryptopp_utils::ECDSAVerifier(key_str, concord::util::crypto::KeyFormat::PemFormat)); +#if ECDSA_Algo + verifier_.reset(new ECDSAVerifier(key_str, KeyFormat::PemFormat)); +#else + verifier_.reset(new EdDSA_Verifier(key_str, KeyFormat::PemFormat)); +#endif } bool BftReconfigurationHandler::verifySignature(uint32_t sender_id, const std::string& data, @@ -364,7 +378,7 @@ bool ClientReconfigurationHandler::handle(const concord::messages::ClientExchang // assuming we always send hex DER over the wire for (const auto& clientId : affected_clients) bftEngine::impl::KeyExchangeManager::instance().onClientPublicKeyExchange( - msg.pub_key, concord::util::crypto::KeyFormat::HexaDecimalStrippedFormat, clientId); + msg.pub_key, KeyFormat::HexaDecimalStrippedFormat, clientId); return true; } } // namespace concord::reconfiguration diff --git a/secretsmanager/src/aes.cpp b/secretsmanager/src/aes.cpp index 1beb0ac387..5d03d69aa8 100644 --- a/secretsmanager/src/aes.cpp +++ b/secretsmanager/src/aes.cpp @@ -51,20 +51,18 @@ vector AES_CBC::encrypt(const string& input) const { vector cipher; CryptoPP::StringSource ss( input, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::VectorSink(cipher))); + return cipher; #else if (input.empty()) { return {}; } - int c_len = input.size() + AES_BLOCK_SIZE; - int f_len = 0; - auto deleter = [](unsigned char* p) { if (nullptr != p) { delete[] p; } }; - unique_ptr ciphertext(new unsigned char[c_len], deleter); + unique_ptr ciphertext(new unsigned char[input.size() + AES_BLOCK_SIZE], deleter); unique_ptr plaintext(new unsigned char[input.size() + 1], deleter); for (size_t i{0UL}; i < input.size(); ++i) { @@ -74,6 +72,9 @@ vector AES_CBC::encrypt(const string& input) const { unique_ptr ctx(EVP_CIPHER_CTX_new()); ConcordAssert(nullptr != ctx); + int c_len{0}; + int f_len{0}; + ConcordAssert(1 == EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_cbc(), nullptr, key.data(), iv.data())); ConcordAssert(1 == EVP_EncryptUpdate(ctx.get(), ciphertext.get(), &c_len, plaintext.get(), input.size())); ConcordAssert(1 == EVP_EncryptFinal_ex(ctx.get(), ciphertext.get() + c_len, &f_len)); @@ -117,7 +118,11 @@ string AES_CBC::decrypt(const vector& cipher) const { plaintext.get()[c_len + f_len] = 0; - return string((char*)plaintext.get()); + vector temp(c_len + f_len); + for (int i{0}; i < c_len + f_len; ++i) { + temp[i] = plaintext.get()[i]; + } + return string(temp.begin(), temp.end()); #endif } } // namespace concord::secretsmanager \ No newline at end of file diff --git a/tests/apollo/util/operator.py b/tests/apollo/util/operator.py index 3e7542db2f..6ec8f65c78 100644 --- a/tests/apollo/util/operator.py +++ b/tests/apollo/util/operator.py @@ -24,7 +24,6 @@ from ecdsa import SigningKey from ecdsa import SECP256k1 import hashlib -from Crypto.PublicKey import RSA import util.eliot_logging as log diff --git a/threshsign/src/ThresholdSignaturesTypes.cpp b/threshsign/src/ThresholdSignaturesTypes.cpp index 2c4c770b45..0303b5600f 100644 --- a/threshsign/src/ThresholdSignaturesTypes.cpp +++ b/threshsign/src/ThresholdSignaturesTypes.cpp @@ -318,7 +318,7 @@ Cryptosystem* Cryptosystem::fromConfiguration(std::istream& input, type = yaml::readValue(input, prefix + "_cryptosystem_type"); subtype = yaml::readValue(input, prefix + "_cryptosystem_subtype_parameter"); std::uint16_t numSigners = yaml::readValue(input, prefix + "_cryptosystem_num_signers"); - std::string publicKey = "uninitialized"; + // std::string publicKey = "uninitialized"; uint16_t threshold = 1; if (type == THRESHOLD_BLS_SCHEME) threshold = yaml::readValue(input, prefix + "_cryptosystem_threshold"); diff --git a/tools/GenerateConcordKeys.cpp b/tools/GenerateConcordKeys.cpp index 31ee20ed9e..3a38e50adf 100644 --- a/tools/GenerateConcordKeys.cpp +++ b/tools/GenerateConcordKeys.cpp @@ -22,6 +22,11 @@ #include "threshsign/ThresholdSignaturesTypes.h" #include "KeyfileIOUtils.hpp" +#include "openssl_utils.hpp" + +using concord::util::openssl_utils::Crypto; + +#define RSA_Algo false // Helper functions and static state to this executable's main function. @@ -34,6 +39,7 @@ static bool containsHelpOption(int argc, char** argv) { return false; } +#if RSA_Algo static CryptoPP::RandomPool sGlobalRandGen; const unsigned int rsaKeyLength = 2048; @@ -54,6 +60,7 @@ static std::pair generateRsaKey() { return keyPair; } +#endif /** * Main function for the GenerateConcordKeys executable. Pseudorandomly @@ -187,10 +194,20 @@ int main(int argc, char** argv) { config.cVal = (n - (3 * config.fVal) - 1) / 2; +#if RSA_Algo std::vector> rsaKeys; +#else + std::vector> eddsaKeys; +#endif + for (uint16_t i = 0; i < n + ro; ++i) { +#if RSA_Algo rsaKeys.push_back(generateRsaKey()); config.publicKeysOfReplicas.insert(std::pair(i, rsaKeys[i].second)); +#else + eddsaKeys.push_back(Crypto::instance().generateEdDSAKeyPair()); + config.publicKeysOfReplicas.insert(std::pair(i, eddsaKeys[i].second)); +#endif } // We want to generate public key for n-out-of-n case @@ -199,14 +216,22 @@ int main(int argc, char** argv) { // Output the generated keys. for (uint16_t i = 0; i < n; ++i) { config.replicaId = i; +#if RSA_Algo config.replicaPrivateKey = rsaKeys[i].first; +#else + config.replicaPrivateKey = eddsaKeys[i].first; +#endif outputReplicaKeyfile(n, ro, config, outputPrefix + std::to_string(i), &cryptoSys); } for (uint16_t i = n; i < n + ro; ++i) { config.isReadOnly = true; config.replicaId = i; +#if RSA_Algo config.replicaPrivateKey = rsaKeys[i].first; +#else + config.replicaPrivateKey = eddsaKeys[i].first; +#endif outputReplicaKeyfile(n, ro, config, outputPrefix + std::to_string(i)); } } catch (std::exception& e) { diff --git a/tools/KeyfileIOUtils.cpp b/tools/KeyfileIOUtils.cpp index 824d8b1cfa..ff87fbb8ee 100644 --- a/tools/KeyfileIOUtils.cpp +++ b/tools/KeyfileIOUtils.cpp @@ -21,6 +21,8 @@ #include "KeyfileIOUtils.hpp" #include "yaml_utils.hpp" +#define RSA_Algo false + void outputReplicaKeyfile(uint16_t numReplicas, uint16_t numRoReplicas, bftEngine::ReplicaConfig& config, @@ -39,17 +41,27 @@ void outputReplicaKeyfile(uint16_t numReplicas, << "c_val: " << config.cVal << "\n" << "replica_id: " << config.replicaId << "\n" << "read-only: " << config.isReadOnly << "\n\n" +#if RSA_Algo << "# RSA non-threshold replica public keys\n" << "rsa_public_keys:\n"; +#else + << "# EdDSA non-threshold replica public keys\n" + << "eddsa_public_keys:\n"; +#endif for (auto& v : config.publicKeysOfReplicas) output << " - " << v.second << "\n"; output << "\n"; +#if RSA_Algo output << "rsa_private_key: " << config.replicaPrivateKey << "\n"; +#else + output << "eddsa_private_key: " << config.replicaPrivateKey << "\n"; +#endif if (commonSys) commonSys->writeConfiguration(output, "common", config.replicaId); } +#if RSA_Algo static void validateRSAPublicKey(const std::string& key) { const size_t rsaPublicKeyHexadecimalLength = 584; if (!(key.length() == rsaPublicKeyHexadecimalLength) && (std::regex_match(key, std::regex("[0-9A-Fa-f]+")))) @@ -63,6 +75,21 @@ static void validateRSAPrivateKey(const std::string& key) { if (!std::regex_match(key, std::regex("[0-9A-Fa-f]+"))) throw std::runtime_error("Invalid RSA private key: " + key); } +#else +static void validateEdDSAPublicKey(const std::string& key) { + const size_t eddsaPublicKeyHexadecimalLength{64UL}; + if (!(key.length() == eddsaPublicKeyHexadecimalLength) && (std::regex_match(key, std::regex("[0-9A-Fa-f]+")))) { + throw std::runtime_error("Invalid EdDSA public key: " + key); + } +} + +static void validateEdDSAPrivateKey(const std::string& key) { + const size_t eddsaPrivateKeyHexadecimalLength{64UL}; + if (!(key.length() == eddsaPrivateKeyHexadecimalLength) && (std::regex_match(key, std::regex("[0-9A-Fa-f]+")))) { + throw std::runtime_error("Invalid EdDSA private key: " + key); + } +} +#endif Cryptosystem* inputReplicaKeyfileMultisig(const std::string& filename, bftEngine::ReplicaConfig& config) { using namespace concord::util; @@ -86,19 +113,36 @@ Cryptosystem* inputReplicaKeyfileMultisig(const std::string& filename, bftEngine if (config.replicaId >= config.numReplicas + config.numRoReplicas) throw std::runtime_error("replica IDs must be in the range [0, num_replicas + num_ro_replicas]"); +#if RSA_Algo std::vector rsaPublicKeys = yaml::readCollection(input, "rsa_public_keys"); if (rsaPublicKeys.size() != config.numReplicas + config.numRoReplicas) throw std::runtime_error("number of public RSA keys must match num_replicas"); +#else + std::vector eddsaPublicKeys = yaml::readCollection(input, "eddsa_public_keys"); + + if (eddsaPublicKeys.size() != config.numReplicas + config.numRoReplicas) + throw std::runtime_error("number of public EdDSA keys must match num_replicas"); +#endif config.publicKeysOfReplicas.clear(); for (size_t i = 0; i < config.numReplicas + config.numRoReplicas; ++i) { +#if RSA_Algo validateRSAPublicKey(rsaPublicKeys[i]); config.publicKeysOfReplicas.insert(std::pair(i, rsaPublicKeys[i])); +#else + validateEdDSAPublicKey(eddsaPublicKeys[i]); + config.publicKeysOfReplicas.insert(std::pair(i, eddsaPublicKeys[i])); +#endif } +#if RSA_Algo config.replicaPrivateKey = yaml::readValue(input, "rsa_private_key"); validateRSAPrivateKey(config.replicaPrivateKey); +#else + config.replicaPrivateKey = yaml::readValue(input, "eddsa_private_key"); + validateEdDSAPrivateKey(config.replicaPrivateKey); +#endif if (config.isReadOnly) return nullptr; diff --git a/tools/TestGeneratedKeys.cpp b/tools/TestGeneratedKeys.cpp index 6107188125..8b75238b6a 100644 --- a/tools/TestGeneratedKeys.cpp +++ b/tools/TestGeneratedKeys.cpp @@ -20,6 +20,18 @@ #include #include "KeyfileIOUtils.hpp" #include "cryptopp_utils.hpp" +#include "openssl_utils.hpp" + +#define RSA_Algo false + +#if RSA_Algo +using concord::util::cryptopp_utils::RSASigner; +using concord::util::cryptopp_utils::RSAVerifier; +#else +using concord::util::openssl_utils::EdDSA_Signer; +using concord::util::openssl_utils::EdDSA_Verifier; +#endif +using concord::util::crypto::KeyFormat; // How often to output status when testing cryptosystems, measured as an // interval measured in tested signaturs. @@ -120,6 +132,7 @@ static bool validateFundamentalFields(const std::vector& conf return true; } +#if RSA_Algo // Helper function to test RSA keys to test the compatibility of a single key // pair. static bool testRSAKeyPair(const std::string& privateKey, const std::string& publicKey, uint16_t replicaID) { @@ -128,22 +141,20 @@ static bool testRSAKeyPair(const std::string& privateKey, const std::string& pub // limiting their scope to those statements; declaring them by value is not // possible in this case becuause they lack paramter-less default // constructors. - std::unique_ptr signer; - std::unique_ptr verifier; + std::unique_ptr signer; + std::unique_ptr verifier; std::string invalidPrivateKey = "FAILURE: Invalid RSA private key for replica " + std::to_string(replicaID) + ".\n"; std::string invalidPublicKey = "FAILURE: Invalid RSA public key for replica " + std::to_string(replicaID) + ".\n"; try { - signer.reset(new concord::util::cryptopp_utils::RSASigner( - privateKey, concord::util::crypto::KeyFormat::HexaDecimalStrippedFormat)); + signer.reset(new RSASigner(privateKey, KeyFormat::HexaDecimalStrippedFormat)); } catch (std::exception& e) { std::cout << invalidPrivateKey; return false; } try { - verifier.reset(new concord::util::cryptopp_utils::RSAVerifier( - publicKey, concord::util::crypto::KeyFormat::HexaDecimalStrippedFormat)); + verifier.reset(new RSAVerifier(publicKey, KeyFormat::HexaDecimalStrippedFormat)); } catch (std::exception& e) { std::cout << invalidPublicKey; return false; @@ -245,6 +256,126 @@ static bool testRSAKeys(const std::vector& configs) { return true; } +#else +// Helper function to test EdDSA keys to test the compatibility of a single key pair. +static bool testEdDSAKeyPair(const std::string& privateKey, const std::string& publicKey, uint16_t replicaID) { + // The signer and verifier are stored with unique pointers rather than by + // value so that they can be constructed in try/catch statements without + // limiting their scope to those statements; declaring them by value is not + // possible in this case becuause they lack paramter-less default + // constructors. + std::unique_ptr signer; + std::unique_ptr verifier; + + const std::string invalidPrivateKey = + "FAILURE: Invalid EdDSA private key for replica " + std::to_string(replicaID) + ".\n"; + const std::string invalidPublicKey = + "FAILURE: Invalid EdDSA public key for replica " + std::to_string(replicaID) + ".\n"; + + try { + signer.reset(new EdDSA_Signer(privateKey, KeyFormat::HexaDecimalStrippedFormat)); + } catch (const std::exception& e) { + std::cout << invalidPrivateKey; + return false; + } + try { + verifier.reset(new EdDSA_Verifier(publicKey, KeyFormat::HexaDecimalStrippedFormat)); + } catch (const std::exception& e) { + std::cout << invalidPublicKey; + return false; + } + + for (auto iter = std::begin(kHashesToTest); iter != std::end(kHashesToTest); ++iter) { + const std::string& hash = *iter; + + std::string sig; + try { + sig = signer->sign(hash); + if (sig.empty()) { + std::cout << "FAILURE: Failed to sign data with replica " << replicaID << "'s EdDSA private key.\n"; + return false; + } + } catch (std::exception& e) { + std::cout << invalidPrivateKey; + return false; + } + + try { + if (!verifier->verify(hash, sig)) { + std::cout << "FAILURE: A signature with replica " << replicaID + << "'s EdDSA private key could not be verified with replica " << replicaID + << "'s EdDSA public key.\n"; + return false; + } + } catch (std::exception& e) { + std::cout << invalidPublicKey; + return false; + } + } + return true; +} + +// Test that the EdDSA key pairs given in the keyfiles work, that the keyfiles +// agree on what the public keys are, and that there are no duplicates. +static bool testEdDSAKeys(const std::vector& configs) { + uint16_t numReplicas = configs.size(); + + std::cout << "Testing " << numReplicas << " EdDSA key pairs...\n"; + std::unordered_map expectedPublicKeys; + std::unordered_set eddsaPublicKeysSeen; + + // Test that a signature produced with each replica's private key can be + // verified with that replica's public key. + for (uint16_t i = 0; i < numReplicas; ++i) { + std::string privateKey = configs[i].replicaPrivateKey; + std::string publicKey; + + for (const auto& publicKeyEntry : configs[i].publicKeysOfReplicas) { + if (publicKeyEntry.first == i) { + publicKey = publicKeyEntry.second; + } + } + + if (!testEdDSAKeyPair(privateKey, publicKey, i)) { + return false; + } + + if (eddsaPublicKeysSeen.count(publicKey) > 0) { + uint16_t existingKeyholder; + for (const auto& publicKeyEntry : expectedPublicKeys) { + if (publicKeyEntry.second == publicKey) { + existingKeyholder = publicKeyEntry.first; + } + } + std::cout << "FAILURE: Replicas " << existingKeyholder << " and " << i << " share the same EdDSA public key.\n"; + return false; + } + expectedPublicKeys[i] = publicKey; + + if (((i + 1) % kTestProgressReportingInterval) == 0) { + std::cout << "Tested " << (i + 1) << " out of " << numReplicas << " EdDSA key pairs...\n"; + } + } + + std::cout << "Verifying that all replicas agree on EdDSA public keys...\n"; + + // Verify that all replicas' keyfiles agree on the EdDSA public keys. + for (uint16_t i = 0; i < numReplicas; ++i) { + for (const auto& publicKeyEntry : configs[i].publicKeysOfReplicas) { + if (publicKeyEntry.second != expectedPublicKeys[publicKeyEntry.first]) { + std::cout << "FAILURE: Replica " << i << " has an incorrect EdDSA public key for replica " + << publicKeyEntry.first << ".\n"; + return false; + } + } + } + + std::cout << "All EdDSA key tests were successful.\n"; + + return true; +} +#endif + // Testing the threshold cryptosystem keys is not as straightforward as testing // the RSA keys because each signature may have multiple signers. Testing all // possible signer combinations, or even only all signer combinations that we @@ -724,7 +855,13 @@ int main(int argc, char** argv) { } std::cout << "Cryptographic configurations read appear to be sane.\n"; std::cout << "Testing key functionality and agreement...\n"; - if (!testRSAKeys(configs)) { + +#if RSA_Algo + if (!testRSAKeys(configs)) +#else + if (!testEdDSAKeys(configs)) +#endif + { return -1; } if (!testThresholdKeys(configs, cryptoSystems)) { diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index d76ca623aa..0040acafcf 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -20,8 +20,8 @@ add_library(util STATIC ${util_source_files}) add_library(util_shared SHARED ${util_source_files}) # Use below macros to use CryptoPP's SHA_256 or OpenSSL's SHA_256 hashing. -# USE_CRYPTOPP_SHA_256=FALSE -# USE_OPENSSL_SHA_256=FALSE +# USE_CRYPTOPP_SHA_256 +# USE_OPENSSL_SHA_256 target_compile_definitions(util PUBLIC USE_OPENSSL_SHA3_256) target_compile_definitions(util_shared PUBLIC USE_OPENSSL_SHA3_256) diff --git a/util/pyclient/bft_client.py b/util/pyclient/bft_client.py index 9809f28ba5..6e1157353a 100644 --- a/util/pyclient/bft_client.py +++ b/util/pyclient/bft_client.py @@ -17,9 +17,7 @@ import ssl import os import random -from Crypto.PublicKey import RSA -from Crypto.Hash import SHA256 -from Crypto.Signature import pkcs1_15 +from cryptography.hazmat.primitives import serialization import bft_msgs import replica_specific_info as RSI @@ -96,7 +94,7 @@ def __init__(self, config, replicas, ro_replicas=[]): self.signing_key = None if txn_signing_key_path: with open(txn_signing_key_path, 'rb') as f: - self.signing_key = RSA.import_key(f.read()) + self.signing_key = serialization.load_pem_private_key(f.read(), password=None) @abstractmethod def __enter__(self): @@ -187,8 +185,7 @@ async def sendSync(self, msg, read_only, seq_num=None, cid=None, pre_process=Fal signature = b'' client_id = self.client_id if self.signing_key: - h = SHA256.new(msg) - signature = pkcs1_15.new(self.signing_key).sign(h) + signature = self.signing_key.sign(bytes(msg)) if corrupt_params: msg, signature, client_id = self._corrupt_signing_params(msg, signature, client_id, corrupt_params) @@ -232,8 +229,7 @@ async def write_batch(self, msg_batch, batch_seq_nums=None, m_of_n_quorum=None, signature = b'' client_id = self.client_id if self.signing_key: - h = SHA256.new(msg) - signature = pkcs1_15.new(self.signing_key).sign(h) + signature = self.signing_key.sign(bytes(msg)) if corrupt_params and (req_index_to_corrupt == n): msg, signature, client_id = self._corrupt_signing_params(msg, signature, client_id, corrupt_params) diff --git a/util/src/openssl_utils.cpp b/util/src/openssl_utils.cpp index a59cc9ba35..26efb86a07 100644 --- a/util/src/openssl_utils.cpp +++ b/util/src/openssl_utils.cpp @@ -192,13 +192,14 @@ EdDSA_Signer::EdDSA_Signer(const string& strPrivKey, KeyFormat fmt) : keyStr_{st std::terminate(); } - unsigned char key[EDDSA_KEY_SIZE]{}; size_t keyLen{EDDSA_KEY_SIZE}; edPkey_.reset(PEM_read_PrivateKey(fp.get(), nullptr, nullptr, nullptr)); - ConcordAssertEQ(1, EVP_PKEY_get_raw_private_key(edPkey_.get(), key, &keyLen)); // Extract private key in 'key'. + ConcordAssertEQ(1, + EVP_PKEY_get_raw_private_key(edPkey_.get(), + reinterpret_cast(keyStr_.data()), + &keyLen)); // Extract private key in 'keyStr_'. remove(temp.data()); - keyStr_ = concordUtils::hexToASCII(concordUtils::bufferToHex(key, keyLen)); } else { string privCh = concordUtils::hexToASCII(strPrivKey); edPkey_.reset( @@ -248,13 +249,14 @@ EdDSA_Verifier::EdDSA_Verifier(const string& strPubKey, KeyFormat fmt) : keyStr_ std::terminate(); } - unsigned char key[EDDSA_KEY_SIZE]{}; size_t keyLen{EDDSA_KEY_SIZE}; edPkey_.reset(PEM_read_PUBKEY(fp.get(), nullptr, nullptr, nullptr)); - ConcordAssertEQ(1, EVP_PKEY_get_raw_public_key(edPkey_.get(), key, &keyLen)); // Extract public key. + ConcordAssertEQ(1, + EVP_PKEY_get_raw_public_key(edPkey_.get(), + reinterpret_cast(keyStr_.data()), + &keyLen)); // Extract public key in 'keyStr_'. remove(temp.data()); - keyStr_ = concordUtils::hexToASCII(concordUtils::bufferToHex(key, keyLen)); } else { string pubCh = concordUtils::hexToASCII(strPubKey); edPkey_.reset(EVP_PKEY_new_raw_public_key(NID_ED25519, nullptr, (const unsigned char*)pubCh.data(), pubCh.size())); @@ -276,6 +278,7 @@ bool EdDSA_Verifier::verify(const string& dataToVerify, const string& sigToVerif sigLen_, reinterpret_cast(dataToVerify.data()), dataToVerify.size())) { + LOG_ERROR(OPENSSL_LOG, "EdDSA verification failed." << KVLOG(dataToVerify, sigToVerify)); return false; } return true;