// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/base/hash_value.h" #include #include #include "base/base64.h" #include "base/logging.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "crypto/sha2.h" namespace net { namespace { // LessThan comparator for use with std::binary_search() in determining // whether a SHA-256 HashValue appears within a sorted array of // SHA256HashValues. struct SHA256ToHashValueComparator { bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const { DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag()); return memcmp(lhs.data, rhs.data(), rhs.size()) < 0; } bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const { DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag()); return memcmp(lhs.data(), rhs.data, lhs.size()) < 0; } }; } // namespace HashValue::HashValue(const SHA256HashValue& hash) : HashValue(HASH_VALUE_SHA256) { fingerprint.sha256 = hash; } bool HashValue::FromString(const base::StringPiece value) { base::StringPiece base64_str; if (value.starts_with("sha256/")) { tag_ = HASH_VALUE_SHA256; base64_str = value.substr(7); } else { return false; } std::string decoded; if (!base::Base64Decode(base64_str, &decoded) || decoded.size() != size()) return false; memcpy(data(), decoded.data(), size()); return true; } std::string HashValue::ToString() const { std::string base64_str; base::Base64Encode(base::StringPiece(reinterpret_cast(data()), size()), &base64_str); switch (tag_) { case HASH_VALUE_SHA256: return std::string("sha256/") + base64_str; } NOTREACHED() << "Unknown HashValueTag " << tag_; return std::string("unknown/" + base64_str); } size_t HashValue::size() const { switch (tag_) { case HASH_VALUE_SHA256: return sizeof(fingerprint.sha256.data); } NOTREACHED() << "Unknown HashValueTag " << tag_; // While an invalid tag should not happen, return a non-zero length // to avoid compiler warnings when the result of size() is // used with functions like memset. return sizeof(fingerprint.sha256.data); } unsigned char* HashValue::data() { return const_cast(const_cast(this)->data()); } const unsigned char* HashValue::data() const { switch (tag_) { case HASH_VALUE_SHA256: return fingerprint.sha256.data; } NOTREACHED() << "Unknown HashValueTag " << tag_; return nullptr; } bool operator==(const HashValue& lhs, const HashValue& rhs) { if (lhs.tag_ != rhs.tag_) return false; switch (lhs.tag_) { case HASH_VALUE_SHA256: return lhs.fingerprint.sha256 == rhs.fingerprint.sha256; } NOTREACHED(); return false; } bool operator!=(const HashValue& lhs, const HashValue& rhs) { return !(lhs == rhs); } bool operator<(const HashValue& lhs, const HashValue& rhs) { if (lhs.tag_ != rhs.tag_) return lhs.tag_ < rhs.tag_; switch (lhs.tag_) { case HASH_VALUE_SHA256: return lhs.fingerprint.sha256 < rhs.fingerprint.sha256; } NOTREACHED(); return false; } bool operator>(const HashValue& lhs, const HashValue& rhs) { return rhs < lhs; } bool operator<=(const HashValue& lhs, const HashValue& rhs) { return !(lhs > rhs); } bool operator>=(const HashValue& lhs, const HashValue& rhs) { return !(lhs < rhs); } bool IsSHA256HashInSortedArray(const HashValue& hash, base::span array) { return std::binary_search(array.begin(), array.end(), hash, SHA256ToHashValueComparator()); } bool IsAnySHA256HashInSortedArray(base::span hashes, base::span array) { for (const auto& hash : hashes) { if (hash.tag() != HASH_VALUE_SHA256) continue; if (IsSHA256HashInSortedArray(hash, array)) return true; } return false; } } // namespace net