diff options
Diffstat (limited to 'chromium/components/password_manager/core/browser/password_hash_data.cc')
-rw-r--r-- | chromium/components/password_manager/core/browser/password_hash_data.cc | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/chromium/components/password_manager/core/browser/password_hash_data.cc b/chromium/components/password_manager/core/browser/password_hash_data.cc new file mode 100644 index 00000000000..ef7b2f9069e --- /dev/null +++ b/chromium/components/password_manager/core/browser/password_hash_data.cc @@ -0,0 +1,128 @@ +// Copyright 2018 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 "components/password_manager/core/browser/password_hash_data.h" + +#include "base/strings/string_piece.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "crypto/openssl_util.h" +#include "crypto/random.h" +#include "google_apis/gaia/gaia_auth_util.h" +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace password_manager { + +namespace { + +std::string CreateRandomSalt() { + constexpr size_t kSyncPasswordSaltLength = 16; + + char buffer[kSyncPasswordSaltLength]; + crypto::RandBytes(buffer, kSyncPasswordSaltLength); + // Explicit std::string constructor with a string length must be used in order + // to avoid treating '\0' symbols as a string ends. + std::string result(buffer, kSyncPasswordSaltLength); + return result; +} + +} // namespace + +PasswordHashData::PasswordHashData() = default; + +PasswordHashData::PasswordHashData(const PasswordHashData& other) = default; + +PasswordHashData::PasswordHashData(const std::string& username, + const base::string16& password, + bool force_update, + bool is_gaia_password) + : username(username), + length(password.size()), + salt(CreateRandomSalt()), + hash(CalculatePasswordHash(password, salt)), + force_update(force_update), + is_gaia_password(is_gaia_password) {} + +bool PasswordHashData::MatchesPassword(const std::string& username, + const base::string16& password, + bool is_gaia_password) const { + if (password.size() != this->length || + !AreUsernamesSame(username, is_gaia_password, this->username, + this->is_gaia_password)) { + return false; + } + + return CalculatePasswordHash(password, this->salt) == this->hash; +} + +SyncPasswordData::SyncPasswordData(const base::string16& password, + bool force_update) + : length(password.size()), + salt(CreateRandomSalt()), + hash(CalculatePasswordHash(password, salt)), + force_update(force_update) {} + +bool SyncPasswordData::MatchesPassword(const base::string16& password) const { + if (password.size() != this->length) + return false; + return CalculatePasswordHash(password, this->salt) == this->hash; +} + +uint64_t CalculatePasswordHash(const base::StringPiece16& text, + const std::string& salt) { + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); + constexpr size_t kBytesFromHash = 8; + constexpr uint64_t kScryptCost = 32; // It must be a power of 2. + constexpr uint64_t kScryptBlockSize = 8; + constexpr uint64_t kScryptParallelization = 1; + constexpr size_t kScryptMaxMemory = 1024 * 1024; + + uint8_t hash[kBytesFromHash]; + base::StringPiece text_8bits(reinterpret_cast<const char*>(text.data()), + text.size() * 2); + const uint8_t* salt_ptr = reinterpret_cast<const uint8_t*>(salt.c_str()); + + int scrypt_ok = EVP_PBE_scrypt(text_8bits.data(), text_8bits.size(), salt_ptr, + salt.size(), kScryptCost, kScryptBlockSize, + kScryptParallelization, kScryptMaxMemory, hash, + kBytesFromHash); + + // EVP_PBE_scrypt can only fail due to memory allocation error (which aborts + // Chromium) or invalid parameters. In case of a failure a hash could leak + // information from the stack, so using CHECK is better than DCHECK. + CHECK(scrypt_ok); + + // Take 37 bits of |hash|. + uint64_t hash37 = ((static_cast<uint64_t>(hash[0]))) | + ((static_cast<uint64_t>(hash[1])) << 8) | + ((static_cast<uint64_t>(hash[2])) << 16) | + ((static_cast<uint64_t>(hash[3])) << 24) | + (((static_cast<uint64_t>(hash[4])) & 0x1F) << 32); + + return hash37; +} + +std::string CanonicalizeUsername(const std::string& username, + bool is_gaia_account) { + std::vector<std::string> parts = base::SplitString( + username, "@", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + if (parts.size() != 2U) { + if (is_gaia_account && parts.size() == 1U) + return gaia::CanonicalizeEmail(username + "@gmail.com"); + return username; + } + return gaia::CanonicalizeEmail(username); +} + +bool AreUsernamesSame(const std::string& username1, + bool is_username1_gaia_account, + const std::string& username2, + bool is_username2_gaia_account) { + if (is_username1_gaia_account != is_username2_gaia_account) + return false; + return CanonicalizeUsername(username1, is_username1_gaia_account) == + CanonicalizeUsername(username2, is_username2_gaia_account); +} + +} // namespace password_manager |