| // Copyright 2026 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // | |
| #include "crypto/default/hasher.h" | |
| #include <memory> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/base/no_destructor.h" | |
| #include "absl/base/nullability.h" | |
| #include "absl/log/absl_log.h" | |
| #include "absl/log/log.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_macros.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/escaping.h" | |
| #include "absl/strings/str_cat.h" | |
| #include "absl/strings/string_view.h" | |
| #include "crypto/algorithms.h" | |
| #include "crypto/hash.h" | |
| #include "openssl/base.h" | |
| #include "openssl/digest.h" | |
| namespace credentio { | |
| namespace { | |
| class DefaultHashChecker : public HashChecker { | |
| public: | |
| explicit DefaultHashChecker(std::unique_ptr<Hasher> hasher) | |
| : hasher_(std::move(hasher)) {} | |
| void Update(absl::string_view content) override { hasher_->Update(content); } | |
| bool Check(absl::string_view expected_hash) override { | |
| std::string computed_hash = hasher_->Digest(); | |
| if (computed_hash != expected_hash) { | |
| ABSL_DVLOG(1) << "Hash mismatch: base64(computed) = " | |
| << absl::Base64Escape(computed_hash) | |
| << " base64(expected) = " | |
| << absl::Base64Escape(expected_hash); | |
| return false; | |
| } | |
| return true; | |
| } | |
| private: | |
| std::unique_ptr<Hasher> hasher_; | |
| }; | |
| class DefaultHashCheckerFactoryImpl : public HashCheckerFactory { | |
| public: | |
| DefaultHashCheckerFactoryImpl() = default; | |
| absl::StatusOr<std::unique_ptr<HashChecker>> Create( | |
| HashAlgorithm algorithm) const override { | |
| ABSL_ASSIGN_OR_RETURN(auto hasher, CreateHasher(algorithm)); | |
| return std::make_unique<DefaultHashChecker>(std::move(hasher)); | |
| } | |
| }; | |
| class DefaultHasher : public Hasher { | |
| public: | |
| static absl::StatusOr<std::unique_ptr<DefaultHasher>> Create( | |
| const EVP_MD* md) { | |
| bssl::UniquePtr<EVP_MD_CTX> ctx(EVP_MD_CTX_new()); | |
| if (ctx == nullptr || EVP_DigestInit_ex(ctx.get(), md, nullptr) != 1) { | |
| return absl::InternalError("Failed to initialize hasher"); | |
| } | |
| return std::unique_ptr<DefaultHasher>(new DefaultHasher(std::move(ctx))); | |
| } | |
| void Update(absl::string_view content) override { | |
| // We don't check the return value because BoringSSL's implementation always | |
| // returns 1. | |
| EVP_DigestUpdate(ctx_.get(), content.data(), content.size()); | |
| } | |
| std::string Digest() override { | |
| unsigned int len = 0; | |
| unsigned char digest[EVP_MAX_MD_SIZE]; | |
| // We don't check the return value because BoringSSL's implementation always | |
| // returns 1. | |
| EVP_DigestFinal_ex(ctx_.get(), digest, &len); | |
| return std::string(reinterpret_cast<char*>(digest), len); | |
| } | |
| private: | |
| explicit DefaultHasher(bssl::UniquePtr<EVP_MD_CTX> ctx) | |
| : ctx_(std::move(ctx)) {} | |
| bssl::UniquePtr<EVP_MD_CTX> ctx_; | |
| }; | |
| } // namespace | |
| absl::StatusOr<std::unique_ptr<Hasher> absl_nonnull> CreateHasher( | |
| HashAlgorithm algorithm) { | |
| switch (algorithm) { | |
| case HashAlgorithm::kSha256: | |
| return DefaultHasher::Create(EVP_sha256()); | |
| case HashAlgorithm::kSha384: | |
| return DefaultHasher::Create(EVP_sha384()); | |
| case HashAlgorithm::kSha512: | |
| return DefaultHasher::Create(EVP_sha512()); | |
| } | |
| std::string error_msg = absl::StrCat( | |
| "fell through end of exhaustive switch statement with HashAlgorithm " | |
| "value: ", | |
| static_cast<int>(algorithm)); | |
| ABSL_LOG(DFATAL) << error_msg; | |
| return absl::FailedPreconditionError(error_msg); | |
| } | |
| absl::StatusOr<std::unique_ptr<Hasher> absl_nonnull> CreateHasher( | |
| absl::string_view algorithm) { | |
| ABSL_ASSIGN_OR_RETURN(auto ha, ParseHashAlgorithm(algorithm)); | |
| return CreateHasher(ha); | |
| } | |
| const HashCheckerFactory& DefaultHashCheckerFactory() { | |
| static const absl::NoDestructor<DefaultHashCheckerFactoryImpl> singleton; | |
| return *singleton; | |
| } | |
| const HasherFactory& DefaultHasherFactory() { | |
| static const absl::NoDestructor<Sha256HasherFactory> singleton; | |
| return *singleton; | |
| } | |
| absl::StatusOr<std::unique_ptr<Hasher>> Sha256HasherFactory::Create() const { | |
| return DefaultHasher::Create(EVP_sha256()); | |
| } | |
| absl::StatusOr<std::unique_ptr<Hasher>> Sha384HasherFactory::Create() const { | |
| return DefaultHasher::Create(EVP_sha384()); | |
| } | |
| absl::StatusOr<std::unique_ptr<Hasher>> Sha512HasherFactory::Create() const { | |
| return DefaultHasher::Create(EVP_sha512()); | |
| } | |
| } // namespace credentio |