From 9702db04a400faf880147e4cdefd88b2e7eeaf6b Mon Sep 17 00:00:00 2001 From: Ynon Flum Date: Mon, 12 Sep 2022 18:20:53 +0300 Subject: [PATCH] Move digest files --- bftengine/src/bftengine/KeyStore.cpp | 9 +- .../preprocessor/RequestProcessingState.cpp | 29 +- .../preprocessor/RequestProcessingState.hpp | 18 +- .../messages/PreProcessReplyMsg.cpp | 10 +- .../messages/PreProcessReplyMsg.hpp | 2 +- .../messages/PreProcessResultHashCreator.hpp | 12 +- .../preprocessor/tests/preprocessor_test.cpp | 3 +- bftengine/tests/KeyStore/KeyStore_test.cpp | 2 +- .../bcstatetransfer/bcstatetransfer_tests.cpp | 2 +- .../ReplicaAsksToLeaveViewMsg_test.cpp | 3 - .../tests/messages/ViewChangeMsg_test.cpp | 2 +- .../clientservice/state_snapshot_service.hpp | 2 +- .../src/state_snapshot_service.cpp | 12 +- .../client/thin-replica-client/trc_hash.hpp | 4 +- client/thin-replica-client/src/trc_hash.cpp | 2 +- examples/replica/src/KVCommandHandler.cpp | 2 +- kvbc/benchmark/sparse_merkle_benchmark.cpp | 2 +- .../hash_state_benchmark.cpp | 4 +- kvbc/include/categorization/base_types.h | 2 +- kvbc/include/direct_kv_block.h | 2 +- kvbc/include/sparse_merkle/base_types.h | 2 +- kvbc/src/direct_kv_db_adapter.cpp | 4 +- kvbc/src/kvbc_app_filter/kvbc_app_filter.cpp | 6 +- .../test/kvbc_app_filter/kvbc_filter_test.cpp | 4 +- ...ck_merkle_latest_ver_cf_migration_test.cpp | 2 +- .../internal_node_property_tests.cpp | 2 +- secretsmanager/src/aes.cpp | 10 +- .../TesterReplica/internalCommandsHandler.cpp | 2 +- .../threshsign/eddsa/SingleEdDSASignature.h | 2 +- threshsign/src/ThresholdSignaturesTypes.cpp | 4 +- threshsign/src/eddsa/EdDSAMultisigFactory.cpp | 12 +- tools/KeyfileIOUtils.cpp | 8 +- util/CMakeLists.txt | 8 +- util/include/crypto/crypto.hpp | 7 + .../crypto/cryptopp/digest_creator.hpp | 2 +- util/include/crypto/digest.hpp | 5 +- util/include/crypto/digest_holder.hpp | 4 +- .../{digest_type.hpp => digest_parametes.hpp} | 0 util/include/crypto/factory.hpp | 55 +- util/include/crypto/openssl/EdDSA.hpp | 22 +- util/include/crypto/openssl/EdDSASigner.hpp | 10 +- util/include/crypto/openssl/EdDSAVerifier.hpp | 13 +- .../openssl/crypto.hpp} | 108 +++- .../include/crypto/openssl/digest_creator.hpp | 4 +- util/include/crypto/openssl/hash.hpp | 4 +- util/include/crypto/verifier.hpp | 1 + util/src/crypto/crypto.cpp | 64 ++- util/src/crypto/factory.cpp | 72 +++ util/src/openssl/certificates.cpp | 24 +- .../crypto.cpp} | 481 ++++++++---------- util/test/openssl_crypto_wrapper_tests.cpp | 18 +- util/test/openssl_digest_creator_test.cpp | 4 +- util/test/openssl_digest_holder_test.cpp | 4 +- util/test/openssl_utils_test.cpp | 18 +- util/test/sha_hash_tests.cpp | 6 +- 55 files changed, 616 insertions(+), 500 deletions(-) rename util/include/crypto/{digest_type.hpp => digest_parametes.hpp} (100%) rename util/include/{openssl_crypto.hpp => crypto/openssl/crypto.hpp} (70%) create mode 100644 util/src/crypto/factory.cpp rename util/src/{openssl_crypto.cpp => openssl/crypto.cpp} (55%) diff --git a/bftengine/src/bftengine/KeyStore.cpp b/bftengine/src/bftengine/KeyStore.cpp index 4d4d80440c..e1f3133af8 100644 --- a/bftengine/src/bftengine/KeyStore.cpp +++ b/bftengine/src/bftengine/KeyStore.cpp @@ -63,18 +63,19 @@ void ClusterKeyStore::saveReplicaKeyStoreToReserevedPages(const uint16_t& repID) // Save clients keys to res pages and sets `published` to true. void ClientKeyStore::save(const std::string& keys) { - auto hashed_keys = concord::util::SHA3_256().digest(keys.c_str(), keys.size()); + auto hashed_keys = concord::crypto::openssl::SHA3_256().digest(keys.c_str(), keys.size()); auto strHashed_keys = std::string(hashed_keys.begin(), hashed_keys.end()); - ConcordAssertEQ(strHashed_keys.size(), concord::util::SHA3_256::SIZE_IN_BYTES); + ConcordAssertEQ(strHashed_keys.size(), concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES); saveReservedPage(0, strHashed_keys.size(), strHashed_keys.c_str()); published_ = true; LOG_INFO(KEY_EX_LOG, "Clients keys were updated, size " << keys.size()); } std::string ClientKeyStore::load() { - std::string res_page_version(concord::util::SHA3_256::SIZE_IN_BYTES, '\0'); + std::string res_page_version(concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES, '\0'); loadReservedPage(0, res_page_version.length(), res_page_version.data()); - return res_page_version == std::string(concord::util::SHA3_256::SIZE_IN_BYTES, '\0') ? "" : res_page_version; + return res_page_version == std::string(concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES, '\0') ? "" + : res_page_version; } } // namespace bftEngine::impl diff --git a/bftengine/src/preprocessor/RequestProcessingState.cpp b/bftengine/src/preprocessor/RequestProcessingState.cpp index 0aa6977888..7ac9bd0566 100644 --- a/bftengine/src/preprocessor/RequestProcessingState.cpp +++ b/bftengine/src/preprocessor/RequestProcessingState.cpp @@ -20,7 +20,6 @@ namespace preprocessor { using namespace std; using namespace bftEngine; using namespace chrono; -using namespace concord::util; using namespace concord::kvbc::sparse_merkle; uint16_t RequestProcessingState::numOfRequiredEqualReplies_ = 0; @@ -124,9 +123,8 @@ void RequestProcessingState::releaseResources() { preProcessRequestMsg_.reset(); } -void RequestProcessingState::detectNonDeterministicPreProcessing(const SHA3_256::Digest &newHash, - NodeIdType newSenderId, - uint64_t reqRetryId) const { +void RequestProcessingState::detectNonDeterministicPreProcessing( + const concord::crypto::openssl::SHA3_256::Digest &newHash, NodeIdType newSenderId, uint64_t reqRetryId) const { for (auto &hashArray : preProcessingResultHashes_) if ((newHash != hashArray.first) && reqRetryId_ && (reqRetryId_ == reqRetryId)) { // Compare only between matching request/reply retry ids @@ -170,9 +168,10 @@ void RequestProcessingState::handlePreProcessReplyMsg(const PreProcessReplyMsgSh } } -SHA3_256::Digest RequestProcessingState::convertToArray(const uint8_t resultsHash[SHA3_256::SIZE_IN_BYTES]) { - SHA3_256::Digest hashArray; - for (uint64_t i = 0; i < SHA3_256::SIZE_IN_BYTES; i++) hashArray[i] = resultsHash[i]; +concord::crypto::openssl::SHA3_256::Digest RequestProcessingState::convertToArray( + const uint8_t resultsHash[concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES]) { + concord::crypto::openssl::SHA3_256::Digest hashArray; + for (uint64_t i = 0; i < concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES; i++) hashArray[i] = resultsHash[i]; return hashArray; } @@ -205,8 +204,8 @@ bool RequestProcessingState::isReqTimedOut() const { return false; } -std::pair RequestProcessingState::detectFailureDueToBlockID( - const concord::util::SHA3_256::Digest &other, uint64_t blockId) { +std::pair RequestProcessingState::detectFailureDueToBlockID( + const concord::crypto::openssl::SHA3_256::Digest &other, uint64_t blockId) { // Since this scenario is rare, a new string is allocated for safety. std::string modifiedResult(primaryPreProcessResultData_, primaryPreProcessResultLen_); ConcordAssertGT(modifiedResult.size(), sizeof(uint64_t)); @@ -221,11 +220,11 @@ std::pair RequestProcessingState:: "Primary hash is different from quorum due to mismatch in block id" << KVLOG(batchCid_, reqSeqNum_, reqCid_)); return {modifiedResult, modifiedHash}; } - return {"", concord::util::SHA3_256::Digest{}}; + return {"", concord::crypto::openssl::SHA3_256::Digest{}}; } void RequestProcessingState::modifyPrimaryResult( - const std::pair &result) { + const std::pair &result) { memcpy(const_cast(primaryPreProcessResultData_), result.first.c_str(), primaryPreProcessResultLen_); primaryPreProcessResultHash_ = result.second; auto sm = SigManager::instance(); @@ -241,9 +240,11 @@ void RequestProcessingState::modifyPrimaryResult( void RequestProcessingState::reportNonEqualHashes(const unsigned char *chosenData, uint32_t chosenSize) const { // Primary replica calculated hash is different from a hash that passed pre-execution consensus => we don't have // correct pre-processed results. - const auto &primaryHash = - Hash(SHA3_256().digest(primaryPreProcessResultHash_.data(), primaryPreProcessResultHash_.size())).toString(); - const auto &hashPassedConsensus = Hash(SHA3_256().digest(chosenData, chosenSize)).toString(); + const auto &primaryHash = Hash(concord::crypto::openssl::SHA3_256().digest(primaryPreProcessResultHash_.data(), + primaryPreProcessResultHash_.size())) + .toString(); + const auto &hashPassedConsensus = + Hash(concord::crypto::openssl::SHA3_256().digest(chosenData, chosenSize)).toString(); LOG_WARN(logger(), "Primary replica pre-processing result hash: " << primaryHash << " is different from one passed the consensus: " << hashPassedConsensus diff --git a/bftengine/src/preprocessor/RequestProcessingState.hpp b/bftengine/src/preprocessor/RequestProcessingState.hpp index 5d0a7e4a76..af65fdd78f 100644 --- a/bftengine/src/preprocessor/RequestProcessingState.hpp +++ b/bftengine/src/preprocessor/RequestProcessingState.hpp @@ -80,21 +80,21 @@ class RequestProcessingState { void resetRejectedReplicasList() { rejectedReplicaIds_.clear(); } void setPreprocessingRightNow(bool set) { preprocessingRightNow_ = set; } const std::set& getPreProcessResultSignatures(); - const concord::util::SHA3_256::Digest& getResultHash() { return primaryPreProcessResultHash_; }; + const concord::crypto::openssl::SHA3_256::Digest& getResultHash() { return primaryPreProcessResultHash_; }; const bftEngine::OperationResult getAgreedPreProcessResult() const { return agreedPreProcessResult_; } static void init(uint16_t numOfRequiredReplies, preprocessor::PreProcessorRecorder* histograms); uint16_t getNumOfReceivedReplicas() { return numOfReceivedReplies_; }; private: - static concord::util::SHA3_256::Digest convertToArray( - const uint8_t resultsHash[concord::util::SHA3_256::SIZE_IN_BYTES]); + static concord::crypto::openssl::SHA3_256::Digest convertToArray( + const uint8_t resultsHash[concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES]); static logging::Logger& logger() { static logging::Logger logger_ = logging::getLogger("concord.preprocessor"); return logger_; } auto calculateMaxNbrOfEqualHashes(uint16_t& maxNumOfEqualHashes) const; - void detectNonDeterministicPreProcessing(const concord::util::SHA3_256::Digest& newHash, + void detectNonDeterministicPreProcessing(const concord::crypto::openssl::SHA3_256::Digest& newHash, NodeIdType newSenderId, uint64_t reqRetryId) const; void setupPreProcessResultData(bftEngine::OperationResult preProcessResult); @@ -103,11 +103,11 @@ class RequestProcessingState { void reportNonEqualHashes(const unsigned char* chosenData, uint32_t chosenSize) const; // Detect if a hash is different from the input parameter because of the appended block id. - std::pair detectFailureDueToBlockID( - const concord::util::SHA3_256::Digest&, uint64_t); + std::pair detectFailureDueToBlockID( + const concord::crypto::openssl::SHA3_256::Digest&, uint64_t); // Set a new block id at the end of the result. - void modifyPrimaryResult(const std::pair&); + void modifyPrimaryResult(const std::pair&); private: static uint16_t numOfRequiredEqualReplies_; @@ -132,10 +132,10 @@ class RequestProcessingState { uint32_t primaryPreProcessResultLen_ = 0; bftEngine::OperationResult primaryPreProcessResult_ = bftEngine::OperationResult::UNKNOWN; bftEngine::OperationResult agreedPreProcessResult_ = bftEngine::OperationResult::UNKNOWN; - concord::util::SHA3_256::Digest primaryPreProcessResultHash_ = {}; + concord::crypto::openssl::SHA3_256::Digest primaryPreProcessResultHash_ = {}; // Maps result hash to a list of replica signatures sent for this hash. This also implicitly gives the number of // replicas returning a specific hash. - std::map> preProcessingResultHashes_; + std::map> preProcessingResultHashes_; bool preprocessingRightNow_ = false; uint64_t reqRetryId_ = 0; }; diff --git a/bftengine/src/preprocessor/messages/PreProcessReplyMsg.cpp b/bftengine/src/preprocessor/messages/PreProcessReplyMsg.cpp index 7c3a2b1fde..dfb1d918b7 100644 --- a/bftengine/src/preprocessor/messages/PreProcessReplyMsg.cpp +++ b/bftengine/src/preprocessor/messages/PreProcessReplyMsg.cpp @@ -84,7 +84,7 @@ void PreProcessReplyMsg::validate(const ReplicasInfo& repInfo) const { concord::diagnostics::TimeRecorder scoped_timer(*preProcessorHistograms_->verifyPreProcessReplySig); if (!sigManager->verifySig(msgHeader.senderId, msgBody()->resultsHash, - SHA3_256::SIZE_IN_BYTES, + concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES, reinterpret_cast(msgBody()) + headerSize, sigLen)) throw runtime_error(__PRETTY_FUNCTION__ + string(": verifySig failed")); @@ -151,17 +151,19 @@ void PreProcessReplyMsg::setupMsgBody(const char* preProcessResultBuf, msgBody()->preProcessResult, msgBody()->clientId, msgBody()->reqSeqNum); - memcpy(msgBody()->resultsHash, hash.data(), SHA3_256::SIZE_IN_BYTES); + memcpy(msgBody()->resultsHash, hash.data(), concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES); { concord::diagnostics::TimeRecorder scoped_timer(*preProcessorHistograms_->signPreProcessReplyHash); - sigManager->sign(hash.data(), SHA3_256::SIZE_IN_BYTES, reinterpret_cast(body() + sizeof(Header))); + sigManager->sign(hash.data(), + concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES, + reinterpret_cast(body() + sizeof(Header))); } setLeftMsgParams(reqCid, sigSize); } // Used by PreProcessBatchReplyMsg while retrieving PreProcessReplyMsgs from the batch void PreProcessReplyMsg::setupMsgBody(const uint8_t* resultsHash, const char* signature, const string& reqCid) { - memcpy(msgBody()->resultsHash, resultsHash, SHA3_256::SIZE_IN_BYTES); + memcpy(msgBody()->resultsHash, resultsHash, concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES); const uint16_t sigLen = SigManager::instance()->getMySigLength(); memcpy(body() + sizeof(Header), signature, sigLen); setLeftMsgParams(reqCid, sigLen); diff --git a/bftengine/src/preprocessor/messages/PreProcessReplyMsg.hpp b/bftengine/src/preprocessor/messages/PreProcessReplyMsg.hpp index 298514b897..36143df42d 100644 --- a/bftengine/src/preprocessor/messages/PreProcessReplyMsg.hpp +++ b/bftengine/src/preprocessor/messages/PreProcessReplyMsg.hpp @@ -75,7 +75,7 @@ class PreProcessReplyMsg : public MessageBase { uint16_t reqOffsetInBatch = 0; ReplyStatus status = STATUS_GOOD; bftEngine::OperationResult preProcessResult = bftEngine::OperationResult::UNKNOWN; - uint8_t resultsHash[concord::util::SHA3_256::SIZE_IN_BYTES]; + uint8_t resultsHash[concord::crypto::openssl::SHA3_256::SIZE_IN_BYTES]; uint32_t replyLength = 0; uint32_t cidLength = 0; uint64_t reqRetryId = 0; diff --git a/bftengine/src/preprocessor/messages/PreProcessResultHashCreator.hpp b/bftengine/src/preprocessor/messages/PreProcessResultHashCreator.hpp index f38ca48146..513db76c9a 100644 --- a/bftengine/src/preprocessor/messages/PreProcessResultHashCreator.hpp +++ b/bftengine/src/preprocessor/messages/PreProcessResultHashCreator.hpp @@ -18,12 +18,12 @@ namespace preprocessor { class PreProcessResultHashCreator { public: - static concord::util::SHA3_256::Digest create(const char* preProcessResultData, - uint32_t preProcessResultLen, - bftEngine::OperationResult preProcessResult, - uint16_t clientId, - ReqId reqSeqNum) { - auto dataDigest = concord::util::SHA3_256(); + static concord::crypto::openssl::SHA3_256::Digest create(const char* preProcessResultData, + uint32_t preProcessResultLen, + bftEngine::OperationResult preProcessResult, + uint16_t clientId, + ReqId reqSeqNum) { + auto dataDigest = concord::crypto::openssl::SHA3_256(); dataDigest.init(); if (preProcessResult == bftEngine::OperationResult::SUCCESS) dataDigest.update(preProcessResultData, preProcessResultLen); diff --git a/bftengine/src/preprocessor/tests/preprocessor_test.cpp b/bftengine/src/preprocessor/tests/preprocessor_test.cpp index 691c2f9c7a..3b9d3d5975 100644 --- a/bftengine/src/preprocessor/tests/preprocessor_test.cpp +++ b/bftengine/src/preprocessor/tests/preprocessor_test.cpp @@ -493,7 +493,8 @@ TEST(requestPreprocessingState_test, changePrimaryBlockId) { memcpy(buf + bufLen - sizeof(uint64_t), reinterpret_cast(&primaryBlockId), sizeof(uint64_t)); reqState.handlePrimaryPreProcessed(buf, bufLen, OperationResult::SUCCESS); - concord::util::SHA3_256::Digest replicasHash = *((concord::util::SHA3_256::Digest*)reply->resultsHash()); + concord::crypto::openssl::SHA3_256::Digest replicasHash = + *((concord::crypto::openssl::SHA3_256::Digest*)reply->resultsHash()); ConcordAssertNE(replicasHash, reqState.getResultHash()); ConcordAssertEQ(reqState.definePreProcessingConsensusResult(), COMPLETE); ConcordAssertEQ(replicasHash, reqState.getResultHash()); diff --git a/bftengine/tests/KeyStore/KeyStore_test.cpp b/bftengine/tests/KeyStore/KeyStore_test.cpp index eb6b21566b..da6fba565f 100644 --- a/bftengine/tests/KeyStore/KeyStore_test.cpp +++ b/bftengine/tests/KeyStore/KeyStore_test.cpp @@ -52,7 +52,7 @@ TEST(checkAndSetState_set_true, ClientKeyStore) { cks.save(str_ser); ASSERT_TRUE(cks.published()); auto loaded_keys = cks.load(); - auto hashed_keys = concord::util::SHA3_256().digest(str_ser.c_str(), str_ser.size()); + auto hashed_keys = concord::crypto::openssl::SHA3_256().digest(str_ser.c_str(), str_ser.size()); auto strHashed_keys = std::string(hashed_keys.begin(), hashed_keys.end()); ASSERT_EQ(loaded_keys, strHashed_keys); } diff --git a/bftengine/tests/bcstatetransfer/bcstatetransfer_tests.cpp b/bftengine/tests/bcstatetransfer/bcstatetransfer_tests.cpp index b0ff119d2f..9134efa074 100644 --- a/bftengine/tests/bcstatetransfer/bcstatetransfer_tests.cpp +++ b/bftengine/tests/bcstatetransfer/bcstatetransfer_tests.cpp @@ -3028,7 +3028,7 @@ TEST_F(BcStTest, bkpTestRvbDataConflictDetection) { ASSERT_TRUE(datastore_->hasCheckpointDesc(i)); DataStore::CheckpointDesc desc = datastore_->getCheckpointDesc(i); - digest::Digest stateDigest, reservedPagesDigest, rvbDataDigest; + Digest stateDigest, reservedPagesDigest, rvbDataDigest; uint64_t outBlockId; stateTransfer_->getDigestOfCheckpoint( diff --git a/bftengine/tests/messages/ReplicaAsksToLeaveViewMsg_test.cpp b/bftengine/tests/messages/ReplicaAsksToLeaveViewMsg_test.cpp index 194878ad1c..fa1261d468 100644 --- a/bftengine/tests/messages/ReplicaAsksToLeaveViewMsg_test.cpp +++ b/bftengine/tests/messages/ReplicaAsksToLeaveViewMsg_test.cpp @@ -12,14 +12,11 @@ #include "gtest/gtest.h" #include "helper.hpp" -#include "crypto/digest_type.hpp" #include "ViewsManager.hpp" #include "ReplicasInfo.hpp" #include "SigManager.hpp" #include "messages/MsgCode.hpp" #include "messages/ReplicaAsksToLeaveViewMsg.hpp" -#include "bftengine/ClientMsgs.hpp" -#include "bftengine/ReplicaConfig.hpp" #include "ReservedPagesMock.hpp" #include "EpochManager.hpp" diff --git a/bftengine/tests/messages/ViewChangeMsg_test.cpp b/bftengine/tests/messages/ViewChangeMsg_test.cpp index 490817ce9f..334958b7ee 100644 --- a/bftengine/tests/messages/ViewChangeMsg_test.cpp +++ b/bftengine/tests/messages/ViewChangeMsg_test.cpp @@ -12,7 +12,7 @@ #include "gtest/gtest.h" #include "helper.hpp" -#include "crypto/digest_type.hpp" +#include "crypto/digest_parametes.hpp" #include "ViewsManager.hpp" #include "ReplicasInfo.hpp" #include "SigManager.hpp" diff --git a/client/clientservice/include/client/clientservice/state_snapshot_service.hpp b/client/clientservice/include/client/clientservice/state_snapshot_service.hpp index 2adee4155a..8a7d243514 100644 --- a/client/clientservice/include/client/clientservice/state_snapshot_service.hpp +++ b/client/clientservice/include/client/clientservice/state_snapshot_service.hpp @@ -41,7 +41,7 @@ class StateSnapshotServiceImpl final private: void isHashValid(uint64_t snapshot_id, - const concord::util::SHA3_256::Digest& final_hash, + const concord::crypto::openssl::SHA3_256::Digest& final_hash, const std::chrono::milliseconds& timeout, grpc::Status& return_status); diff --git a/client/clientservice/src/state_snapshot_service.cpp b/client/clientservice/src/state_snapshot_service.cpp index 77648df82e..d95ebe6566 100644 --- a/client/clientservice/src/state_snapshot_service.cpp +++ b/client/clientservice/src/state_snapshot_service.cpp @@ -59,12 +59,14 @@ using namespace std; namespace concord::client::clientservice { -static concord::util::SHA3_256::Digest singleHash(const std::string& key) { - return concord::util::SHA3_256{}.digest(key.data(), key.size()); +static concord::crypto::openssl::SHA3_256::Digest singleHash(const std::string& key) { + return concord::crypto::openssl::SHA3_256{}.digest(key.data(), key.size()); } -static void nextHash(const std::string& key, const std::string& value, concord::util::SHA3_256::Digest& prev_hash) { - auto hasher = concord::util::SHA3_256{}; +static void nextHash(const std::string& key, + const std::string& value, + concord::crypto::openssl::SHA3_256::Digest& prev_hash) { + auto hasher = concord::crypto::openssl::SHA3_256{}; hasher.init(); hasher.update(prev_hash.data(), prev_hash.size()); const auto key_hash = singleHash(key); @@ -362,7 +364,7 @@ Status StateSnapshotServiceImpl::StreamSnapshot(ServerContext* context, } void StateSnapshotServiceImpl::isHashValid(uint64_t snapshot_id, - const concord::util::SHA3_256::Digest& final_hash, + const concord::crypto::openssl::SHA3_256::Digest& final_hash, const chrono::milliseconds& timeout, Status& return_status) { auto read_config = std::shared_ptr( diff --git a/client/thin-replica-client/include/client/thin-replica-client/trc_hash.hpp b/client/thin-replica-client/include/client/thin-replica-client/trc_hash.hpp index 75b9bbda06..3d9246245c 100644 --- a/client/thin-replica-client/include/client/thin-replica-client/trc_hash.hpp +++ b/client/thin-replica-client/include/client/thin-replica-client/trc_hash.hpp @@ -17,13 +17,13 @@ #define TRC_HASH_HPP_ #include -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" #include "thin_replica.grpc.pb.h" #include "client/concordclient/event_update.hpp" namespace client::thin_replica_client { -const size_t kThinReplicaHashLength = concord::util::openssl_utils::kExpectedSHA256HashLengthInBytes; +const size_t kThinReplicaHashLength = concord::crypto::openssl::kExpectedSHA256HashLengthInBytes; // Compute the Thin Replica Mechanism hash of a given update; the hash is // returned as a byte string stored in an std::string and should be of length diff --git a/client/thin-replica-client/src/trc_hash.cpp b/client/thin-replica-client/src/trc_hash.cpp index 156a6062d2..82d4f24a68 100644 --- a/client/thin-replica-client/src/trc_hash.cpp +++ b/client/thin-replica-client/src/trc_hash.cpp @@ -23,7 +23,7 @@ using com::vmware::concord::thin_replica::Data; using concord::client::concordclient::EventVariant; using concord::client::concordclient::EventGroup; using concord::client::concordclient::Update; -using concord::util::openssl_utils::computeSHA256Hash; +using concord::crypto::openssl::computeSHA256Hash; using std::invalid_argument; using std::list; using std::map; diff --git a/examples/replica/src/KVCommandHandler.cpp b/examples/replica/src/KVCommandHandler.cpp index 56d98333c7..84fb045691 100644 --- a/examples/replica/src/KVCommandHandler.cpp +++ b/examples/replica/src/KVCommandHandler.cpp @@ -42,7 +42,7 @@ using concord::osexample::kv::messages::KVRequest; using concord::osexample::kv::messages::KVWriteReply; using concord::osexample::kv::messages::KVWriteRequest; -using Hasher = concord::util::SHA3_256; +using Hasher = concord::crypto::openssl::SHA3_256; using Hash = Hasher::Digest; const uint64_t LONG_EXEC_CMD_TIME_IN_SEC = 11; diff --git a/kvbc/benchmark/sparse_merkle_benchmark.cpp b/kvbc/benchmark/sparse_merkle_benchmark.cpp index 8eb06bf5c5..902d2ced04 100644 --- a/kvbc/benchmark/sparse_merkle_benchmark.cpp +++ b/kvbc/benchmark/sparse_merkle_benchmark.cpp @@ -264,7 +264,7 @@ void calculateSha2(benchmark::State &state) { void calculateSha3(benchmark::State &state) { const auto value = randomBuffer(state.range(0)); - auto hasher = SHA3_256{}; + auto hasher = concord::crypto::openssl::SHA3_256{}; for (auto _ : state) { const auto hash = hasher.digest(value.data(), value.size()); diff --git a/kvbc/benchmark/state_snapshot_benchmarks/hash_state_benchmark.cpp b/kvbc/benchmark/state_snapshot_benchmarks/hash_state_benchmark.cpp index 5f574910fc..dd2979f6db 100644 --- a/kvbc/benchmark/state_snapshot_benchmarks/hash_state_benchmark.cpp +++ b/kvbc/benchmark/state_snapshot_benchmarks/hash_state_benchmark.cpp @@ -199,7 +199,7 @@ int run(int argc, char* argv[]) { auto db = NativeClient::newClient(config["rocksdb-path"].as(), read_only, opts); // Start with an arbitrary hash - SHA2-256('a'). - auto current_hash = SHA2_256{}.digest("a", 1); + auto current_hash = concord::crypto::openssl::SHA2_256{}.digest("a", 1); const auto time = Time{}; auto multi_get_batch = MultiGetBatch{static_cast(point_lookup_batch_size), static_cast(point_lookup_threads)}; @@ -243,7 +243,7 @@ int run(int argc, char* argv[]) { for (auto j = 0ull; j < serialized_keys.size(); ++j) { ConcordAssert(statuses[j].ok()); bytes_read += (serialized_keys[j].size() + value_slices[j].size()); - auto h = SHA2_256{}; + auto h = concord::crypto::openssl::SHA2_256{}; h.init(); h.update(current_hash.data(), current_hash.size()); const auto& ver_key = multi_get_batch[key_idx]; diff --git a/kvbc/include/categorization/base_types.h b/kvbc/include/categorization/base_types.h index 054c1a2864..3e9cc00043 100644 --- a/kvbc/include/categorization/base_types.h +++ b/kvbc/include/categorization/base_types.h @@ -25,7 +25,7 @@ namespace concord::kvbc::categorization { -using Hasher = concord::util::SHA3_256; +using Hasher = concord::crypto::openssl::SHA3_256; using Hash = Hasher::Digest; struct BasicValue { diff --git a/kvbc/include/direct_kv_block.h b/kvbc/include/direct_kv_block.h index 80fb5de356..ab58f60ac8 100644 --- a/kvbc/include/direct_kv_block.h +++ b/kvbc/include/direct_kv_block.h @@ -15,7 +15,7 @@ #include "kv_types.hpp" #include "sliver.hpp" -#include "crypto/digest_type.hpp" +#include "crypto/digest_parametes.hpp" #include "crypto/digest.hpp" #include diff --git a/kvbc/include/sparse_merkle/base_types.h b/kvbc/include/sparse_merkle/base_types.h index 9ebd177ecb..abadc5aa95 100644 --- a/kvbc/include/sparse_merkle/base_types.h +++ b/kvbc/include/sparse_merkle/base_types.h @@ -229,7 +229,7 @@ class Hasher { } private: - util::SHA3_256 sha3_256; + concord::crypto::openssl::SHA3_256 sha3_256; }; static const Hash PLACEHOLDER_HASH = Hash(Hash::EMPTY_BUF); diff --git a/kvbc/src/direct_kv_db_adapter.cpp b/kvbc/src/direct_kv_db_adapter.cpp index 6fb118599a..d810b68627 100644 --- a/kvbc/src/direct_kv_db_adapter.cpp +++ b/kvbc/src/direct_kv_db_adapter.cpp @@ -78,8 +78,8 @@ Key S3KeyGenerator::blockKey(const BlockId &blockId) const { } Key S3KeyGenerator::dataKey(const Key &key, const BlockId &blockId) const { - auto digest = concord::util::SHA3_256().digest(key.data(), key.length()); - auto digest_str = concord::util::SHA3_256().toHexString(digest); + auto digest = concord::crypto::openssl::SHA3_256().digest(key.data(), key.length()); + auto digest_str = concord::crypto::openssl::SHA3_256().toHexString(digest); LOG_DEBUG(logger(), prefix_ + std::string("keys/") + digest_str); return prefix_ + std::string("keys/") + digest_str; } diff --git a/kvbc/src/kvbc_app_filter/kvbc_app_filter.cpp b/kvbc/src/kvbc_app_filter/kvbc_app_filter.cpp index 7b022b11ea..33b1a93da1 100644 --- a/kvbc/src/kvbc_app_filter/kvbc_app_filter.cpp +++ b/kvbc/src/kvbc_app_filter/kvbc_app_filter.cpp @@ -27,7 +27,7 @@ #include "concord_kvbc.pb.h" #include "kv_types.hpp" #include "kvbc_app_filter/kvbc_key_types.h" -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" using namespace std::chrono_literals; @@ -42,8 +42,8 @@ using com::vmware::concord::kvbc::ValueWithTrids; using concord::kvbc::BlockId; using concord::kvbc::categorization::ImmutableInput; using concord::kvbc::InvalidBlockRange; -using concord::util::openssl_utils::computeSHA256Hash; -using concord::util::openssl_utils::kExpectedSHA256HashLengthInBytes; +using concord::crypto::openssl::computeSHA256Hash; +using concord::crypto::openssl::kExpectedSHA256HashLengthInBytes; namespace concord { namespace kvbc { diff --git a/kvbc/test/kvbc_app_filter/kvbc_filter_test.cpp b/kvbc/test/kvbc_app_filter/kvbc_filter_test.cpp index eddcbbab10..de1b04334a 100644 --- a/kvbc/test/kvbc_app_filter/kvbc_filter_test.cpp +++ b/kvbc/test/kvbc_app_filter/kvbc_filter_test.cpp @@ -25,7 +25,7 @@ #include "kv_types.hpp" #include "memorydb/client.h" #include "memorydb/key_comparator.h" -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" #include "status.hpp" #include "concord_kvbc.pb.h" @@ -45,7 +45,7 @@ using concord::kvbc::KvbFilteredUpdate; using concord::kvbc::KvbFilteredEventGroupUpdate; using concord::kvbc::KvbUpdate; using concord::kvbc::NoLegacyEvents; -using concord::util::openssl_utils::computeSHA256Hash; +using concord::crypto::openssl::computeSHA256Hash; namespace { diff --git a/kvbc/test/migrations/block_merkle_latest_ver_cf_migration_test.cpp b/kvbc/test/migrations/block_merkle_latest_ver_cf_migration_test.cpp index be5bb35722..62e4da5357 100644 --- a/kvbc/test/migrations/block_merkle_latest_ver_cf_migration_test.cpp +++ b/kvbc/test/migrations/block_merkle_latest_ver_cf_migration_test.cpp @@ -142,7 +142,7 @@ class block_merkle_latest_ver_cf_migration_test : public Test { // Firstly, accumulate the key-values in a write batch, with the key hashes as keys. it.first(); while (it) { - const auto hash = SHA3_256{}.digest(it.keyView().data(), it.keyView().size()); + const auto hash = concord::crypto::openssl::SHA3_256{}.digest(it.keyView().data(), it.keyView().size()); batch.put(BLOCK_MERKLE_LATEST_KEY_VERSION_CF, hash, it.valueView()); it.next(); } diff --git a/kvbc/test/sparse_merkle/internal_node_property_tests.cpp b/kvbc/test/sparse_merkle/internal_node_property_tests.cpp index c1ad0ca33d..d0550c2560 100644 --- a/kvbc/test/sparse_merkle/internal_node_property_tests.cpp +++ b/kvbc/test/sparse_merkle/internal_node_property_tests.cpp @@ -21,7 +21,7 @@ #include "crypto/openssl/hash.hpp" using concordUtils::Sliver; -using concord::util::SHA3_256; +using concord::crypto::openssl::SHA3_256; using namespace concord::kvbc::sparse_merkle; static constexpr size_t ROOT_INDEX = 0; diff --git a/secretsmanager/src/aes.cpp b/secretsmanager/src/aes.cpp index bd3f60b3fd..9b91a93227 100644 --- a/secretsmanager/src/aes.cpp +++ b/secretsmanager/src/aes.cpp @@ -14,7 +14,7 @@ // This convenience header combines different block implementations. #include "aes.h" -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" #include "assertUtils.hpp" #include "ReplicaConfig.hpp" @@ -25,8 +25,8 @@ namespace concord::secretsmanager { using std::vector; using std::string; using std::unique_ptr; -using concord::util::openssl_utils::OPENSSL_SUCCESS; -using concord::util::openssl_utils::UniqueOpenSSLCipherContext; +using concord::crypto::openssl::OPENSSL_SUCCESS; +using concord::crypto::openssl::UniqueCipherContext; using bftEngine::ReplicaConfig; using concord::crypto::SIGN_VERIFY_ALGO; @@ -61,7 +61,7 @@ vector AES_CBC::encrypt(const string& input) { plaintext.get()[i] = (unsigned char)input[i]; } - UniqueOpenSSLCipherContext ctx(EVP_CIPHER_CTX_new()); + UniqueCipherContext ctx(EVP_CIPHER_CTX_new()); ConcordAssert(nullptr != ctx); int c_len{0}; @@ -95,7 +95,7 @@ string AES_CBC::decrypt(const vector& cipher) { int c_len{0}, f_len{0}; unique_ptr plaintext(new unsigned char[cipherLength]); - UniqueOpenSSLCipherContext ctx(EVP_CIPHER_CTX_new()); + UniqueCipherContext ctx(EVP_CIPHER_CTX_new()); ConcordAssert(nullptr != ctx); ConcordAssert(OPENSSL_SUCCESS == EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_cbc(), nullptr, key.data(), iv.data())); diff --git a/tests/simpleKVBC/TesterReplica/internalCommandsHandler.cpp b/tests/simpleKVBC/TesterReplica/internalCommandsHandler.cpp index 43d7bd21d2..ffa660a24b 100644 --- a/tests/simpleKVBC/TesterReplica/internalCommandsHandler.cpp +++ b/tests/simpleKVBC/TesterReplica/internalCommandsHandler.cpp @@ -44,7 +44,7 @@ using skvbc::messages::SKVBCRequest; using skvbc::messages::SKVBCWriteReply; using skvbc::messages::SKVBCWriteRequest; -using Hasher = concord::util::SHA3_256; +using Hasher = concord::crypto::openssl::SHA3_256; using Hash = Hasher::Digest; const uint64_t LONG_EXEC_CMD_TIME_IN_SEC = 11; diff --git a/threshsign/include/threshsign/eddsa/SingleEdDSASignature.h b/threshsign/include/threshsign/eddsa/SingleEdDSASignature.h index 36f8fe93cd..fdff04876c 100644 --- a/threshsign/include/threshsign/eddsa/SingleEdDSASignature.h +++ b/threshsign/include/threshsign/eddsa/SingleEdDSASignature.h @@ -20,5 +20,5 @@ */ struct SingleEdDSASignature { uint64_t id; - std::array signatureBytes; + std::array signatureBytes; }; \ No newline at end of file diff --git a/threshsign/src/ThresholdSignaturesTypes.cpp b/threshsign/src/ThresholdSignaturesTypes.cpp index 0e21e3bcc9..867f96ea26 100644 --- a/threshsign/src/ThresholdSignaturesTypes.cpp +++ b/threshsign/src/ThresholdSignaturesTypes.cpp @@ -236,7 +236,7 @@ void Cryptosystem::validatePublicKey(const std::string& key) const { void Cryptosystem::validateVerificationKey(const std::string& key) const { #ifdef USE_EDDSA_OPENSSL - constexpr const size_t expectedKeyLength = concord::crypto::openssl::EdDSAPublicKeyByteSize * 2; + constexpr const size_t expectedKeyLength = concord::crypto::Ed25519PublicKeyByteSize * 2; #else constexpr const size_t expectedKeyLength = 130u; #endif @@ -246,7 +246,7 @@ void Cryptosystem::validateVerificationKey(const std::string& key) const { void Cryptosystem::validatePrivateKey(const std::string& key) const { #ifdef USE_EDDSA_OPENSSL - constexpr const size_t expectedKeyLength = concord::crypto::openssl::EdDSAPrivateKeyByteSize * 2; + constexpr const size_t expectedKeyLength = concord::crypto::Ed25519PrivateKeyByteSize * 2; #else // We currently do not validate the length of the private key's string // representation because the length of its serialization varies slightly. diff --git a/threshsign/src/eddsa/EdDSAMultisigFactory.cpp b/threshsign/src/eddsa/EdDSAMultisigFactory.cpp index b2ea7c6188..6f2df0a338 100644 --- a/threshsign/src/eddsa/EdDSAMultisigFactory.cpp +++ b/threshsign/src/eddsa/EdDSAMultisigFactory.cpp @@ -12,17 +12,17 @@ #include #include #include "threshsign/eddsa/EdDSAMultisigFactory.h" -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" #include "threshsign/eddsa/EdDSAThreshsignKeys.h" #include "threshsign/eddsa/EdDSAMultisigSigner.h" #include "threshsign/eddsa/EdDSAMultisigVerifier.h" #include #include -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" -using concord::util::openssl_utils::UniquePKEY; -using concord::util::openssl_utils::UniqueOpenSSLPKEYContext; -using concord::util::openssl_utils::OPENSSL_SUCCESS; +using concord::crypto::openssl::UniquePKEY; +using concord::crypto::openssl::UniquePKEYContext; +using concord::crypto::openssl::OPENSSL_SUCCESS; IThresholdVerifier *EdDSAMultisigFactory::newVerifier(ShareID reqSigners, ShareID totalSigners, @@ -79,7 +79,7 @@ std::pair, std::unique_ptr(i, replicaPublicKeys[i])); @@ -127,7 +127,7 @@ Cryptosystem* inputReplicaKeyfileMultisig(const std::string& filename, ReplicaCo if ("rsa" == mainKeyAlgo) { validateRSAPrivateKey(config.replicaPrivateKey); } else if ("eddsa" == mainKeyAlgo) { - constexpr const size_t expectedKeyLength = EdDSAPrivateKeyByteSize * 2; + constexpr const size_t expectedKeyLength = Ed25519PrivateKeyByteSize * 2; isValidKey("EdDSA private", config.replicaPrivateKey, expectedKeyLength); } diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index a88f80a9ac..2aa667061f 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -20,8 +20,8 @@ set(util_source_files src/config_file_parser.cpp src/crypto/cryptopp/digest_creator.cpp src/io.cpp) -add_library(util STATIC ${util_source_files}) -add_library(util_shared SHARED ${util_source_files}) +add_library(util STATIC ${util_source_files} src/crypto/factory.cpp) +add_library(util_shared SHARED ${util_source_files} src/crypto/factory.cpp) # Use below macros to use CryptoPP's SHA_256 or OpenSSL's SHA_256 hashing. # USE_CRYPTOPP_SHA_256 @@ -32,8 +32,8 @@ if(USE_OPENSSL) if(NOT BUILD_THIRDPARTY) find_package(OpenSSL REQUIRED) endif() - target_sources(util PRIVATE src/openssl_crypto.cpp) - target_sources(util_shared PRIVATE src/openssl_crypto.cpp) + target_sources(util PRIVATE src/openssl/crypto.cpp) + target_sources(util_shared PRIVATE src/openssl/crypto.cpp) target_link_libraries(util PUBLIC OpenSSL::Crypto) target_link_libraries(util_shared PUBLIC OpenSSL::Crypto) target_compile_definitions(util PUBLIC USE_OPENSSL) diff --git a/util/include/crypto/crypto.hpp b/util/include/crypto/crypto.hpp index 79e0c39409..eaf8c35ac3 100644 --- a/util/include/crypto/crypto.hpp +++ b/util/include/crypto/crypto.hpp @@ -24,6 +24,10 @@ enum SignatureAlgorithm : uint32_t { Uninitialized = 0, BLS = 1, EdDSA = 2, RSA enum class KeyFormat : uint16_t { HexaDecimalStrippedFormat, PemFormat }; enum class CurveType : uint16_t { secp256k1, secp384r1 }; +static constexpr const size_t Ed25519PrivateKeyByteSize = 32UL; +static constexpr const size_t Ed25519PublicKeyByteSize = 32UL; +static constexpr const size_t Ed25519SignatureByteSize = 64UL; + /** * @brief Generates an EdDSA asymmetric key pair (private-public key pair). * @@ -32,6 +36,9 @@ enum class CurveType : uint16_t { secp256k1, secp384r1 }; */ std::pair generateEdDSAKeyPair(const KeyFormat fmt = KeyFormat::HexaDecimalStrippedFormat); +std::pair generateECDSAKeyPair(CurveType type, + const KeyFormat fmt = KeyFormat::HexaDecimalStrippedFormat); + /** * @brief Generates an EdDSA PEM file from hexadecimal key pair (private-public key pair). * diff --git a/util/include/crypto/cryptopp/digest_creator.hpp b/util/include/crypto/cryptopp/digest_creator.hpp index 7041133e70..164552b53c 100644 --- a/util/include/crypto/cryptopp/digest_creator.hpp +++ b/util/include/crypto/cryptopp/digest_creator.hpp @@ -12,7 +12,7 @@ #pragma once #include "crypto/digest_creator.hpp" -#include "crypto/digest_type.hpp" +#include "crypto/digest_parametes.hpp" #if defined MD5_DIGEST #include diff --git a/util/include/crypto/digest.hpp b/util/include/crypto/digest.hpp index 2cdfbedaf4..5a3a66db14 100644 --- a/util/include/crypto/digest.hpp +++ b/util/include/crypto/digest.hpp @@ -11,7 +11,6 @@ #pragma once -#include "digest_type.hpp" #include "digest_holder.hpp" #if defined USE_CRYPTOPP_SHA_256 @@ -26,8 +25,8 @@ namespace concord::crypto { using Digest = DigestHolder; using DigestGenerator = concord::crypto::cryptopp::CryptoppDigestCreator; #elif defined USE_OPENSSL_SHA_256 -using Digest = DigestHolder >; -using DigestGenerator = concord::crypto::openssl::OpenSSLDigestCreator; +using Digest = DigestHolder >; +using DigestGenerator = concord::crypto::openssl::OpenSSLDigestCreator; #endif static_assert(DIGEST_SIZE >= sizeof(uint64_t), "Digest size should be >= sizeof(uint64_t)"); diff --git a/util/include/crypto/digest_holder.hpp b/util/include/crypto/digest_holder.hpp index 31a371dc93..a5d5f7fa30 100644 --- a/util/include/crypto/digest_holder.hpp +++ b/util/include/crypto/digest_holder.hpp @@ -14,8 +14,8 @@ #include #include -#include "digest_type.hpp" -#include "crypto/openssl/digest_creator.hpp" +#include "digest_creator.hpp" +#include "digest_parametes.hpp" #include "hex_tools.h" namespace concord::crypto { diff --git a/util/include/crypto/digest_type.hpp b/util/include/crypto/digest_parametes.hpp similarity index 100% rename from util/include/crypto/digest_type.hpp rename to util/include/crypto/digest_parametes.hpp diff --git a/util/include/crypto/factory.hpp b/util/include/crypto/factory.hpp index bbc98c96c5..e1cd83c69a 100644 --- a/util/include/crypto/factory.hpp +++ b/util/include/crypto/factory.hpp @@ -20,56 +20,31 @@ #include "Logger.hpp" namespace concord::crypto { + enum class SIGN_VERIFY_ALGO : uint8_t { ECDSA, RSA, EDDSA }; +enum class Provider : uint16_t { OpenSSL, CryptoPP }; + +constexpr static const Provider DefaultProvider = Provider::OpenSSL; +/** + * This class hides the implementation details from users of cryptographic algorithms + * and allows the addition and removal of libraries in a single place + */ class Factory { public: static std::unique_ptr getSigner( const std::string& signingKey, SIGN_VERIFY_ALGO signingAlgo, - concord::crypto::KeyFormat fmt = concord::crypto::KeyFormat::HexaDecimalStrippedFormat) { - switch (signingAlgo) { - case SIGN_VERIFY_ALGO::ECDSA: { - return std::unique_ptr(new concord::crypto::cryptopp::ECDSASigner(signingKey, fmt)); - } - case SIGN_VERIFY_ALGO::RSA: { - return std::unique_ptr(new concord::crypto::cryptopp::RSASigner(signingKey, fmt)); - } - case SIGN_VERIFY_ALGO::EDDSA: { - using MainReplicaSigner = concord::crypto::openssl::EdDSASigner; - const auto signingKeyObject = - concord::crypto::openssl::deserializeKey(signingKey, fmt); - return std::unique_ptr(new MainReplicaSigner(signingKeyObject.getBytes())); - } - default: - LOG_ERROR(EDDSA_SIG_LOG, "Invalid signing algorithm."); - return {}; - } - } + concord::crypto::KeyFormat fmt = concord::crypto::KeyFormat::HexaDecimalStrippedFormat, + Provider provider = DefaultProvider); static std::unique_ptr getVerifier( const std::string& verificationKey, SIGN_VERIFY_ALGO verifierAlgo, - concord::crypto::KeyFormat fmt = concord::crypto::KeyFormat::HexaDecimalStrippedFormat) { - switch (verifierAlgo) { - case SIGN_VERIFY_ALGO::ECDSA: { - return std::unique_ptr( - new concord::crypto::cryptopp::ECDSAVerifier(verificationKey, fmt)); - } - case SIGN_VERIFY_ALGO::RSA: { - return std::unique_ptr( - new concord::crypto::cryptopp::RSAVerifier(verificationKey, fmt)); - } - case SIGN_VERIFY_ALGO::EDDSA: { - using MainReplicaVerifier = concord::crypto::openssl::EdDSAVerifier; - const auto verifyingKeyObject = - concord::crypto::openssl::deserializeKey(verificationKey, fmt); - return std::unique_ptr(new MainReplicaVerifier(verifyingKeyObject.getBytes())); - } - default: - LOG_ERROR(EDDSA_SIG_LOG, "Invalid verifying algorithm."); - return {}; - } - } + concord::crypto::KeyFormat fmt = concord::crypto::KeyFormat::HexaDecimalStrippedFormat, + Provider provider = DefaultProvider); + + static std::pair generateKeys(SIGN_VERIFY_ALGO verifierAlgo, + Provider provider = DefaultProvider); }; } // namespace concord::crypto diff --git a/util/include/crypto/openssl/EdDSA.hpp b/util/include/crypto/openssl/EdDSA.hpp index 1ee2b248f2..4d2a30648d 100644 --- a/util/include/crypto/openssl/EdDSA.hpp +++ b/util/include/crypto/openssl/EdDSA.hpp @@ -14,22 +14,18 @@ #include "crypto/crypto.hpp" #include "SerializableByteArray.hpp" -#include "openssl_crypto.hpp" +#include "crypto.hpp" namespace concord::crypto::openssl { -static constexpr const size_t EdDSAPrivateKeyByteSize = 32UL; -static constexpr const size_t EdDSAPublicKeyByteSize = 32UL; -static constexpr const size_t EdDSASignatureByteSize = 64UL; - -class EdDSAPrivateKey : public SerializableByteArray { +class EdDSAPrivateKey : public SerializableByteArray { public: - EdDSAPrivateKey(const EdDSAPrivateKey::ByteArray& arr) : SerializableByteArray(arr) {} + EdDSAPrivateKey(const EdDSAPrivateKey::ByteArray& arr) : SerializableByteArray(arr) {} }; -class EdDSAPublicKey : public SerializableByteArray { +class EdDSAPublicKey : public SerializableByteArray { public: - EdDSAPublicKey(const EdDSAPublicKey::ByteArray& arr) : SerializableByteArray(arr) {} + EdDSAPublicKey(const EdDSAPublicKey::ByteArray& arr) : SerializableByteArray(arr) {} }; /** @@ -42,12 +38,12 @@ class EdDSAPublicKey : public SerializableByteArray { */ template static std::vector extractHexKeyFromPem(const std::string_view pemKey, size_t KeyLength) { - using concord::util::openssl_utils::UniquePKEY; - using concord::util::openssl_utils::UniqueOpenSSLBIO; - using concord::util::openssl_utils::OPENSSL_SUCCESS; + using concord::crypto::openssl::UniquePKEY; + using concord::crypto::openssl::UniqueBIO; + using concord::crypto::openssl::OPENSSL_SUCCESS; UniquePKEY pkey; - UniqueOpenSSLBIO bio(BIO_new(BIO_s_mem())); + UniqueBIO bio(BIO_new(BIO_s_mem())); ConcordAssertGT(BIO_write(bio.get(), pemKey.data(), static_cast(pemKey.size())), 0); diff --git a/util/include/crypto/openssl/EdDSASigner.hpp b/util/include/crypto/openssl/EdDSASigner.hpp index ab33487c58..f3f5fad68c 100644 --- a/util/include/crypto/openssl/EdDSASigner.hpp +++ b/util/include/crypto/openssl/EdDSASigner.hpp @@ -13,7 +13,7 @@ #pragma once #include "EdDSA.hpp" -#include "openssl_crypto.hpp" +#include "crypto.hpp" #include "crypto/signer.hpp" #include "crypto/crypto.hpp" @@ -36,14 +36,12 @@ class EdDSASigner : public ISigner { explicit EdDSASigner(const PrivateKeyType &privateKey) : privateKey_(privateKey) {} size_t signBuffer(const concord::Byte *msg, size_t len, concord::Byte *signature) override { - using concord::util::openssl_utils::UniquePKEY; UniquePKEY pkey(EVP_PKEY_new_raw_private_key( NID_ED25519, nullptr, privateKey_.getBytes().data(), privateKey_.getBytes().size())); ConcordAssertNE(pkey, nullptr); - size_t signatureLength = concord::crypto::openssl::EdDSASignatureByteSize; - using concord::util::openssl_utils::OPENSSL_SUCCESS; - concord::util::openssl_utils::UniqueOpenSSLContext ctx{EVP_MD_CTX_new()}; + size_t signatureLength = Ed25519SignatureByteSize; + UniqueContext ctx{EVP_MD_CTX_new()}; ConcordAssertEQ(EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get()), OPENSSL_SUCCESS); ConcordAssertEQ(EVP_DigestSign(ctx.get(), reinterpret_cast(signature), @@ -54,7 +52,7 @@ class EdDSASigner : public ISigner { return signatureLength; } - size_t signatureLength() const override { return concord::crypto::openssl::EdDSASignatureByteSize; } + size_t signatureLength() const override { return Ed25519SignatureByteSize; } std::string getPrivKey() const override { return privateKey_.toString(); } diff --git a/util/include/crypto/openssl/EdDSAVerifier.hpp b/util/include/crypto/openssl/EdDSAVerifier.hpp index 4f6fa99919..f0f61cf3a4 100644 --- a/util/include/crypto/openssl/EdDSAVerifier.hpp +++ b/util/include/crypto/openssl/EdDSAVerifier.hpp @@ -13,12 +13,9 @@ #pragma once #include "EdDSA.hpp" -#include "openssl_crypto.hpp" +#include "crypto.hpp" #include "crypto/verifier.hpp" -// OpenSSL includes. -#include - namespace concord::crypto::openssl { /** @@ -37,17 +34,15 @@ class EdDSAVerifier : public IVerifier { explicit EdDSAVerifier(const PublicKeyType &publicKey) : publicKey_(publicKey) {} bool verifyBuffer(const Byte *msg, size_t msgLen, const Byte *sig, size_t sigLen) const override { - using concord::util::openssl_utils::UniquePKEY; - using concord::util::openssl_utils::OPENSSL_SUCCESS; - ConcordAssertEQ(sigLen, concord::crypto::openssl::EdDSASignatureByteSize); + ConcordAssertEQ(sigLen, Ed25519SignatureByteSize); UniquePKEY pkey{ EVP_PKEY_new_raw_public_key(NID_ED25519, nullptr, publicKey_.getBytes().data(), publicKey_.getBytes().size())}; - concord::util::openssl_utils::UniqueOpenSSLContext ctx{EVP_MD_CTX_new()}; + UniqueContext ctx{EVP_MD_CTX_new()}; ConcordAssertEQ(EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get()), OPENSSL_SUCCESS); return (OPENSSL_SUCCESS == EVP_DigestVerify(ctx.get(), sig, sigLen, msg, msgLen)); } - uint32_t signatureLength() const override { return concord::crypto::openssl::EdDSASignatureByteSize; } + uint32_t signatureLength() const override { return Ed25519SignatureByteSize; } std::string getPubKey() const override { return publicKey_.toString(); } diff --git a/util/include/openssl_crypto.hpp b/util/include/crypto/openssl/crypto.hpp similarity index 70% rename from util/include/openssl_crypto.hpp rename to util/include/crypto/openssl/crypto.hpp index 4b41078aab..782ef80b4b 100644 --- a/util/include/openssl_crypto.hpp +++ b/util/include/crypto/openssl/crypto.hpp @@ -25,6 +25,8 @@ #include #include #include +#include "crypto/openssl/crypto.hpp" +#include "crypto/crypto.hpp" #include "memory.hpp" #include "assertUtils.hpp" @@ -36,7 +38,22 @@ #include #include -namespace concord::util::openssl_utils { +namespace concord::crypto::openssl { + +using UniqueContext = custom_deleter_unique_ptr; +using UniquePKEYContext = custom_deleter_unique_ptr; +using UniquePKEY = custom_deleter_unique_ptr; +using UniqueX509 = custom_deleter_unique_ptr; +using UniqueBIO = custom_deleter_unique_ptr; +using UniqueCipherContext = custom_deleter_unique_ptr; +using UniqueBIGNUM = custom_deleter_unique_ptr; +using UniqueBNCTX = custom_deleter_unique_ptr; +using UniqueECKEY = custom_deleter_unique_ptr; +using UniqueECPOINT = custom_deleter_unique_ptr; + +constexpr int OPENSSL_SUCCESS = 1; +constexpr int OPENSSL_FAILURE = 0; +constexpr int OPENSSL_ERROR = -1; // Note these utilities may use std::strings to pass arond byte strings; note // this should work since C++ should guarantee std::string is a string of chars @@ -110,6 +127,67 @@ class AsymmetricPublicKey { AsymmetricPublicKey() {} }; +// Wrapper class for OpenSSL Crypto's EVP_PKEY objects implementing +// AsymmetricPrivateKey. +class EVPPKEYPrivateKey : public AsymmetricPrivateKey { + private: + UniquePKEY pkey; + std::string scheme_name; + + public: + // Copying and moving EVPPKEYPrivateKey objects is currently unimplemented; + // note the default implementations for copy and move operations would not be + // appropriate for this class since the EVP_PKEY object it contains must be + // memory-managed through the OpenSSL library rather than by default + // mechanisms. + EVPPKEYPrivateKey(const EVPPKEYPrivateKey& other) = delete; + EVPPKEYPrivateKey(const EVPPKEYPrivateKey&& other) = delete; + EVPPKEYPrivateKey& operator=(const EVPPKEYPrivateKey& other) = delete; + EVPPKEYPrivateKey& operator=(const EVPPKEYPrivateKey&& other) = delete; + + // Note the constructed EVPPKEYPrivateKey takes ownership of the pointer it is + // constructed with. A precondition of this constructor is that the provided + // EVP_PKEY object must have both its private and public keys initialized; + // future behavior of this EVPPKEYPrivateKey object is undefined if this + // precondition is not met. + EVPPKEYPrivateKey(UniquePKEY&& pkey_ptr, const std::string& scheme); + virtual ~EVPPKEYPrivateKey() override; + + virtual std::string serialize() const override; + + virtual std::string sign(const std::string& message) const override; +}; + +// Wrapper class for OpenSSL Crypto's EVP_PKEY objects implementing +// concord::util::openssl_crypto::AsymmetricPublicKey. +class EVPPKEYPublicKey : public AsymmetricPublicKey { + private: + UniquePKEY pkey; + std::string scheme_name; + + public: + // Copying and moving EVPPKEYPublicKey objects is currently unimplemented; + // note the default implementations for copy and move operations would not be + // appropriate for this class since the EVP_PKEY object it contains must be + // memory-managed through the OpenSSL library rather than by default + // mechanisms. + EVPPKEYPublicKey(const EVPPKEYPublicKey& other) = delete; + EVPPKEYPublicKey(const EVPPKEYPublicKey&& other) = delete; + EVPPKEYPublicKey& operator=(const EVPPKEYPublicKey& other) = delete; + EVPPKEYPublicKey& operator=(const EVPPKEYPublicKey&& other) = delete; + + // Note the constructed EVPPKEYPublicKey takes ownership of the pointer it is + // constructed with. A precondition of this constructor is that the provided + // EVP_PKEY object must its public key initialized; future behavior of this + // EVPPKEYPublicKey object is undefined if this precondition is not met. + EVPPKEYPublicKey(UniquePKEY&& pkey_ptr, const std::string& scheme); + virtual ~EVPPKEYPublicKey() override; + + virtual std::string serialize() const override; + + virtual bool verify(const std::string& message, const std::string& signature) const override; +}; + // List of currently permitted and supported asymmetric cryptography schemes // Concord might use. Note Concord maintainers should not add new schemes to // this list and implement support for them unless those new schemes have been @@ -128,6 +206,11 @@ const static std::vector kPermittedAsymmetricCryptoSchemes({ // this curve. }); +std::pair, std::unique_ptr> +generateAsymmetricCryptoKeyPairById(int id, std::string scheme_name); + +std::pair generateECDSAKeyPair(CurveType curveType, const KeyFormat fmt); + // Function for pseudorandomly generating a key pair for asymmetric // cryptography, given an asymmetric cryptography scheme listed in // KPermittedAsymmetricCryptoSchemes. @@ -199,19 +282,12 @@ class UnexpectedOpenSSLCryptoFailureException : public std::exception { virtual const char* what() const noexcept override { return message.c_str(); } }; -using UniqueOpenSSLContext = custom_deleter_unique_ptr; -using UniqueOpenSSLPKEYContext = custom_deleter_unique_ptr; -using UniquePKEY = custom_deleter_unique_ptr; -using UniqueOpenSSLX509 = custom_deleter_unique_ptr; -using UniqueOpenSSLBIO = custom_deleter_unique_ptr; -using UniqueOpenSSLCipherContext = custom_deleter_unique_ptr; -using UniqueOpenSSLBIGNUM = custom_deleter_unique_ptr; -using UniqueOpenSSLBNCTX = custom_deleter_unique_ptr; -using UniqueOpenSSLECKEY = custom_deleter_unique_ptr; -using UniqueOpenSSLECPOINT = custom_deleter_unique_ptr; - -constexpr int OPENSSL_SUCCESS = 1; -constexpr int OPENSSL_FAILURE = 0; -constexpr int OPENSSL_ERROR = -1; +// Deleter classes for using smart pointers that correctly manage objects from +// the OpenSSL Crypto library, given OpenSSL Crypto objects use free functions +// provided by the library rather than normal destructors. +class OPENSSLStringDeleter { + public: + void operator()(char* string) const { OPENSSL_free(string); } +}; -} // namespace concord::util::openssl_utils +} // namespace concord::crypto::openssl diff --git a/util/include/crypto/openssl/digest_creator.hpp b/util/include/crypto/openssl/digest_creator.hpp index a0c80fdc33..0cd18b5fd2 100644 --- a/util/include/crypto/openssl/digest_creator.hpp +++ b/util/include/crypto/openssl/digest_creator.hpp @@ -17,8 +17,8 @@ namespace concord::crypto::openssl { template || - std::is_same_v>> + typename = std::enable_if_t || + std::is_same_v>> class OpenSSLDigestCreator : public concord::crypto::DigestCreator { public: OpenSSLDigestCreator() = default; diff --git a/util/include/crypto/openssl/hash.hpp b/util/include/crypto/openssl/hash.hpp index 7aad658462..5885757787 100644 --- a/util/include/crypto/openssl/hash.hpp +++ b/util/include/crypto/openssl/hash.hpp @@ -22,7 +22,7 @@ #include "hex_tools.h" #include "assertUtils.hpp" -namespace concord::crypto::hash { +namespace concord::crypto::openssl { // A simple wrapper class around OpenSSL versions > 1.1.1 that implements EVP hash functions. template @@ -113,4 +113,4 @@ class EVPHash { using SHA3_256 = EVPHash; using SHA2_256 = EVPHash; -} // namespace concord::crypto +} // namespace concord::crypto::openssl diff --git a/util/include/crypto/verifier.hpp b/util/include/crypto/verifier.hpp index 525130e97f..7c98294ef9 100644 --- a/util/include/crypto/verifier.hpp +++ b/util/include/crypto/verifier.hpp @@ -13,6 +13,7 @@ #pragma once #include +#include "types.hpp" namespace concord::crypto { diff --git a/util/src/crypto/crypto.cpp b/util/src/crypto/crypto.cpp index b71c7d16de..f61dc5d0f0 100644 --- a/util/src/crypto/crypto.cpp +++ b/util/src/crypto/crypto.cpp @@ -27,18 +27,44 @@ using std::pair; using std::string; using concord::Byte; using concord::crypto::KeyFormat; -using concord::crypto::CurveType; -using concord::util::openssl_utils::UniquePKEY; -using concord::util::openssl_utils::UniqueOpenSSLPKEYContext; -using concord::util::openssl_utils::UniqueOpenSSLBIO; -using concord::util::openssl_utils::OPENSSL_SUCCESS; -using concord::crypto::openssl::EdDSASignatureByteSize; -using concord::crypto::openssl::EdDSAPrivateKeyByteSize; -using concord::crypto::openssl::EdDSAPublicKeyByteSize; +using concord::crypto::openssl::UniquePKEY; +using concord::crypto::openssl::UniqueECKEY; +using concord::crypto::openssl::UniquePKEYContext; +using concord::crypto::openssl::UniqueBIO; +using concord::crypto::openssl::OPENSSL_SUCCESS; +using concord::crypto::Ed25519PrivateKeyByteSize; +using concord::crypto::Ed25519PublicKeyByteSize; + +pair generateECKeyPair(int id, const KeyFormat fmt) { + constexpr size_t maxKeySize = 2048; + + UniqueBIO outbio; + openssl::UniqueECKEY myecc{EC_KEY_new_by_curve_name(id)}; + + ConcordAssertEQ(OPENSSL_SUCCESS, EC_KEY_generate_key(myecc.get())); + UniquePKEY pkey{EVP_PKEY_new()}; + EVP_PKEY_assign_EC_KEY(pkey.get(), myecc.get()); + + array privKey; + array pubKey; + size_t privKeyLen{maxKeySize}; + size_t pubKeyLen{maxKeySize}; + + ConcordAssertEQ(OPENSSL_SUCCESS, EVP_PKEY_get_raw_private_key(pkey.get(), privKey.data(), &privKeyLen)); + ConcordAssertEQ(OPENSSL_SUCCESS, EVP_PKEY_get_raw_public_key(pkey.get(), pubKey.data(), &pubKeyLen)); + + pair keyPair(boost::algorithm::hex(string(reinterpret_cast(privKey.data()), privKeyLen)), + boost::algorithm::hex(string(reinterpret_cast(pubKey.data()), pubKeyLen))); + + if (KeyFormat::PemFormat == fmt) { + keyPair = EdDSAHexToPem(keyPair); + } + return keyPair; +} pair generateEdDSAKeyPair(const KeyFormat fmt) { UniquePKEY edPkey; - UniqueOpenSSLPKEYContext edPkeyCtx(EVP_PKEY_CTX_new_id(NID_ED25519, nullptr)); + UniquePKEYContext edPkeyCtx(EVP_PKEY_CTX_new_id(NID_ED25519, nullptr)); ConcordAssertNE(edPkeyCtx, nullptr); ConcordAssertEQ(OPENSSL_SUCCESS, EVP_PKEY_keygen_init(edPkeyCtx.get())); @@ -46,19 +72,19 @@ pair generateEdDSAKeyPair(const KeyFormat fmt) { ConcordAssertEQ(OPENSSL_SUCCESS, EVP_PKEY_keygen(edPkeyCtx.get(), &keygenRet)); edPkey.reset(keygenRet); - array privKey; - array pubKey; - size_t keyLen{EdDSAPrivateKeyByteSize}; + array privKey; + array pubKey; + size_t keyLen{Ed25519PrivateKeyByteSize}; ConcordAssertEQ(OPENSSL_SUCCESS, EVP_PKEY_get_raw_private_key(edPkey.get(), privKey.data(), &keyLen)); - ConcordAssertEQ(keyLen, EdDSAPrivateKeyByteSize); - keyLen = EdDSAPublicKeyByteSize; + ConcordAssertEQ(keyLen, Ed25519PrivateKeyByteSize); + keyLen = Ed25519PublicKeyByteSize; ConcordAssertEQ(OPENSSL_SUCCESS, EVP_PKEY_get_raw_public_key(edPkey.get(), pubKey.data(), &keyLen)); - ConcordAssertEQ(keyLen, EdDSAPublicKeyByteSize); + ConcordAssertEQ(keyLen, Ed25519PublicKeyByteSize); pair keyPair( - boost::algorithm::hex(string(reinterpret_cast(privKey.data()), EdDSAPrivateKeyByteSize)), - boost::algorithm::hex(string(reinterpret_cast(pubKey.data()), EdDSAPublicKeyByteSize))); + boost::algorithm::hex(string(reinterpret_cast(privKey.data()), Ed25519PrivateKeyByteSize)), + boost::algorithm::hex(string(reinterpret_cast(pubKey.data()), Ed25519PublicKeyByteSize))); if (KeyFormat::PemFormat == fmt) { keyPair = EdDSAHexToPem(keyPair); @@ -77,7 +103,7 @@ pair EdDSAHexToPem(const std::pair& he NID_ED25519, nullptr, reinterpret_cast(privKey.data()), privKey.size())); ConcordAssertNE(nullptr, ed_privKey); - UniqueOpenSSLBIO bio(BIO_new(BIO_s_mem())); + UniqueBIO bio(BIO_new(BIO_s_mem())); ConcordAssertNE(nullptr, bio); ConcordAssertEQ(OPENSSL_SUCCESS, @@ -96,7 +122,7 @@ pair EdDSAHexToPem(const std::pair& he NID_ED25519, nullptr, reinterpret_cast(pubKey.data()), pubKey.size())); ConcordAssertNE(nullptr, ed_pubKey); - UniqueOpenSSLBIO bio(BIO_new(BIO_s_mem())); + UniqueBIO bio(BIO_new(BIO_s_mem())); ConcordAssertNE(nullptr, bio); ConcordAssertEQ(OPENSSL_SUCCESS, PEM_write_bio_PUBKEY(bio.get(), ed_pubKey.get())); diff --git a/util/src/crypto/factory.cpp b/util/src/crypto/factory.cpp new file mode 100644 index 0000000000..412c8f5b82 --- /dev/null +++ b/util/src/crypto/factory.cpp @@ -0,0 +1,72 @@ +// Concord +// +// Copyright (c) 2022 VMware, Inc. All Rights Reserved. +// +// This product is licensed to you under the Apache 2.0 license (the "License"). +// You may not use this product except in compliance with the Apache 2.0 +// License. +// +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to the +// terms and conditions of the sub-component's license, as noted in the LICENSE +// file. + +#include "crypto/factory.hpp" + +namespace concord::crypto { + +using AlgProvider = std::pair; + +class AlgProviderHash { + public: + size_t operator()(const AlgProvider& params) const { + size_t result = static_cast(std::get<0>(params)); + result <<= (sizeof(uint16_t) * 8); + result |= static_cast(std::get<1>(params)); + return result; + } +}; + +std::unique_ptr Factory::getSigner(const std::string& signingKey, + SIGN_VERIFY_ALGO signingAlgo, + concord::crypto::KeyFormat fmt, + Provider provider) { + using ImplInitializer = std::function()>; + namespace cryptopp = concord::crypto::cryptopp; + namespace openssl = concord::crypto::openssl; + + const std::unordered_map providerAlgorithmToSigner = { + {{SIGN_VERIFY_ALGO::ECDSA, Provider::CryptoPP}, + [&]() { return std::make_unique(signingKey, fmt); }}, + {{SIGN_VERIFY_ALGO::RSA, Provider::CryptoPP}, + [&]() { return std::make_unique(signingKey, fmt); }}, + {{SIGN_VERIFY_ALGO::EDDSA, Provider::OpenSSL}, [&]() { + const auto signingKeyObject = openssl::deserializeKey(signingKey, fmt); + return std::make_unique>(signingKeyObject.getBytes()); + }}}; + + return providerAlgorithmToSigner.at({signingAlgo, provider})(); +} + +std::unique_ptr Factory::getVerifier(const std::string& verificationKey, + SIGN_VERIFY_ALGO verifierAlgo, + concord::crypto::KeyFormat fmt, + Provider provider) { + using ImplInitializer = std::function()>; + namespace cryptopp = concord::crypto::cryptopp; + namespace openssl = concord::crypto::openssl; + + const std::unordered_map providerAlgorithmToVerifier = { + {{SIGN_VERIFY_ALGO::ECDSA, Provider::CryptoPP}, + [&]() { return std::make_unique(verificationKey, fmt); }}, + {{SIGN_VERIFY_ALGO::RSA, Provider::CryptoPP}, + [&]() { return std::make_unique(verificationKey, fmt); }}, + {{SIGN_VERIFY_ALGO::EDDSA, Provider::OpenSSL}, [&]() { + const auto signingKeyObject = openssl::deserializeKey(verificationKey, fmt); + return std::make_unique>(signingKeyObject.getBytes()); + }}}; + + return providerAlgorithmToVerifier.at({verifierAlgo, provider})(); +} + +} // namespace concord::crypto diff --git a/util/src/openssl/certificates.cpp b/util/src/openssl/certificates.cpp index 2f8d2fef3e..c729fa3826 100644 --- a/util/src/openssl/certificates.cpp +++ b/util/src/openssl/certificates.cpp @@ -21,12 +21,12 @@ namespace concord::crypto { using std::unique_ptr; using std::string; using concord::crypto::SIGN_VERIFY_ALGO; -using concord::util::openssl_utils::UniquePKEY; -using concord::util::openssl_utils::UniqueOpenSSLX509; -using concord::util::openssl_utils::UniqueOpenSSLBIO; -using concord::util::openssl_utils::OPENSSL_SUCCESS; -using concord::util::openssl_utils::OPENSSL_FAILURE; -using concord::util::openssl_utils::OPENSSL_ERROR; +using concord::crypto::openssl::UniquePKEY; +using concord::crypto::openssl::UniqueX509; +using concord::crypto::openssl::UniqueBIO; +using concord::crypto::openssl::OPENSSL_SUCCESS; +using concord::crypto::openssl::OPENSSL_FAILURE; +using concord::crypto::openssl::OPENSSL_ERROR; string generateSelfSignedCert(const string& origin_cert_path, const string& public_key, @@ -38,14 +38,14 @@ string generateSelfSignedCert(const string& origin_cert_path, return string(); } - UniqueOpenSSLX509 cert(PEM_read_X509(fp.get(), nullptr, nullptr, nullptr)); + UniqueX509 cert(PEM_read_X509(fp.get(), nullptr, nullptr, nullptr)); if (nullptr == cert) { LOG_ERROR(OPENSSL_LOG, "Cannot parse certificate, path: " << origin_cert_path); return string(); } UniquePKEY priv_key(EVP_PKEY_new()); - UniqueOpenSSLBIO priv_bio(BIO_new(BIO_s_mem())); + UniqueBIO priv_bio(BIO_new(BIO_s_mem())); if (BIO_write(priv_bio.get(), static_cast(signing_key.c_str()), signing_key.size()) <= 0) { LOG_ERROR(OPENSSL_LOG, "Unable to create private key object"); @@ -57,7 +57,7 @@ string generateSelfSignedCert(const string& origin_cert_path, return string(); } UniquePKEY pub_key(EVP_PKEY_new()); - UniqueOpenSSLBIO pub_bio(BIO_new(BIO_s_mem())); + UniqueBIO pub_bio(BIO_new(BIO_s_mem())); if (BIO_write(pub_bio.get(), static_cast(public_key.c_str()), public_key.size()) <= 0) { LOG_ERROR(OPENSSL_LOG, "Unable to write public key object"); @@ -85,7 +85,7 @@ string generateSelfSignedCert(const string& origin_cert_path, } } - UniqueOpenSSLBIO outbio(BIO_new(BIO_s_mem())); + UniqueBIO outbio(BIO_new(BIO_s_mem())); if (OPENSSL_FAILURE == PEM_write_bio_X509(outbio.get(), cert.get())) { LOG_ERROR(OPENSSL_LOG, "Unable to create certificate object"); return string(); @@ -103,7 +103,7 @@ string generateSelfSignedCert(const string& origin_cert_path, bool verifyCertificate(X509& cert, const string& public_key) { UniquePKEY pub_key(EVP_PKEY_new()); - UniqueOpenSSLBIO pub_bio(BIO_new(BIO_s_mem())); + UniqueBIO pub_bio(BIO_new(BIO_s_mem())); if (BIO_write(pub_bio.get(), static_cast(public_key.c_str()), public_key.size()) <= 0) { return false; @@ -170,7 +170,7 @@ bool verifyCertificate(const X509& cert_to_verify, return false; } - UniqueOpenSSLX509 localCert(PEM_read_X509(fp.get(), nullptr, nullptr, nullptr)); + UniqueX509 localCert(PEM_read_X509(fp.get(), nullptr, nullptr, nullptr)); if (nullptr == localCert) { LOG_ERROR(OPENSSL_LOG, "Cannot parse certificate, path: " << local_cert_path.string()); return false; diff --git a/util/src/openssl_crypto.cpp b/util/src/openssl/crypto.cpp similarity index 55% rename from util/src/openssl_crypto.cpp rename to util/src/openssl/crypto.cpp index 291b0771d1..df8936f724 100644 --- a/util/src/openssl_crypto.cpp +++ b/util/src/openssl/crypto.cpp @@ -11,273 +11,217 @@ // terms and conditions of the subcomponent's license, as noted in the // LICENSE file. -#include "openssl_crypto.hpp" +#include "crypto/openssl/crypto.hpp" #include #include #include #include -using concord::util::openssl_utils::AsymmetricPrivateKey; -using concord::util::openssl_utils::AsymmetricPublicKey; -using concord::util::openssl_utils::kExpectedSHA256HashLengthInBytes; -using concord::util::openssl_utils::UnexpectedOpenSSLCryptoFailureException; -using concord::util::openssl_utils::UniquePKEY; -using concord::util::openssl_utils::UniqueOpenSSLContext; -using concord::util::openssl_utils::UniqueOpenSSLBIGNUM; -using concord::util::openssl_utils::UniqueOpenSSLBNCTX; -using concord::util::openssl_utils::UniqueOpenSSLECKEY; -using concord::util::openssl_utils::UniqueOpenSSLECPOINT; +namespace concord::crypto::openssl { + using std::invalid_argument; using std::pair; using std::string; using std::unique_ptr; -// Deleter classes for using smart pointers that correctly manage objects from -// the OpenSSL Crypto library, given OpenSSL Crypto objects use free functions -// provided by the library rather than normal destructors. -class OPENSSLStringDeleter { - public: - void operator()(char* string) const { OPENSSL_free(string); } -}; - -// Wrapper class for OpenSSL Crypto's EVP_PKEY objects implementing -// concord::util::openssl_crypto::AsymmetricPrivateKey. -class EVPPKEYPrivateKey : public AsymmetricPrivateKey { - private: - UniquePKEY pkey; - string scheme_name; - - public: - // Copying and moving EVPPKEYPrivateKey objects is currently unimplemented; - // note the default implementations for copy and move operations would not be - // appropriate for this class since the EVP_PKEY object it contains must be - // memory-managed through the OpenSSL library rather than by default - // mechanisms. - EVPPKEYPrivateKey(const EVPPKEYPrivateKey& other) = delete; - EVPPKEYPrivateKey(const EVPPKEYPrivateKey&& other) = delete; - EVPPKEYPrivateKey& operator=(const EVPPKEYPrivateKey& other) = delete; - EVPPKEYPrivateKey& operator=(const EVPPKEYPrivateKey&& other) = delete; - - // Note the constructed EVPPKEYPrivateKey takes ownership of the pointer it is - // constructed with. A precondition of this constructor is that the provided - // EVP_PKEY object must have both its private and public keys initialized; - // future behavior of this EVPPKEYPrivateKey object is undefined if this - // precondition is not met. - EVPPKEYPrivateKey(UniquePKEY&& pkey_ptr, const string& scheme) : pkey(move(pkey_ptr)), scheme_name(scheme) {} - virtual ~EVPPKEYPrivateKey() override {} - - virtual string serialize() const override { - if (EVP_PKEY_get0_EC_KEY(pkey.get())) { - const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); - const BIGNUM* private_key = EC_KEY_get0_private_key(ec_key); - if (!private_key) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to fetch the private key from " - "an elliptic curve key pair."); - } - unique_ptr hex_chars(BN_bn2hex(private_key), OPENSSLStringDeleter()); - if (!hex_chars) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to convert a private key to " - "hexadecimal for serialization."); - } - string private_key_data = string(hex_chars.get()); - return "PRIVATE_KEY:" + scheme_name + ":" + private_key_data; - } else { - // This case should not be reachable as all currently supported schemes - // should be handled above. - throw invalid_argument( - "Failed to serialize AsymmetricPrivateKey object; failed to identify " - "supported key type; key serialization logic may be out of sync with " - "key creation logic."); - } - } - - virtual std::string sign(const std::string& message) const override { - UniqueOpenSSLContext digest_context(EVP_MD_CTX_new()); - if (!digest_context) { +// Note the constructed EVPPKEYPrivateKey takes ownership of the pointer it is +// constructed with. A precondition of this constructor is that the provided +// EVP_PKEY object must have both its private and public keys initialized; +// future behavior of this EVPPKEYPrivateKey object is undefined if this +// precondition is not met. +EVPPKEYPrivateKey::EVPPKEYPrivateKey(UniquePKEY&& pkey_ptr, const string& scheme) + : pkey(move(pkey_ptr)), scheme_name(scheme) {} +EVPPKEYPrivateKey::~EVPPKEYPrivateKey() {} + +string EVPPKEYPrivateKey::serialize() const { + if (EVP_PKEY_get0_EC_KEY(pkey.get())) { + const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + const BIGNUM* private_key = EC_KEY_get0_private_key(ec_key); + if (!private_key) { throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to allocate a message digest " - "context object."); + "OpenSSL Crypto unexpectedly failed to fetch the private key from " + "an elliptic curve key pair."); } - if (!EVP_DigestSignInit(digest_context.get(), nullptr, EVP_sha256(), nullptr, pkey.get())) { + unique_ptr hex_chars(BN_bn2hex(private_key), OPENSSLStringDeleter()); + if (!hex_chars) { throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to initialize a message digest " - "context object."); + "OpenSSL Crypto unexpectedly failed to convert a private key to " + "hexadecimal for serialization."); } - if (!EVP_DigestSignUpdate(digest_context.get(), message.data(), message.length())) { + string private_key_data = string(hex_chars.get()); + return "PRIVATE_KEY:" + scheme_name + ":" + private_key_data; + } else { + // This case should not be reachable as all currently supported schemes + // should be handled above. + throw invalid_argument( + "Failed to serialize AsymmetricPrivateKey object; failed to identify " + "supported key type; key serialization logic may be out of sync with " + "key creation logic."); + } +} + +std::string EVPPKEYPrivateKey::sign(const std::string& message) const { + UniqueContext digest_context(EVP_MD_CTX_new()); + if (!digest_context) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to allocate a message digest " + "context object."); + } + if (!EVP_DigestSignInit(digest_context.get(), nullptr, EVP_sha256(), nullptr, pkey.get())) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to initialize a message digest " + "context object."); + } + if (!EVP_DigestSignUpdate(digest_context.get(), message.data(), message.length())) { + throw UnexpectedOpenSSLCryptoFailureException("OpenSSL Crypto unexpectedly failed to hash a message for signing."); + } + size_t signature_length; + if (!EVP_DigestSignFinal(digest_context.get(), nullptr, &signature_length)) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to determine the maximum length " + "for a signature signed with asymmetric cryptography."); + } + string signature(signature_length, (char)0); + if (!EVP_DigestSignFinal( + digest_context.get(), reinterpret_cast(signature.data()), &signature_length)) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to sign a message digest with " + "asymmetric cryptography."); + } + if (signature_length > signature.length()) { + // This should probably never happen. + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly reports having produced an asymmetric " + "cryptography signature of length greater than the maximum signature " + "length it previously reported."); + } + // It is, at least theoretically, possible for the produced signature to be + // shorter than the maximum signature length. + signature.resize(signature_length); + + return signature; +} + +EVPPKEYPublicKey::EVPPKEYPublicKey(UniquePKEY&& pkey_ptr, const string& scheme) + : pkey(move(pkey_ptr)), scheme_name(scheme) {} +EVPPKEYPublicKey::~EVPPKEYPublicKey() {} + +string EVPPKEYPublicKey::serialize() const { + if (EVP_PKEY_get0_EC_KEY(pkey.get())) { + const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + const EC_POINT* public_key = EC_KEY_get0_public_key(ec_key); + if (!public_key) { throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to hash a message for signing."); + "OpenSSL Crypto unexpectedly failed to fetch the public key from " + "an elliptic curve key object."); } - size_t signature_length; - if (!EVP_DigestSignFinal(digest_context.get(), nullptr, &signature_length)) { + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + if (!ec_group) { throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to determine the maximum length " - "for a signature signed with asymmetric cryptography."); + "OpenSSL Crypto unexpectedly failed to fetch the elliptic curve " + "group from an elliptic curve key object."); } - string signature(signature_length, (char)0); - if (!EVP_DigestSignFinal( - digest_context.get(), reinterpret_cast(signature.data()), &signature_length)) { + UniqueBNCTX big_num_context(BN_CTX_new()); + if (!big_num_context) { throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to sign a message digest with " - "asymmetric cryptography."); + "OpenSSL Crypto unexpectedly failed to allocate a big number " + "context object needed to convert an elliptic curve point to " + "hexadecimal for serialization."); } - if (signature_length > signature.length()) { - // This should probably never happen. + unique_ptr hex_chars( + EC_POINT_point2hex(ec_group, public_key, EC_GROUP_get_point_conversion_form(ec_group), big_num_context.get()), + OPENSSLStringDeleter()); + if (!hex_chars) { throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly reports having produced an asymmetric " - "cryptography signature of length greater than the maximum signature " - "length it previously reported."); - } - // It is, at least theoretically, possible for the produced signature to be - // shorter than the maximum signature length. - signature.resize(signature_length); - - return signature; - } -}; - -// Wrapper class for OpenSSL Crypto's EVP_PKEY objects implementing -// concord::util::openssl_crypto::AsymmetricPublicKey. -class EVPPKEYPublicKey : public AsymmetricPublicKey { - private: - UniquePKEY pkey; - string scheme_name; - - public: - // Copying and moving EVPPKEYPublicKey objects is currently unimplemented; - // note the default implementations for copy and move operations would not be - // appropriate for this class since the EVP_PKEY object it contains must be - // memory-managed through the OpenSSL library rather than by default - // mechanisms. - EVPPKEYPublicKey(const EVPPKEYPublicKey& other) = delete; - EVPPKEYPublicKey(const EVPPKEYPublicKey&& other) = delete; - EVPPKEYPublicKey& operator=(const EVPPKEYPublicKey& other) = delete; - EVPPKEYPublicKey& operator=(const EVPPKEYPublicKey&& other) = delete; - - // Note the constructed EVPPKEYPublicKey takes ownership of the pointer it is - // constructed with. A precondition of this constructor is that the provided - // EVP_PKEY object must its public key initialized; future behavior of this - // EVPPKEYPublicKey object is undefined if this precondition is not met. - EVPPKEYPublicKey(UniquePKEY&& pkey_ptr, const string& scheme) : pkey(move(pkey_ptr)), scheme_name(scheme) {} - virtual ~EVPPKEYPublicKey() override {} - - virtual string serialize() const override { - if (EVP_PKEY_get0_EC_KEY(pkey.get())) { - const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); - const EC_POINT* public_key = EC_KEY_get0_public_key(ec_key); - if (!public_key) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to fetch the public key from " - "an elliptic curve key object."); - } - const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); - if (!ec_group) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to fetch the elliptic curve " - "group from an elliptic curve key object."); - } - UniqueOpenSSLBNCTX big_num_context(BN_CTX_new()); - if (!big_num_context) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to allocate a big number " - "context object needed to convert an elliptic curve point to " - "hexadecimal for serialization."); - } - unique_ptr hex_chars( - EC_POINT_point2hex(ec_group, public_key, EC_GROUP_get_point_conversion_form(ec_group), big_num_context.get()), - OPENSSLStringDeleter()); - if (!hex_chars) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to convert a public key to " - "hexadecimal for serialization."); - } - string public_key_data = string(hex_chars.get()); - return "PUBLIC_KEY:" + scheme_name + ":" + public_key_data; - } else { - // This case should not be reachable as all currently supported schemes - // should be handled above. - throw invalid_argument( - "Failed to serialize AsymmetricPublicKey object; failed to identify " - "supported key type; key serialization logic may be out of sync with " - "key creation logic."); + "OpenSSL Crypto unexpectedly failed to convert a public key to " + "hexadecimal for serialization."); } + string public_key_data = string(hex_chars.get()); + return "PUBLIC_KEY:" + scheme_name + ":" + public_key_data; + } else { + // This case should not be reachable as all currently supported schemes + // should be handled above. + throw invalid_argument( + "Failed to serialize AsymmetricPublicKey object; failed to identify " + "supported key type; key serialization logic may be out of sync with " + "key creation logic."); } +} - virtual bool verify(const std::string& message, const std::string& signature) const override { - UniqueOpenSSLContext digest_context(EVP_MD_CTX_new()); - if (!digest_context) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to allocate a message digest " - "context object."); - } - if (!EVP_DigestVerifyInit(digest_context.get(), nullptr, EVP_sha256(), nullptr, pkey.get())) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to initialize a message digest " - "context object."); - } - if (!EVP_DigestVerifyUpdate(digest_context.get(), message.data(), message.length())) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to hash a message to validate a " - "signature over it."); - } +bool EVPPKEYPublicKey::verify(const std::string& message, const std::string& signature) const { + UniqueContext digest_context(EVP_MD_CTX_new()); + if (!digest_context) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to allocate a message digest " + "context object."); + } + if (!EVP_DigestVerifyInit(digest_context.get(), nullptr, EVP_sha256(), nullptr, pkey.get())) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to initialize a message digest " + "context object."); + } + if (!EVP_DigestVerifyUpdate(digest_context.get(), message.data(), message.length())) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to hash a message to validate a " + "signature over it."); + } + + // Note we only return true if EVP_DigestVerifyFinal returns 1, and not if + // it returns a non-1, non-0 value; only 1 indicates a verification success, + // other non-1, non-0 values indicate unexpected failures (and 0 indicates + // that the signature was not correct cryptographically). + return (EVP_DigestVerifyFinal( + digest_context.get(), reinterpret_cast(signature.data()), signature.length()) == 1); +} - // Note we only return true if EVP_DigestVerifyFinal returns 1, and not if - // it returns a non-1, non-0 value; only 1 indicates a verification success, - // other non-1, non-0 values indicate unexpected failures (and 0 indicates - // that the signature was not correct cryptographically). - return (EVP_DigestVerifyFinal(digest_context.get(), - reinterpret_cast(signature.data()), - signature.length()) == 1); +pair, unique_ptr> generateAsymmetricCryptoKeyPairById( + int id, std::string scheme_name) { + UniqueECKEY key_pair(EC_KEY_new_by_curve_name(id)); + UniqueECKEY public_key(EC_KEY_new_by_curve_name(id)); + if (!key_pair || !public_key) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to allocate and prepare an " + "elliptic curve key object."); + } + if (!EC_KEY_generate_key(key_pair.get())) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to generate a new Elliptic Curve " + "key pair."); + } + const EC_POINT* public_key_raw = EC_KEY_get0_public_key(key_pair.get()); + if (!public_key_raw) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to get a pointer to the public " + "key for a generated elliptic curve key pair."); + } + if (!EC_KEY_set_public_key(public_key.get(), public_key_raw)) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to set the public key for an " + "empty allocated elliptic curve key object."); + } + UniquePKEY private_pkey(EVP_PKEY_new()); + UniquePKEY public_pkey(EVP_PKEY_new()); + if (!private_pkey || !public_pkey) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to allocate and prepare a " + "high-level key object."); + } + if (!EVP_PKEY_set1_EC_KEY(private_pkey.get(), key_pair.get()) || + !EVP_PKEY_set1_EC_KEY(public_pkey.get(), key_pair.get())) { + throw UnexpectedOpenSSLCryptoFailureException( + "OpenSSL Crypto unexpectedly failed to initialize a high-level key " + "object given an elliptic curve key object."); } -}; -pair, unique_ptr> -concord::util::openssl_utils::generateAsymmetricCryptoKeyPair(const string& scheme_name) { - if (scheme_name == "secp256r1") { - // prime256v1 is an alternative name for the same curve parameters as - // secp256r1; prime256v1 happens to be the name OpenSSL's Crypto library - // uses for a possible parameter to EC_KEY_new_by_curve_name. - UniqueOpenSSLECKEY key_pair(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); - UniqueOpenSSLECKEY public_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); - if (!key_pair || !public_key) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to allocate and prepare an " - "elliptic curve key object."); - } - if (!EC_KEY_generate_key(key_pair.get())) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to generate a new Elliptic Curve " - "key pair."); - } - const EC_POINT* public_key_raw = EC_KEY_get0_public_key(key_pair.get()); - if (!public_key_raw) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to get a pointer to the public " - "key for a generated elliptic curve key pair."); - } - if (!EC_KEY_set_public_key(public_key.get(), public_key_raw)) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to set the public key for an " - "empty allocated elliptic curve key object."); - } - UniquePKEY private_pkey(EVP_PKEY_new()); - UniquePKEY public_pkey(EVP_PKEY_new()); - if (!private_pkey || !public_pkey) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to allocate and prepare a " - "high-level key object."); - } - if (!EVP_PKEY_set1_EC_KEY(private_pkey.get(), key_pair.get()) || - !EVP_PKEY_set1_EC_KEY(public_pkey.get(), key_pair.get())) { - throw UnexpectedOpenSSLCryptoFailureException( - "OpenSSL Crypto unexpectedly failed to initialize a high-level key " - "object given an elliptic curve key object."); - } + return pair, unique_ptr>( + new EVPPKEYPrivateKey(move(private_pkey), scheme_name), new EVPPKEYPublicKey(move(public_pkey), scheme_name)); +} - return pair, unique_ptr>( - new EVPPKEYPrivateKey(move(private_pkey), scheme_name), new EVPPKEYPublicKey(move(public_pkey), scheme_name)); +pair, unique_ptr> generateAsymmetricCryptoKeyPair( + const string& scheme_name) { + if (scheme_name == "secp256r1") { + return generateAsymmetricCryptoKeyPairById(NID_X9_62_prime256v1, scheme_name); } else { throw invalid_argument( "Cannot generate asymmetric cryptography key pair for cryptography " @@ -292,7 +236,7 @@ concord::util::openssl_utils::generateAsymmetricCryptoKeyPair(const string& sche const string kLegalHexadecimalDigits = "0123456789ABCDEFabcdef"; -unique_ptr concord::util::openssl_utils::deserializePrivateKey(const string& input) { +unique_ptr deserializePrivateKey(const string& input) { size_t first_split_point = input.find(':'); size_t second_split_point = input.rfind(':'); if ((first_split_point == string::npos) || (first_split_point == second_split_point)) { @@ -319,13 +263,13 @@ unique_ptr concord::util::openssl_utils::deserializePrivat // prime256v1 is an alternative name for the same curve parameters as // secp256r1; prime256v1 happens to be the name OpenSSL's Crypto library // uses for a possible parameter to EC_KEY_new_by_curve_name. - UniqueOpenSSLECKEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + UniqueECKEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); if (nullptr == ec_key.get()) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate and prepare an " "elliptic curve key object."); } - UniqueOpenSSLBIGNUM private_key(nullptr); + UniqueBIGNUM private_key(nullptr); BIGNUM* allocated_private_key = nullptr; int hex_parse_return_code = BN_hex2bn(&allocated_private_key, private_key_data.c_str()); private_key.reset(allocated_private_key); @@ -354,13 +298,13 @@ unique_ptr concord::util::openssl_utils::deserializePrivat "OpenSSL Crypto unexpectedly failed to fetch the elliptic curve " "group for an elliptic curve key object."); } - UniqueOpenSSLECPOINT public_key(EC_POINT_new(ec_group)); + UniqueECPOINT public_key(EC_POINT_new(ec_group)); if (!public_key) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate an elliptic curve " "point object."); } - UniqueOpenSSLBNCTX public_key_derivation_context(BN_CTX_new()); + UniqueBNCTX public_key_derivation_context(BN_CTX_new()); if (!public_key_derivation_context) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate a big number context " @@ -401,8 +345,8 @@ unique_ptr concord::util::openssl_utils::deserializePrivat } } -std::unique_ptr concord::util::openssl_utils::deserializePrivateKeyFromPem( - const std::string& path_to_file, const std::string& scheme) { +std::unique_ptr deserializePrivateKeyFromPem(const std::string& path_to_file, + const std::string& scheme) { if (scheme != "secp256r1") { throw invalid_argument("Failed to deserialize private key: scheme \"" + scheme + "\" is either not recognized, not supported, or has not been permitted " @@ -414,7 +358,7 @@ std::unique_ptr concord::util::openssl_utils::deserializeP if (nullptr == fp) { return nullptr; } - UniqueOpenSSLECKEY pkey(EC_KEY_new()); + UniqueECKEY pkey(EC_KEY_new()); if (!PEM_read_ECPrivateKey(fp.get(), reinterpret_cast(pkey.get()), nullptr, nullptr)) { throw UnexpectedOpenSSLCryptoFailureException( @@ -432,8 +376,8 @@ std::unique_ptr concord::util::openssl_utils::deserializeP return std::make_unique(std::move(private_pkey), "secp256r1"); } -std::unique_ptr concord::util::openssl_utils::deserializePrivateKeyFromPemString( - const std::string& pem_contents, const std::string& scheme) { +std::unique_ptr deserializePrivateKeyFromPemString(const std::string& pem_contents, + const std::string& scheme) { if (scheme != "secp256r1") { throw invalid_argument("Failed to deserialize private key from string: scheme \"" + scheme + "\" is either not recognized, not supported, or has not been permitted " @@ -485,8 +429,8 @@ std::unique_ptr concord::util::openssl_utils::deserializeP return std::make_unique(std::move(private_pkey), "secp256r1"); } -std::unique_ptr concord::util::openssl_utils::deserializePublicKeyFromPem( - const std::string& path_to_file, const std::string& scheme) { +std::unique_ptr deserializePublicKeyFromPem(const std::string& path_to_file, + const std::string& scheme) { if (scheme != "secp256r1") { throw invalid_argument("Failed to deserialize private key: scheme \"" + scheme + "\" is either not recognized, not supported, or has not been permitted " @@ -499,7 +443,7 @@ std::unique_ptr concord::util::openssl_utils::deserializePu throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to open the public key file for " + path_to_file); } - UniqueOpenSSLECKEY pkey(EC_KEY_new()); + UniqueECKEY pkey(EC_KEY_new()); if (!PEM_read_EC_PUBKEY(fp.get(), reinterpret_cast(pkey.get()), nullptr, nullptr)) { throw UnexpectedOpenSSLCryptoFailureException( @@ -515,7 +459,7 @@ std::unique_ptr concord::util::openssl_utils::deserializePu return std::make_unique(std::move(public_pkey), "secp256r1"); } -unique_ptr concord::util::openssl_utils::deserializePublicKey(const string& input) { +unique_ptr deserializePublicKey(const string& input) { size_t first_split_point = input.find(':'); size_t second_split_point = input.rfind(':'); if ((first_split_point == string::npos) || (first_split_point == second_split_point)) { @@ -542,7 +486,7 @@ unique_ptr concord::util::openssl_utils::deserializePublicK // prime256v1 is an alternative name for the same curve parameters as // secp256r1; prime256v1 happens to be the name OpenSSL's Crypto library // uses for a possible parameter to EC_KEY_new_by_curve_name. - UniqueOpenSSLECKEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + UniqueECKEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); if (nullptr == ec_key.get()) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate and prepare an " @@ -554,13 +498,13 @@ unique_ptr concord::util::openssl_utils::deserializePublicK "OpenSSL Crypto unexpectedly failed to fetch the elliptic curve " "group from an elliptic curve key object."); } - UniqueOpenSSLECPOINT public_key(EC_POINT_new(ec_group)); + UniqueECPOINT public_key(EC_POINT_new(ec_group)); if (!public_key) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate an elliptic curve " "point object."); } - UniqueOpenSSLBNCTX big_num_context(BN_CTX_new()); + UniqueBNCTX big_num_context(BN_CTX_new()); if (!big_num_context) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate a big number context " @@ -601,12 +545,10 @@ unique_ptr concord::util::openssl_utils::deserializePublicK } } -string concord::util::openssl_utils::computeSHA256Hash(const string& data) { - return computeSHA256Hash(data.data(), data.length()); -} +string computeSHA256Hash(const string& data) { return computeSHA256Hash(data.data(), data.length()); } -string concord::util::openssl_utils::computeSHA256Hash(const char* data, size_t length) { - UniqueOpenSSLContext digest_context(EVP_MD_CTX_new()); +string computeSHA256Hash(const char* data, size_t length) { + UniqueContext digest_context(EVP_MD_CTX_new()); if (!digest_context) { throw UnexpectedOpenSSLCryptoFailureException( "OpenSSL Crypto unexpectedly failed to allocate a message digest " @@ -639,4 +581,21 @@ string concord::util::openssl_utils::computeSHA256Hash(const char* data, size_t } return hash; -} \ No newline at end of file +} + +std::pair generateECDSAKeyPair(CurveType curveType, const KeyFormat fmt) { + // TODO(yf): need to implement PEM support + UNUSED(fmt); + UNUSED(curveType); + /* UNUSED(fmt); + if (curveType == CurveType::secp256k1) { + return generateAsymmetricCryptoKeyPairById(NID_secp256k1, fmt); + } + else if (curveType == CurveType::secp384r1) { + return generateAsymmetricCryptoKeyPairById(NID_secp256k1, fmt); + }*/ + ConcordAssert(false); + return {}; +} + +} // namespace concord::crypto::openssl \ No newline at end of file diff --git a/util/test/openssl_crypto_wrapper_tests.cpp b/util/test/openssl_crypto_wrapper_tests.cpp index bd43281352..256058c517 100644 --- a/util/test/openssl_crypto_wrapper_tests.cpp +++ b/util/test/openssl_crypto_wrapper_tests.cpp @@ -13,15 +13,15 @@ #include "gtest/gtest.h" -#include "openssl_crypto.hpp" - -using concord::util::openssl_utils::AsymmetricPrivateKey; -using concord::util::openssl_utils::AsymmetricPublicKey; -using concord::util::openssl_utils::deserializePrivateKey; -using concord::util::openssl_utils::deserializePrivateKeyFromPemString; -using concord::util::openssl_utils::deserializePublicKey; -using concord::util::openssl_utils::generateAsymmetricCryptoKeyPair; -using concord::util::openssl_utils::kPermittedAsymmetricCryptoSchemes; +#include "crypto/openssl/crypto.hpp" + +using concord::crypto::openssl::AsymmetricPrivateKey; +using concord::crypto::openssl::AsymmetricPublicKey; +using concord::crypto::openssl::deserializePrivateKey; +using concord::crypto::openssl::deserializePrivateKeyFromPemString; +using concord::crypto::openssl::deserializePublicKey; +using concord::crypto::openssl::generateAsymmetricCryptoKeyPair; +using concord::crypto::openssl::kPermittedAsymmetricCryptoSchemes; using std::invalid_argument; using std::pair; using std::string; diff --git a/util/test/openssl_digest_creator_test.cpp b/util/test/openssl_digest_creator_test.cpp index 4bfc1906b1..8850f650fe 100644 --- a/util/test/openssl_digest_creator_test.cpp +++ b/util/test/openssl_digest_creator_test.cpp @@ -16,8 +16,8 @@ #include "hex_tools.h" #include "crypto/openssl/digest_creator.hpp" -using concord::util::SHA2_256; -using concord::util::SHA3_256; +using concord::crypto::openssl::SHA2_256; +using concord::crypto::openssl::SHA3_256; using concord::crypto::openssl::OpenSSLDigestCreator; using DigestGeneratorTest_SHA2_256 = OpenSSLDigestCreator; diff --git a/util/test/openssl_digest_holder_test.cpp b/util/test/openssl_digest_holder_test.cpp index a839ffa448..22ce9e436c 100644 --- a/util/test/openssl_digest_holder_test.cpp +++ b/util/test/openssl_digest_holder_test.cpp @@ -17,8 +17,8 @@ #include "crypto/digest_holder.hpp" #include "crypto/openssl/digest_creator.hpp" -using concord::util::SHA2_256; -using concord::util::SHA3_256; +using concord::crypto::openssl::SHA2_256; +using concord::crypto::openssl::SHA3_256; using concord::crypto::DigestHolder; using concord::crypto::openssl::OpenSSLDigestCreator; diff --git a/util/test/openssl_utils_test.cpp b/util/test/openssl_utils_test.cpp index 2e96f2eaea..0ed26a465a 100644 --- a/util/test/openssl_utils_test.cpp +++ b/util/test/openssl_utils_test.cpp @@ -26,9 +26,10 @@ using concord::crypto::generateEdDSAKeyPair; using concord::crypto::EdDSAHexToPem; using concord::crypto::openssl::EdDSAPrivateKey; using concord::crypto::openssl::EdDSAPublicKey; -using concord::crypto::openssl::EdDSAPrivateKeyByteSize; -using concord::crypto::openssl::EdDSAPublicKeyByteSize; +using concord::crypto::Ed25519PrivateKeyByteSize; +using concord::crypto::Ed25519PublicKeyByteSize; using concord::crypto::openssl::deserializeKey; +using concord::crypto::CurveType; class EdDSATests : public ::testing::Test { public: @@ -68,8 +69,8 @@ class EdDSATests : public ::testing::Test { TEST_F(EdDSATests, TestHexFormatKeyLengths) { const auto keyPair = generateEdDSAKeyPair(KeyFormat::HexaDecimalStrippedFormat); - ASSERT_TRUE(concord::crypto::isValidKey("", keyPair.first, EdDSAPrivateKeyByteSize * 2)); - ASSERT_TRUE(concord::crypto::isValidKey("", keyPair.second, EdDSAPublicKeyByteSize * 2)); + ASSERT_TRUE(concord::crypto::isValidKey("", keyPair.first, Ed25519PrivateKeyByteSize * 2)); + ASSERT_TRUE(concord::crypto::isValidKey("", keyPair.second, Ed25519PublicKeyByteSize * 2)); } TEST_F(EdDSATests, TestPEMFormatValidity) { @@ -86,6 +87,15 @@ TEST_F(EdDSATests, TestInvalidSignature) { } } // namespace +TEST(openssl_test, generateECDSA) { + auto a = concord::crypto::openssl::generateAsymmetricCryptoKeyPairById(NID_secp256k1, "secp256k1"); + std::cout << a.first->serialize() << std::endl; + std::cout << a.second->serialize() << std::endl; + auto b = concord::crypto::openssl::generateAsymmetricCryptoKeyPairById(NID_secp384r1, "secp384r1"); + std::cout << b.first->serialize() << std::endl; + std::cout << b.second->serialize() << std::endl; +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/util/test/sha_hash_tests.cpp b/util/test/sha_hash_tests.cpp index 1a5f214502..f8e0405c57 100644 --- a/util/test/sha_hash_tests.cpp +++ b/util/test/sha_hash_tests.cpp @@ -17,8 +17,6 @@ #include "gtest/gtest.h" #include "crypto/openssl/hash.hpp" -using namespace concord::util; - namespace { // Convert a lowercase string hash to an array @@ -55,7 +53,7 @@ struct SHATest : public ::testing::Test { // All hash strings in this test were computed with https://emn178.github.io/online-tools/sha3_256.html struct SHA3_256TestType { - using Hash = SHA3_256; + using Hash = concord::crypto::openssl::SHA3_256; static constexpr auto OPENSSL_TYPE = "sha3-256"; static constexpr auto EMPTY_DIGEST = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"; static constexpr auto ARTIST_DIGEST = "2a3697512e6ce65dcf220b5c189c1045db4aaf59855a507b873d51c7505c54a5"; @@ -64,7 +62,7 @@ struct SHA3_256TestType { // All hash strings in this test were computed with https://emn178.github.io/online-tools/sha256.html struct SHA2_256TestType { - using Hash = SHA2_256; + using Hash = concord::crypto::openssl::SHA2_256; static constexpr auto OPENSSL_TYPE = "sha256"; static constexpr auto EMPTY_DIGEST = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; static constexpr auto ARTIST_DIGEST = "70b1e8e06785cae451496104850781f33faf6cc8e0777ecd3a9ccaaefb154b2d";