autofill_ie_toolbar_import_win.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h" 6 7#include "base/basictypes.h" 8#include "base/string16.h" 9#include "base/win/registry.h" 10#include "chrome/browser/autofill/autofill_profile.h" 11#include "chrome/browser/autofill/credit_card.h" 12#include "chrome/browser/autofill/crypto/rc4_decryptor.h" 13#include "chrome/browser/autofill/field_types.h" 14#include "chrome/browser/autofill/personal_data_manager.h" 15#include "chrome/browser/sync/util/data_encryption.h" 16 17using base::win::RegKey; 18 19// Forward declaration. This function is not in unnamed namespace as it 20// is referenced in the unittest. 21bool ImportCurrentUserProfiles(std::vector<AutoFillProfile>* profiles, 22 std::vector<CreditCard>* credit_cards); 23namespace { 24 25const wchar_t* const kProfileKey = 26 L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles"; 27const wchar_t* const kCreditCardKey = 28 L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards"; 29const wchar_t* const kPasswordHashValue = L"password_hash"; 30const wchar_t* const kSaltValue = L"salt"; 31 32// This is RC4 decryption for Toolbar credit card data. This is necessary 33// because it is not standard, so Crypto api cannot be used. 34std::wstring DecryptCCNumber(const std::wstring& data) { 35 const wchar_t* kEmptyKey = 36 L"\x3605\xCEE5\xCE49\x44F7\xCF4E\xF6CC\x604B\xFCBE\xC70A\x08FD"; 37 const size_t kMacLen = 10; 38 39 if (data.length() <= kMacLen) 40 return std::wstring(); 41 42 RC4Decryptor rc4_algorithm(kEmptyKey); 43 return rc4_algorithm.Run(data.substr(kMacLen)); 44} 45 46bool IsEmptySalt(std::wstring const& salt) { 47 // Empty salt in IE Toolbar is \x1\x2...\x14 48 if (salt.length() != 20) 49 return false; 50 for (size_t i = 0; i < salt.length(); ++i) { 51 if (salt[i] != i + 1) 52 return false; 53 } 54 return true; 55} 56 57string16 ReadAndDecryptValue(RegKey* key, const wchar_t* value_name) { 58 DWORD data_type = REG_BINARY; 59 DWORD data_size = 0; 60 LONG result = key->ReadValue(value_name, NULL, &data_size, &data_type); 61 if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY) 62 return string16(); 63 std::vector<uint8> data; 64 data.resize(data_size); 65 result = key->ReadValue(value_name, &(data[0]), &data_size, &data_type); 66 if (result == ERROR_SUCCESS) { 67 std::string out_data; 68 if (DecryptData(data, &out_data)) { 69 // The actual data is in UTF16 already. 70 if (!(out_data.size() & 1) && (out_data.size() > 2) && 71 !out_data[out_data.size() - 1] && !out_data[out_data.size() - 2]) { 72 return string16( 73 reinterpret_cast<const wchar_t *>(out_data.c_str())); 74 } 75 } 76 } 77 return string16(); 78} 79 80struct { 81 AutoFillFieldType field_type; 82 const wchar_t *reg_value_name; 83} profile_reg_values[] = { 84 { NAME_FIRST, L"name_first" }, 85 { NAME_MIDDLE, L"name_middle" }, 86 { NAME_LAST, L"name_last" }, 87 { NAME_SUFFIX, L"name_suffix" }, 88 { EMAIL_ADDRESS, L"email" }, 89 { COMPANY_NAME, L"company_name" }, 90 { PHONE_HOME_NUMBER, L"phone_home_number" }, 91 { PHONE_HOME_CITY_CODE, L"phone_home_city_code" }, 92 { PHONE_HOME_COUNTRY_CODE, L"phone_home_country_code" }, 93 { PHONE_FAX_NUMBER, L"phone_fax_number" }, 94 { PHONE_FAX_CITY_CODE, L"phone_fax_city_code" }, 95 { PHONE_FAX_COUNTRY_CODE, L"phone_fax_country_code" }, 96 { ADDRESS_HOME_LINE1, L"address_home_line1" }, 97 { ADDRESS_HOME_LINE2, L"address_home_line2" }, 98 { ADDRESS_HOME_CITY, L"address_home_city" }, 99 { ADDRESS_HOME_STATE, L"address_home_state" }, 100 { ADDRESS_HOME_ZIP, L"address_home_zip" }, 101 { ADDRESS_HOME_COUNTRY, L"address_home_country" }, 102 { ADDRESS_BILLING_LINE1, L"address_billing_line1" }, 103 { ADDRESS_BILLING_LINE2, L"address_billing_line2" }, 104 { ADDRESS_BILLING_CITY, L"address_billing_city" }, 105 { ADDRESS_BILLING_STATE, L"address_billing_state" }, 106 { ADDRESS_BILLING_ZIP, L"address_billing_zip" }, 107 { ADDRESS_BILLING_COUNTRY, L"address_billing_country" }, 108 { CREDIT_CARD_NAME, L"credit_card_name" }, 109 { CREDIT_CARD_NUMBER, L"credit_card_number" }, 110 { CREDIT_CARD_EXP_MONTH, L"credit_card_exp_month" }, 111 { CREDIT_CARD_EXP_4_DIGIT_YEAR, L"credit_card_exp_4_digit_year" }, 112 { CREDIT_CARD_TYPE, L"credit_card_type" }, 113 // We do not import verification code. 114}; 115 116typedef std::map<std::wstring, AutoFillFieldType> RegToFieldMap; 117 118bool ImportSingleProfile(FormGroup* profile, 119 RegKey* key, 120 const RegToFieldMap& reg_to_field ) { 121 DCHECK(profile != NULL); 122 if (!key->Valid()) 123 return false; 124 125 bool has_non_empty_fields = false; 126 127 for (uint32 value_index = 0; value_index < key->ValueCount(); ++value_index) { 128 std::wstring value_name; 129 if (key->ReadName(value_index, &value_name) != ERROR_SUCCESS) 130 continue; 131 RegToFieldMap::const_iterator it = reg_to_field.find(value_name); 132 if (it == reg_to_field.end()) 133 continue; // This field is not imported. 134 string16 field_value = ReadAndDecryptValue(key, value_name.c_str()); 135 if (!field_value.empty()) { 136 has_non_empty_fields = true; 137 if (it->second == CREDIT_CARD_NUMBER) { 138 field_value = DecryptCCNumber(field_value); 139 } 140 profile->SetInfo(AutoFillType(it->second), field_value); 141 } 142 } 143 return has_non_empty_fields; 144} 145 146// Imports profiles from the IE toolbar and stores them. Asynchronous 147// if PersonalDataManager has not been loaded yet. Deletes itself on completion. 148class AutoFillImporter : public PersonalDataManager::Observer { 149 public: 150 explicit AutoFillImporter(PersonalDataManager* personal_data_manager) 151 : personal_data_manager_(personal_data_manager) { 152 personal_data_manager_->SetObserver(this); 153 } 154 155 bool ImportProfiles() { 156 if (!ImportCurrentUserProfiles(&profiles_, &credit_cards_)) { 157 delete this; 158 return false; 159 } 160 if (personal_data_manager_->IsDataLoaded()) 161 OnPersonalDataLoaded(); 162 return true; 163 } 164 165 // PersonalDataManager::Observer methods: 166 virtual void OnPersonalDataLoaded() { 167 if (!profiles_.empty()) 168 personal_data_manager_->SetProfiles(&profiles_); 169 if (!credit_cards_.empty()) 170 personal_data_manager_->SetCreditCards(&credit_cards_); 171 delete this; 172 } 173 174 private: 175 ~AutoFillImporter() { 176 personal_data_manager_->RemoveObserver(this); 177 } 178 179 PersonalDataManager* personal_data_manager_; 180 std::vector<AutoFillProfile> profiles_; 181 std::vector<CreditCard> credit_cards_; 182}; 183 184} // namespace 185 186// Imports AutoFill profiles and credit cards from IE Toolbar if present and not 187// password protected. Returns true if data is successfully retrieved. False if 188// there is no data, data is password protected or error occurred. 189bool ImportCurrentUserProfiles(std::vector<AutoFillProfile>* profiles, 190 std::vector<CreditCard>* credit_cards) { 191 DCHECK(profiles); 192 DCHECK(credit_cards); 193 194 // Create a map of possible fields for a quick access. 195 RegToFieldMap reg_to_field; 196 for (size_t i = 0; i < arraysize(profile_reg_values); ++i) { 197 reg_to_field[std::wstring(profile_reg_values[i].reg_value_name)] = 198 profile_reg_values[i].field_type; 199 } 200 201 base::win::RegistryKeyIterator iterator_profiles(HKEY_CURRENT_USER, 202 kProfileKey); 203 for (; iterator_profiles.Valid(); ++iterator_profiles) { 204 std::wstring key_name(kProfileKey); 205 key_name.append(L"\\"); 206 key_name.append(iterator_profiles.Name()); 207 RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ); 208 AutoFillProfile profile; 209 if (ImportSingleProfile(&profile, &key, reg_to_field)) { 210 // Combine phones into whole phone #. 211 string16 phone; 212 phone = profile.GetFieldText(AutoFillType(PHONE_HOME_COUNTRY_CODE)); 213 phone.append(profile.GetFieldText(AutoFillType(PHONE_HOME_CITY_CODE))); 214 phone.append(profile.GetFieldText(AutoFillType(PHONE_HOME_NUMBER))); 215 profile.SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), phone); 216 phone = profile.GetFieldText(AutoFillType(PHONE_FAX_COUNTRY_CODE)); 217 phone.append(profile.GetFieldText(AutoFillType(PHONE_FAX_CITY_CODE))); 218 phone.append(profile.GetFieldText(AutoFillType(PHONE_FAX_NUMBER))); 219 profile.SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER), phone); 220 profiles->push_back(profile); 221 } 222 } 223 string16 password_hash; 224 string16 salt; 225 RegKey cc_key(HKEY_CURRENT_USER, kCreditCardKey, KEY_READ); 226 if (cc_key.Valid()) { 227 password_hash = ReadAndDecryptValue(&cc_key, kPasswordHashValue); 228 salt = ReadAndDecryptValue(&cc_key, kSaltValue); 229 } 230 231 // We import CC profiles only if they are not password protected. 232 if (password_hash.empty() && IsEmptySalt(salt)) { 233 base::win::RegistryKeyIterator iterator_cc(HKEY_CURRENT_USER, 234 kCreditCardKey); 235 for (; iterator_cc.Valid(); ++iterator_cc) { 236 std::wstring key_name(kCreditCardKey); 237 key_name.append(L"\\"); 238 key_name.append(iterator_cc.Name()); 239 RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ); 240 CreditCard credit_card; 241 if (ImportSingleProfile(&credit_card, &key, reg_to_field)) { 242 string16 cc_number = credit_card.GetFieldText( 243 AutoFillType(CREDIT_CARD_NUMBER)); 244 if (!cc_number.empty()) 245 credit_cards->push_back(credit_card); 246 } 247 } 248 } 249 return (profiles->size() + credit_cards->size()) > 0; 250} 251 252bool ImportAutofillDataWin(PersonalDataManager* pdm) { 253 // In incognito mode we do not have PDM - and we should not import anything. 254 if (!pdm) 255 return false; 256 AutoFillImporter *importer = new AutoFillImporter(pdm); 257 // importer will self delete. 258 return importer->ImportProfiles(); 259} 260 261