Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix password import failure on windows (uplift to 1.8) #5380

Merged
merged 1 commit into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 85 additions & 2 deletions utility/importer/chrome_importer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,78 @@
#include "ui/base/l10n/l10n_util.h"
#endif // defined(OS_LINUX)

#if defined(OS_WIN)
#include "base/base64.h"
#include "base/win/wincrypt_shim.h"
#endif

using base::Time;

namespace {

// Most of below code is copied from os_crypt_win.cc
#if defined(OS_WIN)
// Contains base64 random key encrypted with DPAPI.
const char kOsCryptEncryptedKeyPrefName[] = "os_crypt.encrypted_key";

// Key prefix for a key encrypted with DPAPI.
const char kDPAPIKeyPrefix[] = "DPAPI";

bool DecryptStringWithDPAPI(const std::string& ciphertext,
std::string* plaintext) {
DATA_BLOB input;
input.pbData =
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(ciphertext.data()));
input.cbData = static_cast<DWORD>(ciphertext.length());

DATA_BLOB output;
BOOL result = CryptUnprotectData(&input, nullptr, nullptr, nullptr, nullptr,
0, &output);
if (!result) {
PLOG(ERROR) << "Failed to decrypt";
return false;
}

plaintext->assign(reinterpret_cast<char*>(output.pbData), output.cbData);
LocalFree(output.pbData);
return true;
}

// Return false if encryption key setting is failed.
// Fetch chrome's raw encryption key and use it to get chrome's password data.
bool SetEncryptionKeyForPasswordImporting(
const base::FilePath& local_state_path) {
std::string local_state_content;
base::ReadFileToString(local_state_path, &local_state_content);
base::Optional<base::Value> local_state =
base::JSONReader::Read(local_state_content);
if (auto* base64_encrypted_key =
local_state->FindStringPath(kOsCryptEncryptedKeyPrefName)) {
std::string encrypted_key_with_header;

base::Base64Decode(*base64_encrypted_key, &encrypted_key_with_header);

if (!base::StartsWith(encrypted_key_with_header, kDPAPIKeyPrefix,
base::CompareCase::SENSITIVE)) {
return false;
}
std::string encrypted_key =
encrypted_key_with_header.substr(sizeof(kDPAPIKeyPrefix) - 1);
std::string key;
// This DPAPI decryption can fail if the user's password has been reset
// by an Administrator.
if (DecryptStringWithDPAPI(encrypted_key, &key)) {
OSCrypt::SetRawEncryptionKey(key);
return true;
}
}

return false;
}
#endif

} // namespace

ChromeImporter::ChromeImporter() {
}

Expand Down Expand Up @@ -69,7 +139,7 @@ void ChromeImporter::StartImport(const importer::SourceProfile& source_profile,

if ((items & importer::PASSWORDS) && !cancelled()) {
bridge_->NotifyItemStarted(importer::PASSWORDS);
ImportPasswords(base::FilePath(FILE_PATH_LITERAL("Preferences")));
ImportPasswords();
bridge_->NotifyItemEnded(importer::PASSWORDS);
}

Expand Down Expand Up @@ -290,7 +360,7 @@ double ChromeImporter::chromeTimeToDouble(int64_t time) {
return ((time * 10 - 0x19DB1DED53E8000) / 10000) / 1000;
}

void ChromeImporter::ImportPasswords(const base::FilePath& prefs_filename) {
void ChromeImporter::ImportPasswords() {
#if defined(OS_LINUX)
// Set up crypt config.
std::unique_ptr<os_crypt::Config> config(new os_crypt::Config());
Expand All @@ -299,9 +369,22 @@ void ChromeImporter::ImportPasswords(const base::FilePath& prefs_filename) {
config->user_data_path = source_path_;
OSCrypt::SetConfig(std::move(config));
#endif

#if defined(OS_WIN)
base::FilePath local_state_path = source_path_.DirName().Append(
base::FilePath::StringType(FILE_PATH_LITERAL("Local State")));
if (!base::PathExists(local_state_path))
return;
if (!SetEncryptionKeyForPasswordImporting(local_state_path))
return;
#endif

base::FilePath passwords_path = source_path_.Append(
base::FilePath::StringType(FILE_PATH_LITERAL("Login Data")));

if (!base::PathExists(passwords_path))
return;

password_manager::LoginDatabase database(
passwords_path, password_manager::IsAccountStore(false));
if (!database.Init()) {
Expand Down
4 changes: 1 addition & 3 deletions utility/importer/chrome_importer.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ class ChromeImporter : public Importer {
protected:
~ChromeImporter() override;

static base::nix::DesktopEnvironment GetDesktopEnvironment();

void ImportBookmarks();
void ImportHistory();
void ImportPasswords(const base::FilePath& prefs_filename);
void ImportPasswords();

double chromeTimeToDouble(int64_t time);

Expand Down