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