Home | History | Annotate | Download | only in browser
      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 
     29 using base::win::RegKey;
     30 
     31 namespace autofill {
     32 
     33 // Forward declaration. This function is not in unnamed namespace as it
     34 // is referenced in the unittest.
     35 bool ImportCurrentUserProfiles(const std::string& app_locale,
     36                                std::vector<AutofillProfile>* profiles,
     37                                std::vector<CreditCard>* credit_cards);
     38 namespace {
     39 
     40 const wchar_t* const kProfileKey =
     41     L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles";
     42 const wchar_t* const kCreditCardKey =
     43     L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards";
     44 const wchar_t* const kPasswordHashValue = L"password_hash";
     45 const 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.
     50 const 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.
     54 std::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 
     66 bool 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 
     77 base::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 
    101 struct {
    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 
    134 typedef 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.
    140 bool 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.
    179 bool 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.
    199 class 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.
    246 bool 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 
    303 bool 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