diff --git a/bftengine/src/bcstatetransfer/BCStateTran.cpp b/bftengine/src/bcstatetransfer/BCStateTran.cpp index 51b2e821fe..da4008f979 100644 --- a/bftengine/src/bcstatetransfer/BCStateTran.cpp +++ b/bftengine/src/bcstatetransfer/BCStateTran.cpp @@ -3880,17 +3880,17 @@ void BCStateTran::checkStoredCheckpoints(uint64_t firstStoredCheckpoint, uint64_ void BCStateTran::computeDigestOfPage( const uint32_t pageId, const uint64_t checkpointNumber, const char *page, uint32_t pageSize, Digest &outDigest) { DigestGenerator digestGenerator; - digestGenerator.updateDigest(reinterpret_cast(&pageId), sizeof(pageId)); - digestGenerator.updateDigest(reinterpret_cast(&checkpointNumber), sizeof(checkpointNumber)); + digestGenerator.update(reinterpret_cast(&pageId), sizeof(pageId)); + digestGenerator.update(reinterpret_cast(&checkpointNumber), sizeof(checkpointNumber)); if (checkpointNumber > 0) { - digestGenerator.updateDigest(page, pageSize); + digestGenerator.update(page, pageSize); } digestGenerator.writeDigest(reinterpret_cast(&outDigest)); } void BCStateTran::computeDigestOfPagesDescriptor(const DataStore::ResPagesDescriptor *pagesDesc, Digest &outDigest) { DigestGenerator digestGenerator; - digestGenerator.updateDigest(reinterpret_cast(pagesDesc), pagesDesc->size()); + digestGenerator.update(reinterpret_cast(pagesDesc), pagesDesc->size()); digestGenerator.writeDigest(reinterpret_cast(&outDigest)); } @@ -3901,8 +3901,8 @@ void BCStateTran::computeDigestOfBlockImpl(const uint64_t blockNum, ConcordAssertGT(blockNum, 0); ConcordAssertGT(blockSize, 0); DigestGenerator digestGenerator; - digestGenerator.updateDigest(reinterpret_cast(&blockNum), sizeof(blockNum)); - digestGenerator.updateDigest(block, blockSize); + digestGenerator.update(reinterpret_cast(&blockNum), sizeof(blockNum)); + digestGenerator.update(block, blockSize); digestGenerator.writeDigest(outDigest); } diff --git a/bftengine/src/bcstatetransfer/RVBManager.cpp b/bftengine/src/bcstatetransfer/RVBManager.cpp index bd79b9538a..332a0486bc 100644 --- a/bftengine/src/bcstatetransfer/RVBManager.cpp +++ b/bftengine/src/bcstatetransfer/RVBManager.cpp @@ -630,8 +630,8 @@ void RVBManager::computeDigestOfBlock(const uint64_t block_id, ConcordAssertGT(block_id, 0); ConcordAssertGT(block_size, 0); DigestGenerator digest_generator; - digest_generator.updateDigest(reinterpret_cast(&block_id), sizeof(block_id)); - digest_generator.updateDigest(block, block_size); + digest_generator.update(reinterpret_cast(&block_id), sizeof(block_id)); + digest_generator.update(block, block_size); digest_generator.writeDigest(out_digest); } diff --git a/bftengine/src/bcstatetransfer/RangeValidationTree.cpp b/bftengine/src/bcstatetransfer/RangeValidationTree.cpp index 695a7e6af6..6ada47d8b7 100644 --- a/bftengine/src/bcstatetransfer/RangeValidationTree.cpp +++ b/bftengine/src/bcstatetransfer/RangeValidationTree.cpp @@ -152,8 +152,8 @@ const shared_ptr RVBNode::computeNodeInitialValue(NodeInfo& node_info, c ConcordAssertGT(node_info.id(), 0); DigestGenerator digest_generator; - digest_generator.updateDigest(reinterpret_cast(&node_info.id_data_), sizeof(node_info.id_data_)); - digest_generator.updateDigest(data, data_size); + digest_generator.update(reinterpret_cast(&node_info.id_data_), sizeof(node_info.id_data_)); + digest_generator.update(data, data_size); // TODO - Use default_delete in case memleak is reported by ASAN static std::shared_ptr out_digest_buff(new char[NodeVal::kDigestContextOutputSize]); digest_generator.writeDigest(out_digest_buff.get()); diff --git a/bftengine/src/bftengine/NullStateTransfer.cpp b/bftengine/src/bftengine/NullStateTransfer.cpp index c93b0226ad..19c23184b5 100644 --- a/bftengine/src/bftengine/NullStateTransfer.cpp +++ b/bftengine/src/bftengine/NullStateTransfer.cpp @@ -64,7 +64,7 @@ void NullStateTransfer::getDigestOfCheckpoint(uint64_t checkpointNumber, Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest((char*)&checkpointNumber, sizeof(checkpointNumber), (char*)&d, sizeof(d)); + digestGenerator.compute((char*)&checkpointNumber, sizeof(checkpointNumber), (char*)&d, sizeof(d)); memset(outStateDigest, 0, sizeOfDigestBuffer); memset(outResPagesDigest, 0, sizeOfDigestBuffer); diff --git a/bftengine/src/bftengine/ReplicaImp.cpp b/bftengine/src/bftengine/ReplicaImp.cpp index 001436b9d5..8acc3f78eb 100644 --- a/bftengine/src/bftengine/ReplicaImp.cpp +++ b/bftengine/src/bftengine/ReplicaImp.cpp @@ -1340,13 +1340,8 @@ void ReplicaImp::sendPartialProof(SeqNumInfo &seqNumInfo) { else commitSigner = CryptoManager::instance().thresholdSignerForOptimisticCommit(seqNum); -<<<<<<< HEAD Digest tmpDigest; - Digest digestHelper; -======= - Digest tmpDigest, digestHelper; ->>>>>>> Digest generation using OpenSSL library (SHA2_256 & SHA3_256 algos). - digestHelper.calcCombination(ppDigest, getCurrentView(), seqNum, tmpDigest); + ppDigest.calcCombination(getCurrentView(), seqNum, tmpDigest); const auto &span_context = pp->spanContext::type>(); part = new PartialCommitProofMsg( @@ -1419,8 +1414,8 @@ void ReplicaImp::sendCommitPartial(const SeqNum s) { LOG_INFO(CNSUS, "Sending CommitPartialMsg, sequence number:" << pp->seqNumber()); - Digest digest, digestHelper; - digestHelper.digestOfDigest(pp->digestOfRequests(), digest); + Digest digest; + pp->digestOfRequests().digestOfDigest(digest); auto prepareFullMsg = seqNumInfo.getValidPrepareFullMsg(); @@ -4122,13 +4117,8 @@ ReplicaImp::ReplicaImp(const LoadedReplicaData &ld, else commitSigner = CryptoManager::instance().thresholdSignerForOptimisticCommit(seqNum); -<<<<<<< HEAD Digest tmpDigest; - Digest digestHelper; -======= - Digest tmpDigest, digestHelper; ->>>>>>> Digest generation using OpenSSL library (SHA2_256 & SHA3_256 algos). - digestHelper.calcCombination(ppDigest, getCurrentView(), seqNum, tmpDigest); + ppDigest.calcCombination(getCurrentView(), seqNum, tmpDigest); PartialCommitProofMsg *p = new PartialCommitProofMsg( config_.getreplicaId(), getCurrentView(), seqNum, pathInPrePrepare, tmpDigest, commitSigner); @@ -4157,8 +4147,8 @@ ReplicaImp::ReplicaImp(const LoadedReplicaData &ld, throw; } - Digest digest, digestHelper; - digestHelper.digestOfDigest(e.getPrePrepareMsg()->digestOfRequests(), digest); + Digest digest; + e.getPrePrepareMsg()->digestOfRequests().digestOfDigest(digest); CommitPartialMsg *c = CommitPartialMsg::create(getCurrentView(), s, config_.getreplicaId(), diff --git a/bftengine/src/bftengine/SeqNumInfo.cpp b/bftengine/src/bftengine/SeqNumInfo.cpp index 8db861c2ca..ee5a0c12a0 100644 --- a/bftengine/src/bftengine/SeqNumInfo.cpp +++ b/bftengine/src/bftengine/SeqNumInfo.cpp @@ -103,8 +103,7 @@ bool SeqNumInfo::addMsg(PrePrepareMsg* m, bool directAdd, bool isTimeCorrect) { // set expected Digest tmpDigest; - Digest digestHelper; - digestHelper.calcCombination(m->digestOfRequests(), m->viewNumber(), m->seqNumber(), tmpDigest); + m->digestOfRequests().calcCombination(m->viewNumber(), m->seqNumber(), tmpDigest); if (!directAdd) prepareSigCollector->setExpected(m->seqNumber(), m->viewNumber(), tmpDigest); else @@ -130,8 +129,7 @@ bool SeqNumInfo::addSelfMsg(PrePrepareMsg* m, bool directAdd) { // set expected Digest tmpDigest; - Digest digestHelper; - digestHelper.calcCombination(m->digestOfRequests(), m->viewNumber(), m->seqNumber(), tmpDigest); + m->digestOfRequests().calcCombination(m->viewNumber(), m->seqNumber(), tmpDigest); if (!directAdd) prepareSigCollector->setExpected(m->seqNumber(), m->viewNumber(), tmpDigest); else @@ -197,8 +195,7 @@ bool SeqNumInfo::addSelfCommitPartialMsgAndDigest(CommitPartialMsg* m, Digest& c ConcordAssert(!forcedCompleted); Digest tmpDigest; - Digest digestHelper; - digestHelper.calcCombination(commitDigest, m->viewNumber(), m->seqNumber(), tmpDigest); + commitDigest.calcCombination(m->viewNumber(), m->seqNumber(), tmpDigest); bool r; if (!directAdd) { commitMsgsCollector->setExpected(m->seqNumber(), m->viewNumber(), tmpDigest); diff --git a/bftengine/src/bftengine/ViewChangeSafetyLogic.cpp b/bftengine/src/bftengine/ViewChangeSafetyLogic.cpp index be30b26772..b915ed630c 100644 --- a/bftengine/src/bftengine/ViewChangeSafetyLogic.cpp +++ b/bftengine/src/bftengine/ViewChangeSafetyLogic.cpp @@ -277,8 +277,8 @@ bool ViewChangeSafetyLogic::computeRestrictionsForSeqNum(SeqNum s, for (SlowElem slow : slowPathCertificates) { ConcordAssert(s == slow.seqNum()); - Digest d, digestHelper; - digestHelper.calcCombination(slow.prePrepreDigest(), slow.certificateView(), slow.seqNum(), d); + Digest d; + slow.prePrepreDigest().calcCombination(slow.certificateView(), slow.seqNum(), d); bool valid = CryptoManager::instance().thresholdVerifierForSlowPathCommit(s)->verify( d.content(), DIGEST_SIZE, slow.certificateSig(), slow.certificateSigLength()); diff --git a/bftengine/src/bftengine/messages/PrePrepareMsg.cpp b/bftengine/src/bftengine/messages/PrePrepareMsg.cpp index a93a6dd446..f7ac8a07fe 100644 --- a/bftengine/src/bftengine/messages/PrePrepareMsg.cpp +++ b/bftengine/src/bftengine/messages/PrePrepareMsg.cpp @@ -59,7 +59,7 @@ void PrePrepareMsg::calculateDigestOfRequests(Digest& digest) const { tasks.push_back(threadPool.async( [&sigOrDigestOfRequest, &digestBuffer, local_id](auto* request, auto requestLength) { DigestGenerator digestGenerator; - digestGenerator.computeDigest( + digestGenerator.compute( request, requestLength, digestBuffer.get() + local_id * sizeof(Digest), sizeof(Digest)); sigOrDigestOfRequest[local_id].first = digestBuffer.get() + local_id * sizeof(Digest); sigOrDigestOfRequest[local_id].second = sizeof(Digest); @@ -80,7 +80,7 @@ void PrePrepareMsg::calculateDigestOfRequests(Digest& digest) const { // compute and set digest DigestGenerator digestGenerator; - digestGenerator.computeDigest(sigOrDig.c_str(), sigOrDig.size(), (char*)&digest, sizeof(Digest)); + digestGenerator.compute(sigOrDig.c_str(), sigOrDig.size(), (char*)&digest, sizeof(Digest)); } catch (std::out_of_range& ex) { throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(": digest threadpool")); } diff --git a/bftengine/src/bftengine/messages/SignedShareMsgs.cpp b/bftengine/src/bftengine/messages/SignedShareMsgs.cpp index dc67447088..e64fbb3f34 100644 --- a/bftengine/src/bftengine/messages/SignedShareMsgs.cpp +++ b/bftengine/src/bftengine/messages/SignedShareMsgs.cpp @@ -48,8 +48,7 @@ SignedShareBase* SignedShareBase::create(int16_t type, m->b()->thresSigLength = (uint16_t)sigLen; Digest tmpDigest; - Digest digestHelper; - digestHelper.calcCombination(digest, v, s, tmpDigest); + digest.calcCombination(v, s, tmpDigest); auto position = m->body() + sizeof(Header); std::memcpy(position, spanContext.data().data(), spanContext.data().size()); diff --git a/bftengine/src/bftengine/messages/ViewChangeMsg.cpp b/bftengine/src/bftengine/messages/ViewChangeMsg.cpp index e044a41446..40de987b2e 100644 --- a/bftengine/src/bftengine/messages/ViewChangeMsg.cpp +++ b/bftengine/src/bftengine/messages/ViewChangeMsg.cpp @@ -52,7 +52,7 @@ void ViewChangeMsg::getMsgDigest(Digest& outDigest) const { auto bodySize = getBodySize(); bodySize += b()->sizeOfAllComplaints; DigestGenerator digestGenerator; - digestGenerator.computeDigest(body(), bodySize, (char*)outDigest.content(), sizeof(Digest)); + digestGenerator.compute(body(), bodySize, (char*)outDigest.content(), sizeof(Digest)); } uint32_t ViewChangeMsg::getBodySize() const { diff --git a/bftengine/tests/messages/PrePrepareMsg_test.cpp b/bftengine/tests/messages/PrePrepareMsg_test.cpp index 8b890963f6..df671aeb04 100644 --- a/bftengine/tests/messages/PrePrepareMsg_test.cpp +++ b/bftengine/tests/messages/PrePrepareMsg_test.cpp @@ -139,7 +139,7 @@ TEST_F(PrePrepareMsgTestFixture, finalize_and_validate) { msg.addRequest(crm->body(), crm->size()); Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest(crm->body(), crm->size(), (char*)&d, sizeof(Digest)); + digestGenerator.compute(crm->body(), crm->size(), (char*)&d, sizeof(Digest)); dv.push_back({d.content(), sizeof(Digest)}); } EXPECT_NO_THROW(msg.finishAddingRequests()); // create the digest @@ -151,7 +151,7 @@ TEST_F(PrePrepareMsgTestFixture, finalize_and_validate) { } Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest(dod.c_str(), dod.size(), (char*)&d, sizeof(Digest)); + digestGenerator.compute(dod.c_str(), dod.size(), (char*)&d, sizeof(Digest)); EXPECT_EQ(d, msg.digestOfRequests()); EXPECT_NO_THROW(msg.validate(replicaInfo)); // validate the same digest } diff --git a/tests/simpleKVBC/TesterReplica/strategy/MangledPreProcessResultMsgStrategy.cpp b/tests/simpleKVBC/TesterReplica/strategy/MangledPreProcessResultMsgStrategy.cpp index 7828386c2f..1021043607 100644 --- a/tests/simpleKVBC/TesterReplica/strategy/MangledPreProcessResultMsgStrategy.cpp +++ b/tests/simpleKVBC/TesterReplica/strategy/MangledPreProcessResultMsgStrategy.cpp @@ -57,7 +57,7 @@ bool concord::kvbc::strategy::MangledPreProcessResultMsgStrategy::changeMessage( } else { Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest(req.body(), req.size(), reinterpret_cast(&d), sizeof(Digest)); + digestGenerator.compute(req.body(), req.size(), reinterpret_cast(&d), sizeof(Digest)); sigOrDigestOfRequest[idx].append(d.content(), sizeof(Digest)); } idx++; @@ -71,7 +71,7 @@ bool concord::kvbc::strategy::MangledPreProcessResultMsgStrategy::changeMessage( Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest(sigOrDig.c_str(), sigOrDig.size(), reinterpret_cast(&d), sizeof(Digest)); + digestGenerator.compute(sigOrDig.c_str(), sigOrDig.size(), reinterpret_cast(&d), sizeof(Digest)); nmsg.digestOfRequests() = d; LOG_INFO(logger_, "Finally the PrePrepare Message with correlation id : " diff --git a/tests/simpleKVBC/TesterReplica/strategy/ShufflePrePrepareMsgStrategy.cpp b/tests/simpleKVBC/TesterReplica/strategy/ShufflePrePrepareMsgStrategy.cpp index 5c30ae8c20..2277184d6b 100644 --- a/tests/simpleKVBC/TesterReplica/strategy/ShufflePrePrepareMsgStrategy.cpp +++ b/tests/simpleKVBC/TesterReplica/strategy/ShufflePrePrepareMsgStrategy.cpp @@ -73,7 +73,7 @@ bool ShufflePrePrepareMsgStrategy::changeMessage(std::shared_ptr& m } else { Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest(req.body(), req.size(), reinterpret_cast(&d), sizeof(Digest)); + digestGenerator.compute(req.body(), req.size(), reinterpret_cast(&d), sizeof(Digest)); if (idx == swapIdx) { sigOrDigestOfRequest[idx + 1].append(d.content(), sizeof(Digest)); } else if (idx == (swapIdx + 1)) { @@ -98,7 +98,7 @@ bool ShufflePrePrepareMsgStrategy::changeMessage(std::shared_ptr& m Digest d; DigestGenerator digestGenerator; - digestGenerator.computeDigest(sigOrDig.c_str(), sigOrDig.size(), reinterpret_cast(&d), sizeof(Digest)); + digestGenerator.compute(sigOrDig.c_str(), sigOrDig.size(), reinterpret_cast(&d), sizeof(Digest)); nmsg.digestOfRequests() = d; LOG_INFO(logger_, "Finally the PrePrepare Message with correlation id : " diff --git a/util/include/DigestImpl.ipp b/util/include/DigestImpl.ipp new file mode 100644 index 0000000000..d52fa8a714 --- /dev/null +++ b/util/include/DigestImpl.ipp @@ -0,0 +1,144 @@ +// 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 subcomponent's license, as noted in the LICENSE +// file. + +#pragma once + +#include +#include +#include +#include + +#include "sha_hash.hpp" +#include "DigestType.hpp" +#include "hex_tools.h" + +namespace concord::util::digest { + +class DigestUtil { + public: + static size_t digestLength(); + static bool compute(const char* input, size_t inputLength, char* outBufferForDigest, size_t lengthOfBufferForDigest); + + class Context { + public: + Context(); + void update(const char* data, size_t len); + void writeDigest(char* outDigest); // write digest to outDigest, and invalidate the Context object + ~Context(); + + private: + void* internalState; + }; +}; + +class DigestCreator { + public: + virtual ~DigestCreator() = default; + + virtual void init() = 0; + virtual void compute() = 0; + virtual void update() = 0; + virtual void final() = 0; +}; + +template >> +class DigestHolder { + public: + DigestHolder() { std::memset(d, 0, DIGEST_SIZE); } + DigestHolder(unsigned char initVal) { std::memset(d, initVal, DIGEST_SIZE); } + DigestHolder(const char* other) { std::memcpy(d, other, DIGEST_SIZE); } + DigestHolder(char* buf, size_t len) { DigestUtil::compute(buf, len, (char*)d, DIGEST_SIZE); } + DigestHolder(const DigestHolder& other) { std::memcpy(d, other.d, DIGEST_SIZE); } + + char* content() const { return (char*)d; } // Can be replaced by getForUpdate(). + void makeZero() { std::memset(d, 0, DIGEST_SIZE); } + std::string toString() const { return concordUtils::bufferToHex(d, DIGEST_SIZE, false); } + void print() { printf("digest=[%s]", toString().c_str()); } + const char* const get() const { return d; } + char* getForUpdate() { return d; } + + bool isZero() const { + for (int i = 0; i < DIGEST_SIZE; ++i) { + if (d[i] != 0) return false; + } + return true; + } + + int hash() const { + uint64_t* p = (uint64_t*)d; + int h = (int)p[0]; + return h; + } + + bool operator==(const DigestHolder& other) const { + int r = std::memcmp(d, other.d, DIGEST_SIZE); + return (r == 0); + } + + bool operator!=(const DigestHolder& other) const { + int r = std::memcmp(d, other.d, DIGEST_SIZE); + return (r != 0); + } + + DigestHolder& operator=(const DigestHolder& other) { + if (this == &other) { + return *this; + } + std::memcpy(d, other.d, DIGEST_SIZE); + return *this; + } + + static void digestOfDigest(const DigestHolder& inDigest, DigestHolder& outDigest) { + DigestUtil::compute(inDigest.d, sizeof(DigestHolder), outDigest.d, sizeof(DigestHolder)); + } + + static void calcCombination(const DigestHolder& inDigest, int64_t inDataA, int64_t inDataB, DigestHolder& outDigest) { + const size_t X = ((DIGEST_SIZE / sizeof(uint64_t)) / 2); + + std::memcpy(outDigest.d, inDigest.d, DIGEST_SIZE); + + uint64_t* ptr = (uint64_t*)outDigest.d; + size_t locationA = ptr[0] % X; + size_t locationB = (ptr[0] >> 8) % X; + ptr[locationA] = ptr[locationA] ^ (inDataA); + ptr[locationB] = ptr[locationB] ^ (inDataB); + } + + private: + char d[DIGEST_SIZE]; // DIGEST_SIZE should be >= 8 bytes; // Stores digest. +}; + +// Implements digest using Crypto++ library. +class CryptoppDigestCreator : public DigestCreator { + public: + void init() override {} + void compute() override {} + void update() override {} + void final() override {} + virtual ~CryptoppDigestCreator() = default; +}; + +// Implements digest using OpenSSL library. +template || + std::is_same_v>> +class OpenSSLDigestCreator : public DigestCreator { + public: + virtual ~OpenSSLDigestCreator() = default; + void init() override {} + void compute() override {} + void update() override {} + void final() override {} + + private: + SHACTX hash_ctx_; +}; +} // namespace concord::util::digest diff --git a/util/include/cryptopp_digest_creator.hpp b/util/include/cryptopp_digest_creator.hpp index 364062b056..c4b78e85be 100644 --- a/util/include/cryptopp_digest_creator.hpp +++ b/util/include/cryptopp_digest_creator.hpp @@ -38,10 +38,10 @@ class CryptoppDigestCreator : public DigestCreator { void update(const char* data, size_t len) override; void writeDigest(char* outDigest) override; size_t digestLength() const override; - bool computeDigest(const char* input, - const size_t inputLength, - char* outBufferForDigest, - const size_t lengthOfBufferForDigest) override; + bool compute(const char* input, + size_t inputLength, + char* outBufferForDigest, + size_t lengthOfBufferForDigest) override; private: void* internalState_; diff --git a/util/include/digest_creator.hpp b/util/include/digest_creator.hpp index 578a3123e7..bfff275e21 100644 --- a/util/include/digest_creator.hpp +++ b/util/include/digest_creator.hpp @@ -24,9 +24,9 @@ class DigestCreator { virtual void update(const char* data, size_t len) = 0; virtual void writeDigest(char* outDigest) = 0; virtual size_t digestLength() const = 0; - virtual bool computeDigest(const char* input, - const size_t inputLength, - char* outBufferForDigest, - const size_t lengthOfBufferForDigest) = 0; + virtual bool compute(const char* input, + size_t inputLength, + char* outBufferForDigest, + size_t lengthOfBufferForDigest) = 0; }; } // namespace concord::util::digest diff --git a/util/include/digest_holder.hpp b/util/include/digest_holder.hpp index 4cf5c25231..a77ab36f92 100644 --- a/util/include/digest_holder.hpp +++ b/util/include/digest_holder.hpp @@ -14,7 +14,7 @@ #include #include -#include "digest.hpp" +#include "digest_type.hpp" #include "digest_creator.hpp" #include "hex_tools.h" @@ -29,9 +29,16 @@ class DigestHolder { DigestHolder(const char* other) { std::memcpy(d, other, DIGEST_SIZE); } DigestHolder(char* buf, size_t len) { CREATOR digestCreator; - digestCreator.computeDigest(buf, len, (char*)d, DIGEST_SIZE); + digestCreator.compute(buf, len, (char*)d, DIGEST_SIZE); } DigestHolder(const DigestHolder& other) { std::memcpy(d, other.d, DIGEST_SIZE); } + DigestHolder& operator=(const DigestHolder& other) { + if (this == &other) { + return *this; + } + std::memcpy(d, other.d, DIGEST_SIZE); + return *this; + } char* content() const { return (char*)d; } void makeZero() { std::memset(d, 0, DIGEST_SIZE); } @@ -63,23 +70,15 @@ class DigestHolder { return (r != 0); } - DigestHolder& operator=(const DigestHolder& other) { - if (this == &other) { - return *this; - } - std::memcpy(d, other.d, DIGEST_SIZE); - return *this; - } - - void digestOfDigest(const DigestHolder& inDigest, DigestHolder& outDigest) { + void digestOfDigest(DigestHolder& outDigest) { CREATOR digestCreator; - digestCreator.computeDigest(inDigest.d, sizeof(DigestHolder), outDigest.d, sizeof(DigestHolder)); + digestCreator.compute(d, sizeof(DigestHolder), outDigest.d, sizeof(DigestHolder)); } - void calcCombination(const DigestHolder& inDigest, int64_t inDataA, int64_t inDataB, DigestHolder& outDigest) { + void calcCombination(int64_t inDataA, int64_t inDataB, DigestHolder& outDigest) { const size_t X = ((DIGEST_SIZE / sizeof(uint64_t)) / 2); - std::memcpy(outDigest.d, inDigest.d, DIGEST_SIZE); + std::memcpy(outDigest.d, d, DIGEST_SIZE); uint64_t* ptr = (uint64_t*)outDigest.d; size_t locationA = ptr[0] % X; diff --git a/util/include/evp_hash.hpp b/util/include/evp_hash.hpp index 908dad3660..e00686a9b6 100644 --- a/util/include/evp_hash.hpp +++ b/util/include/evp_hash.hpp @@ -45,9 +45,6 @@ class EVPHash { }; EVPHash& operator=(EVPHash&& other) noexcept { - if (nullptr != ctx_) { // Prevent memory leak. - EVP_MD_CTX_destroy(ctx_); - } *this = EVPHash{std::move(other)}; return *this; } @@ -101,7 +98,10 @@ class EVPHash { } std::string toHexString(const Digest& digest) { - return concordUtils::bufferToHex(std::string(digest.begin(), digest.end()).c_str(), SIZE_IN_BYTES, false); + std::ostringstream oss; + for (size_t i = 0; i < SIZE_IN_BYTES; ++i) + oss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (0xff & (unsigned int)digest[i]); + return oss.str(); } private: diff --git a/util/include/openssl_digest_creator.ipp b/util/include/openssl_digest_creator.ipp index 01128848d8..bc1ff35e7d 100644 --- a/util/include/openssl_digest_creator.ipp +++ b/util/include/openssl_digest_creator.ipp @@ -39,7 +39,7 @@ class OpenSSLDigestCreator : public DigestCreator { } } - void updateDigest(const char* data, const size_t len) { + void update(const char* data, size_t len) { ConcordAssert(nullptr != data); init(); @@ -56,10 +56,7 @@ class OpenSSLDigestCreator : public DigestCreator { size_t digestLength() const { return hash_ctx_.SIZE_IN_BYTES; } - bool computeDigest(const char* input, - const size_t inputLength, - char* outBufferForDigest, - const size_t lengthOfBufferForDigest) { + bool compute(const char* input, size_t inputLength, char* outBufferForDigest, size_t lengthOfBufferForDigest) { ConcordAssert(nullptr != input); ConcordAssert(nullptr != outBufferForDigest); diff --git a/util/src/DigestImpl.cpp b/util/src/DigestImpl.cpp new file mode 100644 index 0000000000..683ce983e8 --- /dev/null +++ b/util/src/DigestImpl.cpp @@ -0,0 +1,92 @@ +// 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 subcomponent's license, as noted in the LICENSE +// file. + +#include +#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include +#include +#pragma GCC diagnostic pop + +#include "assertUtils.hpp" +#include +#include +#include + +#include "DigestImpl.ipp" + +#if defined MD5_DIGEST +#include +#define DigestType Weak1::MD5 +#elif defined SHA256_DIGEST +#define DigestType SHA256 +#elif defined SHA512_DIGEST +#define DigestType SHA512 +#endif + +using namespace CryptoPP; + +namespace concord::util::digest { + +size_t DigestUtil::digestLength() { return DigestType::DIGESTSIZE; } + +bool DigestUtil::compute(const char* input, + size_t inputLength, + char* outBufferForDigest, + size_t lengthOfBufferForDigest) { + DigestType dig; + + size_t size = dig.DigestSize(); + + if (lengthOfBufferForDigest < size) return false; + + SecByteBlock digest(size); + + dig.Update((CryptoPP::byte*)input, inputLength); + dig.Final(digest); + const CryptoPP::byte* h = digest; + memcpy(outBufferForDigest, h, size); + + return true; +} + +DigestUtil::Context::Context() { + DigestType* p = new DigestType(); + internalState = p; +} + +void DigestUtil::Context::update(const char* data, size_t len) { + ConcordAssert(internalState != NULL); + DigestType* p = (DigestType*)internalState; + p->Update((CryptoPP::byte*)data, len); +} + +void DigestUtil::Context::writeDigest(char* outDigest) { + ConcordAssert(internalState != NULL); + DigestType* p = (DigestType*)internalState; + SecByteBlock digest(digestLength()); + p->Final(digest); + const CryptoPP::byte* h = digest; + memcpy(outDigest, h, digestLength()); + + delete p; + internalState = NULL; +} + +DigestUtil::Context::~Context() { + if (internalState != NULL) { + DigestType* p = (DigestType*)internalState; + delete p; + internalState = NULL; + } +} +} // namespace concord::util::digest diff --git a/util/src/cryptopp_digest_creator.cpp b/util/src/cryptopp_digest_creator.cpp index 4aba292623..7d9dc88b00 100644 --- a/util/src/cryptopp_digest_creator.cpp +++ b/util/src/cryptopp_digest_creator.cpp @@ -35,10 +35,10 @@ CryptoppDigestCreator::CryptoppDigestCreator() { size_t CryptoppDigestCreator::digestLength() const { return DigestType::DIGESTSIZE; } -bool CryptoppDigestCreator::computeDigest(const char* input, - const size_t inputLength, - char* outBufferForDigest, - const size_t lengthOfBufferForDigest) { +bool CryptoppDigestCreator::compute(const char* input, + size_t inputLength, + char* outBufferForDigest, + size_t lengthOfBufferForDigest) { DigestType dig; const size_t size = dig.DigestSize(); @@ -57,7 +57,7 @@ bool CryptoppDigestCreator::computeDigest(const char* input, return true; } -void CryptoppDigestCreator::updateDigest(const char* data, const size_t len) { +void CryptoppDigestCreator::update(const char* data, size_t len) { ConcordAssert(nullptr != internalState_); DigestType* p = (DigestType*)internalState_; diff --git a/util/test/CMakeLists.txt b/util/test/CMakeLists.txt index 3ad79aac0b..36f6c7ab0e 100644 --- a/util/test/CMakeLists.txt +++ b/util/test/CMakeLists.txt @@ -94,3 +94,7 @@ target_link_libraries(cryptopp_digest_creator_test GTest::Main util) add_executable(openssl_digest_creator_test openssl_digest_creator_test.cpp) add_test(openssl_digest_creator_test openssl_digest_creator_test) target_link_libraries(openssl_digest_creator_test GTest::Main util) + +add_executable(digest_holder_test digest_holder_test.cpp) +add_test(digest_holder_test digest_holder_test) +target_link_libraries(digest_holder_test GTest::Main util) diff --git a/util/test/digest_holder_test.cpp b/util/test/digest_holder_test.cpp new file mode 100644 index 0000000000..76fd3987af --- /dev/null +++ b/util/test/digest_holder_test.cpp @@ -0,0 +1,142 @@ +// 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 subcomponent's license, as noted in the LICENSE +// file. +// + +#include "gtest/gtest.h" +#include "hex_tools.h" +#include "digest_holder.hpp" +#include "cryptopp_digest_creator.hpp" + +using concord::util::digest::DigestHolder; +using concord::util::digest::CryptoppDigestCreator; + +using Digest = DigestHolder; + +// Hashes are generated via https://emn178.github.io/online-tools/sha256.html +struct SHA_Hashes { + std::string input; + std::string hash; +}; +SHA_Hashes sha256_hashes[] = {{"sha256", "5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e"}, + {"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}, + {"vmware", "592cc302663c0021ffa92186bf3c1a579a97e5e01f8b28f766855e5b121f8bda"}, + {"5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e", "20a30eabfaa29aff866ce471dd7bc129cb3c368bc49409a499a1fbd5851b36cb"}/* Digest of digest (sha256_hashes[0].input). + Change the input type to Hex in online tool. To calculate digestOfDigest. */}; + +namespace { + +TEST(digest_holder_test, test_constructors) { + { + Digest digest; + ASSERT_EQ(true, digest.isZero()); + } + { + unsigned char c = 'a'; + Digest digest(c); + ASSERT_EQ(false, digest.isZero()); + ASSERT_EQ(0, memcmp(digest.content(), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", DIGEST_SIZE)); + + digest.makeZero(); + ASSERT_EQ(true, digest.isZero()); + } + { + const char* cp = "VMware."; + Digest digest(cp); + ASSERT_EQ(false, digest.isZero()); + ASSERT_EQ(0, memcmp(digest.content(), "VMware.", strlen(cp))); + + digest.makeZero(); + ASSERT_EQ(true, digest.isZero()); + } + { + const char* cp = "This is a string whose length is greater than DIGEST_SIZE."; + Digest digest(cp); + ASSERT_EQ(false, digest.isZero()); + ASSERT_EQ(0, memcmp(digest.content(), "This is a string whose length is", DIGEST_SIZE)); + + digest.makeZero(); + ASSERT_EQ(true, digest.isZero()); + } + { + const char* cp = "VMware."; + Digest digest(cp); + ASSERT_EQ(false, digest.isZero()); + ASSERT_EQ(0, memcmp(digest.content(), "VMware.", strlen(cp))); + + Digest digest_1 = digest; // Copy constructor test. + ASSERT_EQ(false, digest_1.isZero()); + ASSERT_EQ(0, memcmp(digest_1.content(), "VMware.", strlen(cp))); + + digest_1.makeZero(); + ASSERT_EQ(true, digest_1.isZero()); + } + { + Digest digest(sha256_hashes[0].input.data(), sha256_hashes[0].input.size()); + ASSERT_EQ(false, digest.isZero()); + ASSERT_EQ(0, + memcmp(sha256_hashes[0].hash.data(), + concordUtils::bufferToHex(digest.get(), DIGEST_SIZE, false).data(), + DIGEST_SIZE)); + + std::string s1 = concordUtils::bufferToHex(digest.getForUpdate(), DIGEST_SIZE, false); + std::string s2 = digest.toString(); + + ASSERT_EQ(s1, s2); + } +} + +TEST(digest_holder_test, test_overloaded_operators) { + { + const char* cp = "VMware."; + Digest digest_1(cp); + Digest digest_2(cp); + + ASSERT_EQ(true, digest_1 == digest_2); + ASSERT_EQ(false, digest_1 != digest_2); + + ASSERT_EQ(true, digest_2 == digest_1); + ASSERT_EQ(false, digest_2 != digest_1); + } + { + const char* cp = "VMware."; + Digest digest_1(cp); + Digest digest_2('c'); + + ASSERT_EQ(false, digest_1 == digest_2); + ASSERT_EQ(true, digest_1 != digest_2); + } + { + const char* cp = "VMware."; + Digest digest_1(cp); + Digest digest_2; + digest_2 = digest_1; // Assignment copy operator. + + ASSERT_EQ(true, digest_1 == digest_2); + ASSERT_EQ(false, digest_1 != digest_2); + } +} + +TEST(digest_holder_test, test_digest_of_digest) { + Digest digest(sha256_hashes[0].input.data(), sha256_hashes[0].input.size()); + Digest digest_of_digest; + + digest.digestOfDigest(digest_of_digest); + + ASSERT_EQ(true, digest_of_digest.toString() == sha256_hashes[3].hash); +} +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}