// Copyright 2021 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 "chromecast/base/hash_util.h" #include #include #include "base/check_op.h" #include "base/hash/sha1.h" #include "base/logging.h" #include "base/notreached.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "chromecast/base/legacy_app_id_mapper.h" #include "chromecast/base/version.h" namespace chromecast { namespace { const size_t kAppIdV2StrLen = 8; } // namespace uint64_t HashToUInt64(const std::string& value) { uint64_t output; const std::string sha1hash = base::SHA1HashString(value); DCHECK_GE(sha1hash.size(), sizeof(output)); memcpy(&output, sha1hash.data(), sizeof(output)); return output; } uint32_t HashToUInt32(const std::string& value) { uint32_t output; const std::string sha1hash = base::SHA1HashString(value); DCHECK_GE(sha1hash.size(), sizeof(output)); memcpy(&output, sha1hash.data(), sizeof(output)); return output; } uint64_t HashGUID64(const std::string& guid) { std::string hex; base::RemoveChars(guid, "-", &hex); uint64_t output; DCHECK_EQ(hex.size(), 32u); if (base::HexStringToUInt64(hex.substr(0, 16), &output)) return output; NOTREACHED(); return 0; } uint32_t HashAppId32(const std::string& app_id) { uint32_t output; if (app_id.size() == kAppIdV2StrLen && base::HexStringToUInt(app_id, &output)) { return output; } return MapLegacyAppId(app_id); } uint64_t HashCastBuildNumber64(const std::string& build_number) { uint64_t return_value = 0; std::vector tokens(base::SplitString( build_number, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)); const size_t tsize = tokens.size(); if (tsize < 1 || tsize > 4) return static_cast(-1); int bits = 64 / tsize; // special case for 3-tuple to make hex look nicer. if (tsize == 3) bits = 16; for (size_t i = 0; i < tsize; ++i) { // special case for the last token of 3-tuple. if (tsize == 3 && i == 2) bits = 32; return_value <<= bits; unsigned value = 0; if (!base::StringToUint(tokens[i], &value)) return static_cast(-1); if (bits != 64) // avoid overflow value &= (static_cast(1) << bits) - 1; return_value |= value; } return return_value; } uint64_t HashSessionId64(const std::string& session_id) { return HashGUID64(session_id); } uint64_t HashSdkVersion64(const std::string& sdk_version) { if (sdk_version.empty()) return 0; // Sdk version is usually in "X.Y.Z(.minor)" format. // Following code is a little bit relaxed to accept all sub-fields optional. uint64_t return_value = 0; std::vector tokens(base::SplitString( sdk_version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)); for (size_t i = 0; i < 4; ++i) { return_value <<= 16; if (tokens.size() > i) { unsigned value = 0; if (base::StringToUint(tokens[i], &value)) { return_value |= value & 0xFFFF; } else { LOG_IF(ERROR, !CAST_IS_DEBUG_BUILD()) << "Sdk version " << sdk_version << " is not in correct format."; return static_cast(-1); } } } return return_value; } uint32_t HashSocketId32(const std::string& socket_id) { uint32_t output; // socket id is usually just numerical. if (base::StringToUint(socket_id, &output)) { return output; } else { // CastControlSocket and unittests. return HashToUInt32(socket_id); } } uint32_t HashConnectionId32(const std::string& connection_id) { return HashToUInt32(connection_id); } uint64_t HashAndroidBuildNumber64(const std::string& build_id) { if (build_id.length() == 0) { return static_cast(-1); } uint64_t value = 0; for (const char& c : build_id.substr(0, sizeof(value) / sizeof(char))) { value <<= CHAR_BIT; value += c; } return value; } } // namespace chromecast