summaryrefslogtreecommitdiff
path: root/chromium/components/password_manager/core/browser/password_hash_data.cc
diff options
context:
space:
mode:
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.cc128
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