blob: 4e7b92066b9ea9f29a6256d6c1c7b250f272a6a1 [file]
// 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