diff options
author | Oliver Reiche <oliver.reiche@huawei.com> | 2022-06-15 18:51:47 +0200 |
---|---|---|
committer | Oliver Reiche <oliver.reiche@huawei.com> | 2022-06-20 15:23:02 +0200 |
commit | 855affd9b681d98f248009ddb2c1abe987029f72 (patch) | |
tree | 6d4dbfc2c99020772313f381d2f793950d2b03f4 /src | |
parent | 391d982f2fbd98a2973f14e0b5969f66c2abd756 (diff) | |
download | justbuild-855affd9b681d98f248009ddb2c1abe987029f72.tar.gz |
Crypto: Refactor hash computation
... by renaming HashGenerator to (incremental) Hasher and
dropping support for Git/MD5 hashes. The Hasher does not
expose the actual hash implementation.
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/build_engine/expression/expression.cpp | 7 | ||||
-rw-r--r-- | src/buildtool/build_engine/target_map/utils.cpp | 14 | ||||
-rw-r--r-- | src/buildtool/crypto/TARGETS | 30 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_function.hpp | 20 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_generator.hpp | 127 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl.hpp | 40 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_git.cpp | 42 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_git.hpp | 10 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_md5.cpp | 50 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_md5.hpp | 10 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_sha1.cpp | 11 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_sha1.hpp | 5 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_sha256.cpp | 11 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_impl_sha256.hpp | 5 | ||||
-rw-r--r-- | src/buildtool/crypto/hasher.cpp | 14 | ||||
-rw-r--r-- | src/buildtool/crypto/hasher.hpp | 104 |
16 files changed, 150 insertions, 350 deletions
diff --git a/src/buildtool/build_engine/expression/expression.cpp b/src/buildtool/build_engine/expression/expression.cpp index 91d293bc..6ae9bd87 100644 --- a/src/buildtool/build_engine/expression/expression.cpp +++ b/src/buildtool/build_engine/expression/expression.cpp @@ -239,12 +239,7 @@ auto Expression::ComputeHash() const noexcept -> std::string { hasher.Update(el.second->ToHash()); } } - auto digest = std::move(hasher).Finalize(); - if (not digest) { - Logger::Log(LogLevel::Error, "Failed to finalize hash."); - std::terminate(); - } - hash = digest->Bytes(); + hash = std::move(hasher).Finalize().Bytes(); } return hash; } diff --git a/src/buildtool/build_engine/target_map/utils.cpp b/src/buildtool/build_engine/target_map/utils.cpp index 136727bc..9a8622e4 100644 --- a/src/buildtool/build_engine/target_map/utils.cpp +++ b/src/buildtool/build_engine/target_map/utils.cpp @@ -169,12 +169,7 @@ auto hash_vector(std::vector<std::string> const& vec) -> std::string { for (auto const& s : vec) { hasher.Update(HashFunction::ComputeHash(s).Bytes()); } - auto digest = std::move(hasher).Finalize(); - if (not digest) { - Logger::Log(LogLevel::Error, "Failed to finalize hash."); - std::terminate(); - } - return digest->Bytes(); + return std::move(hasher).Finalize().Bytes(); } } // namespace @@ -196,12 +191,7 @@ auto BuildMaps::Target::Utils::createAction( hasher.Update(no_cache ? std::string{"N"} : std::string{"Y"}); hasher.Update(inputs_exp->ToHash()); - auto digest = std::move(hasher).Finalize(); - if (not digest) { - Logger::Log(LogLevel::Error, "Failed to finalize hash."); - std::terminate(); - } - auto action_id = digest->HexString(); + auto action_id = std::move(hasher).Finalize().HexString(); std::map<std::string, std::string> env_vars{}; for (auto const& [env_var, env_value] : env->Map()) { diff --git a/src/buildtool/crypto/TARGETS b/src/buildtool/crypto/TARGETS index c48bf596..5f72452a 100644 --- a/src/buildtool/crypto/TARGETS +++ b/src/buildtool/crypto/TARGETS @@ -1,38 +1,20 @@ -{ "hash_impl": +{ "hasher": { "type": ["@", "rules", "CC", "library"] - , "name": ["hash_impl"] - , "hdrs": - [ "hash_impl.hpp" - , "hash_impl_md5.hpp" - , "hash_impl_sha1.hpp" - , "hash_impl_sha256.hpp" - , "hash_impl_git.hpp" - ] - , "srcs": - [ "hash_impl_md5.cpp" - , "hash_impl_sha1.cpp" - , "hash_impl_sha256.cpp" - , "hash_impl_git.cpp" - ] + , "name": ["hasher"] + , "hdrs": ["hasher.hpp", "hash_impl_sha1.hpp", "hash_impl_sha256.hpp"] + , "srcs": ["hasher.cpp", "hash_impl_sha1.cpp", "hash_impl_sha256.cpp"] + , "stage": ["src", "buildtool", "crypto"] , "deps": [ ["src/buildtool/logging", "logging"] , ["src/utils/cpp", "hex_string"] , ["@", "ssl", "", "crypto"] ] - , "stage": ["src", "buildtool", "crypto"] - } -, "hash_generator": - { "type": ["@", "rules", "CC", "library"] - , "name": ["hash_generator"] - , "hdrs": ["hash_generator.hpp"] - , "deps": ["hash_impl"] - , "stage": ["src", "buildtool", "crypto"] } , "hash_function": { "type": ["@", "rules", "CC", "library"] , "name": ["hash_function"] , "hdrs": ["hash_function.hpp"] - , "deps": ["hash_generator"] + , "deps": ["hasher"] , "stage": ["src", "buildtool", "crypto"] } } diff --git a/src/buildtool/crypto/hash_function.hpp b/src/buildtool/crypto/hash_function.hpp index 4030c7a7..734a096d 100644 --- a/src/buildtool/crypto/hash_function.hpp +++ b/src/buildtool/crypto/hash_function.hpp @@ -6,7 +6,7 @@ #include <optional> #include <string> -#include "src/buildtool/crypto/hash_generator.hpp" +#include "src/buildtool/crypto/hasher.hpp" /// \brief Hash function used for the entire buildtool. class HashFunction { @@ -23,13 +23,13 @@ class HashFunction { /// \brief Compute a plain hash. [[nodiscard]] static auto ComputeHash(std::string const& data) noexcept - -> HashGenerator::HashDigest { + -> Hasher::HashDigest { return ComputeTaggedHash(data); } /// \brief Compute a blob hash. [[nodiscard]] static auto ComputeBlobHash(std::string const& data) noexcept - -> HashGenerator::HashDigest { + -> Hasher::HashDigest { static auto const kBlobTagCreator = [](std::string const& data) -> std::string { return {"blob " + std::to_string(data.size()) + '\0'}; @@ -39,7 +39,7 @@ class HashFunction { /// \brief Compute a tree hash. [[nodiscard]] static auto ComputeTreeHash(std::string const& data) noexcept - -> HashGenerator::HashDigest { + -> Hasher::HashDigest { static auto const kTreeTagCreator = [](std::string const& data) -> std::string { return {"tree " + std::to_string(data.size()) + '\0'}; @@ -48,14 +48,12 @@ class HashFunction { } /// \brief Obtain incremental hasher for computing plain hashes. - [[nodiscard]] static auto Hasher() noexcept -> HashGenerator::Hasher { + [[nodiscard]] static auto Hasher() noexcept -> ::Hasher { switch (HashType()) { case JustHash::Native: - return HashGenerator{HashGenerator::HashType::SHA1} - .IncrementalHasher(); + return ::Hasher{Hasher::HashType::SHA1}; case JustHash::Compatible: - return HashGenerator{HashGenerator::HashType::SHA256} - .IncrementalHasher(); + return ::Hasher{Hasher::HashType::SHA256}; } } @@ -74,13 +72,13 @@ class HashFunction { [[nodiscard]] static auto ComputeTaggedHash( std::string const& data, std::function<std::string(std::string const&)> const& tag_creator = - {}) noexcept -> HashGenerator::HashDigest { + {}) noexcept -> Hasher::HashDigest { auto hasher = Hasher(); if (tag_creator and HashType() == JustHash::Native) { hasher.Update(tag_creator(data)); } hasher.Update(data); - return *std::move(hasher).Finalize(); + return std::move(hasher).Finalize(); } }; diff --git a/src/buildtool/crypto/hash_generator.hpp b/src/buildtool/crypto/hash_generator.hpp deleted file mode 100644 index d8b59631..00000000 --- a/src/buildtool/crypto/hash_generator.hpp +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_GENERATOR_HPP -#define INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_GENERATOR_HPP - -#include <iomanip> -#include <memory> -#include <optional> -#include <sstream> -#include <string> -#include <vector> - -#include "src/buildtool/crypto/hash_impl_git.hpp" -#include "src/buildtool/crypto/hash_impl_md5.hpp" -#include "src/buildtool/crypto/hash_impl_sha1.hpp" -#include "src/buildtool/crypto/hash_impl_sha256.hpp" -#include "src/utils/cpp/hex_string.hpp" - -/// \brief Hash generator, supports multiple types \ref HashType. -class HashGenerator { - public: - /// \brief Types of hash implementations supported by generator. - enum class HashType { MD5, SHA1, SHA256, GIT }; - - /// \brief The universal hash digest. - /// The type of hash and the digest length depends on the hash - /// implementation used to generated this digest. - class HashDigest { - friend HashGenerator; - - public: - /// \brief Get pointer to raw bytes of digest. - /// Length can be obtained using \ref Length. - [[nodiscard]] auto Bytes() const& -> std::string const& { - return bytes_; - } - - [[nodiscard]] auto Bytes() && -> std::string { - return std::move(bytes_); - } - - /// \brief Get hexadecimal string of digest. - /// Length is twice the length of raw bytes (\ref Length). - [[nodiscard]] auto HexString() const -> std::string { - return ToHexString(bytes_); - } - - /// \brief Get digest length in raw bytes. - [[nodiscard]] auto Length() const -> std::size_t { - return bytes_.size(); - } - - private: - std::string bytes_{}; - - explicit HashDigest(std::string bytes) : bytes_{std::move(bytes)} {} - }; - - /// \brief Incremental hasher. - class Hasher { - friend HashGenerator; - - public: - /// \brief Feed data to the hasher. - auto Update(std::string const& data) noexcept -> bool { - return impl_->Update(data); - } - - /// \brief Finalize hash. - [[nodiscard]] auto Finalize() && noexcept -> std::optional<HashDigest> { - auto hash = std::move(*impl_).Finalize(); - if (hash) { - return HashDigest{*hash}; - } - return std::nullopt; - } - - private: - std::unique_ptr<IHashImpl> impl_; - - explicit Hasher(std::unique_ptr<IHashImpl> impl) - : impl_{std::move(impl)} {} - }; - - /// \brief Create hash generator for specific type. - explicit HashGenerator(HashType type) - : type_{type}, digest_length_{create_impl()->DigestLength()} {} - HashGenerator(HashGenerator const&) = delete; - HashGenerator(HashGenerator&&) = delete; - auto operator=(HashGenerator const&) -> HashGenerator& = delete; - auto operator=(HashGenerator&&) -> HashGenerator& = delete; - ~HashGenerator() noexcept = default; - - /// \brief Run hash function on data. - [[nodiscard]] auto Run(std::string const& data) const noexcept - -> HashDigest { - auto impl = create_impl(); - return HashDigest{std::move(*impl).Compute(data)}; - } - - [[nodiscard]] auto IncrementalHasher() const noexcept -> Hasher { - return Hasher(create_impl()); - } - - [[nodiscard]] auto DigestLength() const noexcept -> std::size_t { - return digest_length_; - } - - private: - HashType type_{}; - std::size_t digest_length_{}; - - /// \brief Dispatch for creating the actual implementation - [[nodiscard]] auto create_impl() const noexcept - -> std::unique_ptr<IHashImpl> { - switch (type_) { - case HashType::MD5: - return CreateHashImplMd5(); - case HashType::SHA1: - return CreateHashImplSha1(); - case HashType::SHA256: - return CreateHashImplSha256(); - case HashType::GIT: - return CreateHashImplGit(); - } - } -}; - -#endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_GENERATOR_HPP diff --git a/src/buildtool/crypto/hash_impl.hpp b/src/buildtool/crypto/hash_impl.hpp deleted file mode 100644 index d37322bd..00000000 --- a/src/buildtool/crypto/hash_impl.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_HPP -#define INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_HPP - -#include <optional> -#include <string> - -#include "src/buildtool/logging/logger.hpp" - -/// \brief Interface for hash implementations -class IHashImpl { - public: - IHashImpl() noexcept = default; - IHashImpl(IHashImpl const&) = default; - IHashImpl(IHashImpl&&) = default; - auto operator=(IHashImpl const&) -> IHashImpl& = default; - auto operator=(IHashImpl&&) -> IHashImpl& = default; - virtual ~IHashImpl() = default; - - /// \brief Feed data to the incremental hashing. - [[nodiscard]] virtual auto Update(std::string const& data) noexcept - -> bool = 0; - - /// \brief Finalize the hashing and return hash as string of raw bytes. - [[nodiscard]] virtual auto Finalize() && noexcept - -> std::optional<std::string> = 0; - - /// \brief Compute the hash of data and return it as string of raw bytes. - [[nodiscard]] virtual auto Compute(std::string const& data) && noexcept - -> std::string = 0; - - /// \brief Get length of the hash in raw bytes. - [[nodiscard]] virtual auto DigestLength() const noexcept -> std::size_t = 0; - - static auto FatalError() noexcept -> void { - Logger::Log(LogLevel::Error, "Failed to compute hash."); - std::terminate(); - } -}; - -#endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_HPP diff --git a/src/buildtool/crypto/hash_impl_git.cpp b/src/buildtool/crypto/hash_impl_git.cpp deleted file mode 100644 index 9cb2a761..00000000 --- a/src/buildtool/crypto/hash_impl_git.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include <array> -#include <cstdint> - -#include "openssl/sha.h" -#include "src/buildtool/crypto/hash_impl.hpp" - -/// \brief Hash implementation for Git blob ids. -/// Does not support incremental hashing. -class HashImplGit final : public IHashImpl { - public: - auto Update(std::string const& /*data*/) noexcept -> bool final { - return false; - } - - auto Finalize() && noexcept -> std::optional<std::string> final { - return std::nullopt; - } - - auto Compute(std::string const& data) && noexcept -> std::string final { - SHA_CTX ctx; - std::string const header{"blob " + std::to_string(data.size()) + '\0'}; - if (SHA1_Init(&ctx) == 1 && - SHA1_Update(&ctx, header.data(), header.size()) == 1 && - SHA1_Update(&ctx, data.data(), data.size()) == 1) { - auto out = std::array<std::uint8_t, SHA_DIGEST_LENGTH>{}; - if (SHA1_Final(out.data(), &ctx) == 1) { - return std::string{out.begin(), out.end()}; - } - } - FatalError(); - return {}; - } - - [[nodiscard]] auto DigestLength() const noexcept -> std::size_t final { - return SHA_DIGEST_LENGTH; - } -}; - -/// \brief Factory for Git implementation -auto CreateHashImplGit() -> std::unique_ptr<IHashImpl> { - return std::make_unique<HashImplGit>(); -} diff --git a/src/buildtool/crypto/hash_impl_git.hpp b/src/buildtool/crypto/hash_impl_git.hpp deleted file mode 100644 index be0738da..00000000 --- a/src/buildtool/crypto/hash_impl_git.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_GIT_HPP -#define INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_GIT_HPP - -#include <memory> - -#include "src/buildtool/crypto/hash_impl.hpp" - -[[nodiscard]] extern auto CreateHashImplGit() -> std::unique_ptr<IHashImpl>; - -#endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_GIT_HPP diff --git a/src/buildtool/crypto/hash_impl_md5.cpp b/src/buildtool/crypto/hash_impl_md5.cpp deleted file mode 100644 index 106dc984..00000000 --- a/src/buildtool/crypto/hash_impl_md5.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include <array> -#include <cstdint> - -#include "openssl/md5.h" -#include "src/buildtool/crypto/hash_impl.hpp" - -/// \brief Hash implementation for MD5 -class HashImplMd5 final : public IHashImpl { - public: - HashImplMd5() { initialized_ = MD5_Init(&ctx_) == 1; } - - auto Update(std::string const& data) noexcept -> bool final { - return initialized_ and - MD5_Update(&ctx_, data.data(), data.size()) == 1; - } - - auto Finalize() && noexcept -> std::optional<std::string> final { - if (initialized_) { - auto out = std::array<std::uint8_t, MD5_DIGEST_LENGTH>{}; - if (MD5_Final(out.data(), &ctx_) == 1) { - return std::string{out.begin(), out.end()}; - } - } - return std::nullopt; - } - - auto Compute(std::string const& data) && noexcept -> std::string final { - if (Update(data)) { - auto digest = std::move(*this).Finalize(); - if (digest) { - return *digest; - } - } - FatalError(); - return {}; - } - - [[nodiscard]] auto DigestLength() const noexcept -> std::size_t final { - return MD5_DIGEST_LENGTH; - } - - private: - MD5_CTX ctx_{}; - bool initialized_{}; -}; - -/// \brief Factory for MD5 implementation -auto CreateHashImplMd5() -> std::unique_ptr<IHashImpl> { - return std::make_unique<HashImplMd5>(); -} diff --git a/src/buildtool/crypto/hash_impl_md5.hpp b/src/buildtool/crypto/hash_impl_md5.hpp deleted file mode 100644 index 95411570..00000000 --- a/src/buildtool/crypto/hash_impl_md5.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_MD5_HPP -#define INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_MD5_HPP - -#include <memory> - -#include "src/buildtool/crypto/hash_impl.hpp" - -[[nodiscard]] extern auto CreateHashImplMd5() -> std::unique_ptr<IHashImpl>; - -#endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_MD5_HPP diff --git a/src/buildtool/crypto/hash_impl_sha1.cpp b/src/buildtool/crypto/hash_impl_sha1.cpp index e0bee0fb..cecad9ca 100644 --- a/src/buildtool/crypto/hash_impl_sha1.cpp +++ b/src/buildtool/crypto/hash_impl_sha1.cpp @@ -1,11 +1,12 @@ +#include "src/buildtool/crypto/hash_impl_sha1.hpp" + #include <array> #include <cstdint> #include "openssl/sha.h" -#include "src/buildtool/crypto/hash_impl.hpp" /// \brief Hash implementation for SHA-1 -class HashImplSha1 final : public IHashImpl { +class HashImplSha1 final : public Hasher::IHashImpl { public: HashImplSha1() { initialized_ = SHA1_Init(&ctx_) == 1; } @@ -35,16 +36,12 @@ class HashImplSha1 final : public IHashImpl { return {}; } - [[nodiscard]] auto DigestLength() const noexcept -> std::size_t final { - return SHA_DIGEST_LENGTH; - } - private: SHA_CTX ctx_{}; bool initialized_{}; }; /// \brief Factory for SHA-1 implementation -auto CreateHashImplSha1() -> std::unique_ptr<IHashImpl> { +auto CreateHashImplSha1() -> std::unique_ptr<Hasher::IHashImpl> { return std::make_unique<HashImplSha1>(); } diff --git a/src/buildtool/crypto/hash_impl_sha1.hpp b/src/buildtool/crypto/hash_impl_sha1.hpp index 7b8196b5..b82edd64 100644 --- a/src/buildtool/crypto/hash_impl_sha1.hpp +++ b/src/buildtool/crypto/hash_impl_sha1.hpp @@ -3,8 +3,9 @@ #include <memory> -#include "src/buildtool/crypto/hash_impl.hpp" +#include "src/buildtool/crypto/hasher.hpp" -[[nodiscard]] extern auto CreateHashImplSha1() -> std::unique_ptr<IHashImpl>; +[[nodiscard]] extern auto CreateHashImplSha1() + -> std::unique_ptr<Hasher::IHashImpl>; #endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_SHA1_HPP diff --git a/src/buildtool/crypto/hash_impl_sha256.cpp b/src/buildtool/crypto/hash_impl_sha256.cpp index bbea10d3..8fa80bbc 100644 --- a/src/buildtool/crypto/hash_impl_sha256.cpp +++ b/src/buildtool/crypto/hash_impl_sha256.cpp @@ -1,11 +1,12 @@ +#include "src/buildtool/crypto/hash_impl_sha256.hpp" + #include <array> #include <cstdint> #include "openssl/sha.h" -#include "src/buildtool/crypto/hash_impl.hpp" /// \brief Hash implementation for SHA-256 -class HashImplSha256 final : public IHashImpl { +class HashImplSha256 final : public Hasher::IHashImpl { public: HashImplSha256() { initialized_ = SHA256_Init(&ctx_) == 1; } @@ -35,16 +36,12 @@ class HashImplSha256 final : public IHashImpl { return {}; } - [[nodiscard]] auto DigestLength() const noexcept -> std::size_t final { - return SHA256_DIGEST_LENGTH; - } - private: SHA256_CTX ctx_{}; bool initialized_{}; }; /// \brief Factory for SHA-256 implementation -auto CreateHashImplSha256() -> std::unique_ptr<IHashImpl> { +auto CreateHashImplSha256() -> std::unique_ptr<Hasher::IHashImpl> { return std::make_unique<HashImplSha256>(); } diff --git a/src/buildtool/crypto/hash_impl_sha256.hpp b/src/buildtool/crypto/hash_impl_sha256.hpp index d74c1492..106d8a0b 100644 --- a/src/buildtool/crypto/hash_impl_sha256.hpp +++ b/src/buildtool/crypto/hash_impl_sha256.hpp @@ -3,8 +3,9 @@ #include <memory> -#include "src/buildtool/crypto/hash_impl.hpp" +#include "src/buildtool/crypto/hasher.hpp" -[[nodiscard]] extern auto CreateHashImplSha256() -> std::unique_ptr<IHashImpl>; +[[nodiscard]] extern auto CreateHashImplSha256() + -> std::unique_ptr<Hasher::IHashImpl>; #endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_IMPL_SHA256_HPP diff --git a/src/buildtool/crypto/hasher.cpp b/src/buildtool/crypto/hasher.cpp new file mode 100644 index 00000000..6f432679 --- /dev/null +++ b/src/buildtool/crypto/hasher.cpp @@ -0,0 +1,14 @@ +#include "src/buildtool/crypto/hasher.hpp" + +#include "src/buildtool/crypto/hash_impl_sha1.hpp" +#include "src/buildtool/crypto/hash_impl_sha256.hpp" + +auto Hasher::CreateHashImpl(HashType type) noexcept + -> std::unique_ptr<IHashImpl> { + switch (type) { + case HashType::SHA1: + return CreateHashImplSha1(); + case HashType::SHA256: + return CreateHashImplSha256(); + } +} diff --git a/src/buildtool/crypto/hasher.hpp b/src/buildtool/crypto/hasher.hpp new file mode 100644 index 00000000..0efe300f --- /dev/null +++ b/src/buildtool/crypto/hasher.hpp @@ -0,0 +1,104 @@ +#ifndef INCLUDED_SRC_BUILDTOOL_CRYPTO_HASHER_HPP +#define INCLUDED_SRC_BUILDTOOL_CRYPTO_HASHER_HPP + +#include <cstdint> +#include <memory> +#include <optional> +#include <string> + +#include "src/buildtool/logging/logger.hpp" +#include "src/utils/cpp/hex_string.hpp" + +/// \brief Incremental hasher. +class Hasher { + public: + /// \brief Types of hash implementations supported by generator. + enum class HashType : std::uint8_t { SHA1, SHA256 }; + + /// \brief The universal hash digest. + /// The type of hash and the digest length depends on the hash + /// implementation used to generated this digest. + class HashDigest { + friend Hasher; + + public: + /// \brief Get pointer to raw bytes of digest. + /// Length can be obtained using \ref Length. + [[nodiscard]] auto Bytes() const& -> std::string const& { + return bytes_; + } + + [[nodiscard]] auto Bytes() && -> std::string { + return std::move(bytes_); + } + + /// \brief Get hexadecimal string of digest. + /// Length is twice the length of raw bytes (\ref Length). + [[nodiscard]] auto HexString() const -> std::string { + return ToHexString(bytes_); + } + + /// \brief Get digest length in raw bytes. + [[nodiscard]] auto Length() const -> std::size_t { + return bytes_.size(); + } + + private: + std::string bytes_{}; + + explicit HashDigest(std::string bytes) : bytes_{std::move(bytes)} {} + }; + + /// \brief Interface for hash implementations + class IHashImpl { + public: + IHashImpl() noexcept = default; + IHashImpl(IHashImpl const&) = delete; + IHashImpl(IHashImpl&&) = default; + auto operator=(IHashImpl const&) -> IHashImpl& = delete; + auto operator=(IHashImpl&&) -> IHashImpl& = default; + virtual ~IHashImpl() = default; + + /// \brief Feed data to the incremental hashing. + [[nodiscard]] virtual auto Update(std::string const& data) noexcept + -> bool = 0; + + /// \brief Finalize the hashing and return hash as string of raw bytes. + [[nodiscard]] virtual auto Finalize() && noexcept + -> std::optional<std::string> = 0; + + /// \brief Compute the hash of data and return it as string of raw + /// bytes. + [[nodiscard]] virtual auto Compute(std::string const& data) && noexcept + -> std::string = 0; + + static auto FatalError() noexcept -> void { + Logger::Log(LogLevel::Error, "Failed to compute hash."); + std::terminate(); + } + }; + + explicit Hasher(HashType type) : impl_{CreateHashImpl(type)} {} + + /// \brief Feed data to the hasher. + auto Update(std::string const& data) noexcept -> bool { + return impl_->Update(data); + } + + /// \brief Finalize hash. + [[nodiscard]] auto Finalize() && noexcept -> HashDigest { + if (auto hash = std::move(*impl_).Finalize()) { + return HashDigest{std::move(*hash)}; + } + IHashImpl::FatalError(); + return HashDigest{{}}; + } + + private: + std::unique_ptr<IHashImpl> impl_; + + [[nodiscard]] static auto CreateHashImpl(HashType type) noexcept + -> std::unique_ptr<IHashImpl>; +}; + +#endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASHER_HPP |