1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/os_crypt/ie7_password_win.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wincrypt.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sha1.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Structures that IE7/IE8 use to store a username/password. 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some of the fields might have been incorrectly reverse engineered. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PreHeader { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD pre_header_size; // Size of this header structure. Always 12. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD header_size; // Size of the real Header: sizeof(Header) + 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // item_count * sizeof(Entry); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD data_size; // Size of the data referenced by the entries. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Header { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char wick[4]; // The string "WICK". I don't know what it means. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD fixed_header_size; // The size of this structure without the entries: 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sizeof(Header). 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DWORD item_count; // Number of entries. Should be even. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t two_letters[2]; // Two unknown bytes. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD unknown[2]; // Two unknown DWORDs. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Entry { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD offset; // Offset where the data referenced by this entry is 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // located. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILETIME time_stamp; // Timestamp when the password got added. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD string_length; // The length of the data string. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Main data structure. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PasswordEntry { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreHeader pre_header; // Contains the size of the different sections. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Header header; // Contains the number of items. 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Entry entry[1]; // List of entries containing a string. Even-indexed 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // are usernames, odd are passwords. There may be 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // several sets saved for a single url hash. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ie7_password { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetUserPassFromData(const std::vector<unsigned char>& data, 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::vector<DecryptedCredentials>* credentials) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PasswordEntry* information = 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const PasswordEntry*>(&data.front()); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some expected values. If it's not what we expect we don't even try to 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // understand the data. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (information->pre_header.pre_header_size != sizeof(PreHeader)) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const int entry_count = information->header.item_count; 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (entry_count % 2) // Usernames and Passwords 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (information->header.fixed_header_size != sizeof(Header)) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const uint8* offset_to_data = &data[0] + 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) information->pre_header.header_size + 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) information->pre_header.pre_header_size; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (int i = 0; i < entry_count / 2; ++i) { 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const Entry* user_entry = &information->entry[2*i]; 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const Entry* pass_entry = user_entry+1; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DecryptedCredentials c; 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) c.username = reinterpret_cast<const wchar_t*>(offset_to_data + 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) user_entry->offset); 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) c.password = reinterpret_cast<const wchar_t*>(offset_to_data + 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pass_entry->offset); 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) credentials->push_back(c); 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring GetUrlHash(const std::wstring& url) { 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::wstring lower_case_url = base::StringToLowerASCII(url); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get a data buffer out of our std::wstring to pass to SHA1HashString. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_buffer( 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const char*>(lower_case_url.c_str()), 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (lower_case_url.size() + 1) * sizeof(wchar_t)); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string hash_bin = base::SHA1HashString(url_buffer); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::wstring url_hash; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Transform the buffer to an hexadecimal string. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char checksum = 0; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < hash_bin.size(); ++i) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // std::string gives signed chars, which mess with StringPrintf and 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // check_sum. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char hash_byte = static_cast<unsigned char>(hash_bin[i]); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) checksum += hash_byte; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_hash += base::StringPrintf(L"%2.2X", static_cast<unsigned>(hash_byte)); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_hash += base::StringPrintf(L"%2.2X", checksum); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return url_hash; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool DecryptPasswords(const std::wstring& url, 1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::vector<unsigned char>& data, 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::vector<DecryptedCredentials>* credentials) { 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::wstring lower_case_url = base::StringToLowerASCII(url); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DATA_BLOB input = {0}; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DATA_BLOB output = {0}; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DATA_BLOB url_key = {0}; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input.pbData = const_cast<unsigned char*>(&data.front()); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input.cbData = static_cast<DWORD>((data.size()) * 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(std::string::value_type)); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_key.pbData = reinterpret_cast<unsigned char*>( 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const_cast<wchar_t*>(lower_case_url.data())); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_key.cbData = static_cast<DWORD>((lower_case_url.size() + 1) * 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(std::wstring::value_type)); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CryptUnprotectData(&input, NULL, &url_key, NULL, NULL, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPTPROTECT_UI_FORBIDDEN, &output)) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now that we have the decrypted information, we need to understand it. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<unsigned char> decrypted_data; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decrypted_data.resize(output.cbData); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&decrypted_data.front(), output.pbData, output.cbData); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) GetUserPassFromData(decrypted_data, credentials); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LocalFree(output.pbData); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ie7_password 149