autofill_ie_toolbar_import_win.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2013 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 "components/autofill/core/browser/autofill_ie_toolbar_import_win.h"
6
7#include <stddef.h>
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/compiler_specific.h"
14#include "base/logging.h"
15#include "base/strings/string16.h"
16#include "base/win/registry.h"
17#include "components/autofill/core/browser/autofill_country.h"
18#include "components/autofill/core/browser/autofill_profile.h"
19#include "components/autofill/core/browser/credit_card.h"
20#include "components/autofill/core/browser/crypto/rc4_decryptor.h"
21#include "components/autofill/core/browser/field_types.h"
22#include "components/autofill/core/browser/form_group.h"
23#include "components/autofill/core/browser/personal_data_manager.h"
24#include "components/autofill/core/browser/personal_data_manager_observer.h"
25#include "components/autofill/core/browser/phone_number.h"
26#include "components/autofill/core/browser/phone_number_i18n.h"
27#include "components/os_crypt/os_crypt.h"
28
29using base::win::RegKey;
30
31namespace autofill {
32
33// Forward declaration. This function is not in unnamed namespace as it
34// is referenced in the unittest.
35bool ImportCurrentUserProfiles(const std::string& app_locale,
36                               std::vector<AutofillProfile>* profiles,
37                               std::vector<CreditCard>* credit_cards);
38namespace {
39
40const wchar_t* const kProfileKey =
41    L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles";
42const wchar_t* const kCreditCardKey =
43    L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards";
44const wchar_t* const kPasswordHashValue = L"password_hash";
45const wchar_t* const kSaltValue = L"salt";
46
47// This string is stored along with saved addresses and credit cards in the
48// WebDB, and hence should not be modified, so that it remains consistent over
49// time.
50const char kIEToolbarImportOrigin[] = "Imported from Internet Explorer";
51
52// This is RC4 decryption for Toolbar credit card data. This is necessary
53// because it is not standard, so Crypto API cannot be used.
54std::wstring DecryptCCNumber(const std::wstring& data) {
55  const wchar_t* kEmptyKey =
56    L"\x3605\xCEE5\xCE49\x44F7\xCF4E\xF6CC\x604B\xFCBE\xC70A\x08FD";
57  const size_t kMacLen = 10;
58
59  if (data.length() <= kMacLen)
60    return std::wstring();
61
62  RC4Decryptor rc4_algorithm(kEmptyKey);
63  return rc4_algorithm.Run(data.substr(kMacLen));
64}
65
66bool IsEmptySalt(std::wstring const& salt) {
67  // Empty salt in IE Toolbar is \x1\x2...\x14
68  if (salt.length() != 20)
69    return false;
70  for (size_t i = 0; i < salt.length(); ++i) {
71    if (salt[i] != i + 1)
72      return false;
73  }
74  return true;
75}
76
77base::string16 ReadAndDecryptValue(const RegKey& key,
78                                   const wchar_t* value_name) {
79  DWORD data_type = REG_BINARY;
80  DWORD data_size = 0;
81  LONG result = key.ReadValue(value_name, NULL, &data_size, &data_type);
82  if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY)
83    return base::string16();
84  std::string data;
85  data.resize(data_size);
86  result = key.ReadValue(value_name, &(data[0]), &data_size, &data_type);
87  if (result == ERROR_SUCCESS) {
88    std::string out_data;
89    if (OSCrypt::DecryptString(data, &out_data)) {
90      // The actual data is in UTF16 already.
91      if (!(out_data.size() & 1) && (out_data.size() > 2) &&
92          !out_data[out_data.size() - 1] && !out_data[out_data.size() - 2]) {
93        return base::string16(
94            reinterpret_cast<const wchar_t *>(out_data.c_str()));
95      }
96    }
97  }
98  return base::string16();
99}
100
101struct {
102  ServerFieldType field_type;
103  const wchar_t *reg_value_name;
104} profile_reg_values[] = {
105  { NAME_FIRST,                    L"name_first" },
106  { NAME_MIDDLE,                   L"name_middle" },
107  { NAME_LAST,                     L"name_last" },
108  { NAME_SUFFIX,                   L"name_suffix" },
109  { EMAIL_ADDRESS,                 L"email" },
110  { COMPANY_NAME,                  L"company_name" },
111  { PHONE_HOME_NUMBER,             L"phone_home_number" },
112  { PHONE_HOME_CITY_CODE,          L"phone_home_city_code" },
113  { PHONE_HOME_COUNTRY_CODE,       L"phone_home_country_code" },
114  { ADDRESS_HOME_LINE1,            L"address_home_line1" },
115  { ADDRESS_HOME_LINE2,            L"address_home_line2" },
116  { ADDRESS_HOME_CITY,             L"address_home_city" },
117  { ADDRESS_HOME_STATE,            L"address_home_state" },
118  { ADDRESS_HOME_ZIP,              L"address_home_zip" },
119  { ADDRESS_HOME_COUNTRY,          L"address_home_country" },
120  { ADDRESS_BILLING_LINE1,         L"address_billing_line1" },
121  { ADDRESS_BILLING_LINE2,         L"address_billing_line2" },
122  { ADDRESS_BILLING_CITY,          L"address_billing_city" },
123  { ADDRESS_BILLING_STATE,         L"address_billing_state" },
124  { ADDRESS_BILLING_ZIP,           L"address_billing_zip" },
125  { ADDRESS_BILLING_COUNTRY,       L"address_billing_country" },
126  { CREDIT_CARD_NAME,              L"credit_card_name" },
127  { CREDIT_CARD_NUMBER,            L"credit_card_number" },
128  { CREDIT_CARD_EXP_MONTH,         L"credit_card_exp_month" },
129  { CREDIT_CARD_EXP_4_DIGIT_YEAR,  L"credit_card_exp_4_digit_year" },
130  { CREDIT_CARD_TYPE,              L"credit_card_type" },
131  // We do not import verification code.
132};
133
134typedef std::map<std::wstring, ServerFieldType> RegToFieldMap;
135
136// Imports address or credit card data from the given registry |key| into the
137// given |form_group|, with the help of |reg_to_field|.  When importing address
138// data, writes the phone data into |phone|; otherwise, |phone| should be null.
139// Returns true if any fields were set, false otherwise.
140bool ImportSingleFormGroup(const RegKey& key,
141                           const RegToFieldMap& reg_to_field,
142                           const std::string& app_locale,
143                           FormGroup* form_group,
144                           PhoneNumber::PhoneCombineHelper* phone) {
145  if (!key.Valid())
146    return false;
147
148  bool has_non_empty_fields = false;
149
150  for (uint32 i = 0; i < key.GetValueCount(); ++i) {
151    std::wstring value_name;
152    if (key.GetValueNameAt(i, &value_name) != ERROR_SUCCESS)
153      continue;
154
155    RegToFieldMap::const_iterator it = reg_to_field.find(value_name);
156    if (it == reg_to_field.end())
157      continue;  // This field is not imported.
158
159    base::string16 field_value = ReadAndDecryptValue(key, value_name.c_str());
160    if (!field_value.empty()) {
161      if (it->second == CREDIT_CARD_NUMBER)
162        field_value = DecryptCCNumber(field_value);
163
164      // Phone numbers are stored piece-by-piece, and then reconstructed from
165      // the pieces.  The rest of the fields are set "as is".
166      if (!phone || !phone->SetInfo(AutofillType(it->second), field_value)) {
167        has_non_empty_fields = true;
168        form_group->SetInfo(AutofillType(it->second), field_value, app_locale);
169      }
170    }
171  }
172
173  return has_non_empty_fields;
174}
175
176// Imports address data from the given registry |key| into the given |profile|,
177// with the help of |reg_to_field|.  Returns true if any fields were set, false
178// otherwise.
179bool ImportSingleProfile(const std::string& app_locale,
180                         const RegKey& key,
181                         const RegToFieldMap& reg_to_field,
182                         AutofillProfile* profile) {
183  PhoneNumber::PhoneCombineHelper phone;
184  bool has_non_empty_fields =
185      ImportSingleFormGroup(key, reg_to_field, app_locale, profile, &phone);
186
187  // Now re-construct the phones if needed.
188  base::string16 constructed_number;
189  if (phone.ParseNumber(*profile, app_locale, &constructed_number)) {
190    has_non_empty_fields = true;
191    profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, constructed_number);
192  }
193
194  return has_non_empty_fields;
195}
196
197// Imports profiles from the IE toolbar and stores them. Asynchronous
198// if PersonalDataManager has not been loaded yet. Deletes itself on completion.
199class AutofillImporter : public PersonalDataManagerObserver {
200 public:
201  explicit AutofillImporter(PersonalDataManager* personal_data_manager)
202    : personal_data_manager_(personal_data_manager) {
203      personal_data_manager_->AddObserver(this);
204  }
205
206  bool ImportProfiles() {
207    if (!ImportCurrentUserProfiles(personal_data_manager_->app_locale(),
208                                   &profiles_,
209                                   &credit_cards_)) {
210      delete this;
211      return false;
212    }
213    if (personal_data_manager_->IsDataLoaded())
214      OnPersonalDataChanged();
215    return true;
216  }
217
218  // PersonalDataManagerObserver:
219  virtual void OnPersonalDataChanged() OVERRIDE {
220    for (std::vector<AutofillProfile>::const_iterator iter = profiles_.begin();
221         iter != profiles_.end(); ++iter) {
222      personal_data_manager_->AddProfile(*iter);
223    }
224    for (std::vector<CreditCard>::const_iterator iter = credit_cards_.begin();
225         iter != credit_cards_.end(); ++iter) {
226      personal_data_manager_->AddCreditCard(*iter);
227    }
228    delete this;
229  }
230
231 private:
232  ~AutofillImporter() {
233    personal_data_manager_->RemoveObserver(this);
234  }
235
236  PersonalDataManager* personal_data_manager_;
237  std::vector<AutofillProfile> profiles_;
238  std::vector<CreditCard> credit_cards_;
239};
240
241}  // namespace
242
243// Imports Autofill profiles and credit cards from IE Toolbar if present and not
244// password protected. Returns true if data is successfully retrieved. False if
245// there is no data, data is password protected or error occurred.
246bool ImportCurrentUserProfiles(const std::string& app_locale,
247                               std::vector<AutofillProfile>* profiles,
248                               std::vector<CreditCard>* credit_cards) {
249  DCHECK(profiles);
250  DCHECK(credit_cards);
251
252  // Create a map of possible fields for a quick access.
253  RegToFieldMap reg_to_field;
254  for (size_t i = 0; i < arraysize(profile_reg_values); ++i) {
255    reg_to_field[std::wstring(profile_reg_values[i].reg_value_name)] =
256        profile_reg_values[i].field_type;
257  }
258
259  base::win::RegistryKeyIterator iterator_profiles(HKEY_CURRENT_USER,
260                                                   kProfileKey);
261  for (; iterator_profiles.Valid(); ++iterator_profiles) {
262    std::wstring key_name(kProfileKey);
263    key_name.append(L"\\");
264    key_name.append(iterator_profiles.Name());
265    RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ);
266    AutofillProfile profile;
267    profile.set_origin(kIEToolbarImportOrigin);
268    if (ImportSingleProfile(app_locale, key, reg_to_field, &profile)) {
269      // Combine phones into whole phone #.
270      profiles->push_back(profile);
271    }
272  }
273  base::string16 password_hash;
274  base::string16 salt;
275  RegKey cc_key(HKEY_CURRENT_USER, kCreditCardKey, KEY_READ);
276  if (cc_key.Valid()) {
277    password_hash = ReadAndDecryptValue(cc_key, kPasswordHashValue);
278    salt = ReadAndDecryptValue(cc_key, kSaltValue);
279  }
280
281  // We import CC profiles only if they are not password protected.
282  if (password_hash.empty() && IsEmptySalt(salt)) {
283    base::win::RegistryKeyIterator iterator_cc(HKEY_CURRENT_USER,
284                                               kCreditCardKey);
285    for (; iterator_cc.Valid(); ++iterator_cc) {
286      std::wstring key_name(kCreditCardKey);
287      key_name.append(L"\\");
288      key_name.append(iterator_cc.Name());
289      RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ);
290      CreditCard credit_card;
291      credit_card.set_origin(kIEToolbarImportOrigin);
292      if (ImportSingleFormGroup(
293              key, reg_to_field, app_locale, &credit_card, NULL)) {
294        base::string16 cc_number = credit_card.GetRawInfo(CREDIT_CARD_NUMBER);
295        if (!cc_number.empty())
296          credit_cards->push_back(credit_card);
297      }
298    }
299  }
300  return (profiles->size() + credit_cards->size()) > 0;
301}
302
303bool ImportAutofillDataWin(PersonalDataManager* pdm) {
304  // In incognito mode we do not have PDM - and we should not import anything.
305  if (!pdm)
306    return false;
307  AutofillImporter *importer = new AutofillImporter(pdm);
308  // importer will self delete.
309  return importer->ImportProfiles();
310}
311
312}  // namespace autofill
313