diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/ie7_password.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ie7_password.cc')
-rw-r--r-- | chrome/browser/ie7_password.cc | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/chrome/browser/ie7_password.cc b/chrome/browser/ie7_password.cc new file mode 100644 index 0000000..746e81a --- /dev/null +++ b/chrome/browser/ie7_password.cc @@ -0,0 +1,222 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/browser/ie7_password.h" + +#include <wincrypt.h> +#include <string> +#include <vector> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" + +namespace { + +// Structures that IE7/IE8 use to store a username/password. +// Some of the fields might have been incorrectly reverse engineered. +struct PreHeader { + DWORD pre_header_size; // Size of this header structure. Always 12. + DWORD header_size; // Size of the real Header: sizeof(Header) + + // item_count * sizeof(Entry); + DWORD data_size; // Size of the data referenced by the entries. +}; + +struct Header { + char wick[4]; // The string "WICK". I don't know what it means. + DWORD fixed_header_size; // The size of this structure without the entries: + // sizeof(Header). + DWORD item_count; // Number of entries. It should always be 2. One for + // the username, and one for the password. + wchar_t two_letters[2]; // Two unknown bytes. + DWORD unknown[2]; // Two unknown DWORDs. +}; + +struct Entry { + DWORD offset; // Offset where the data referenced by this entry is + // located. + FILETIME time_stamp; // Timestamp when the password got added. + DWORD string_length; // The length of the data string. +}; + +// Main data structure. +struct PasswordEntry { + PreHeader pre_header; // Contains the size of the different sections. + Header header; // Contains the number of items. + Entry entry[1]; // List of entries containing a string. The first one + // is the username, the second one if the password. +}; + +// Cleans up a crypt prov and a crypt hash. +void CleanupHashContext(HCRYPTPROV prov, HCRYPTHASH hash) { + if (hash) + CryptDestroyHash(hash); + if (prov) + CryptReleaseContext(prov, 0); +} + +} // namespace + +namespace ie7_password { + +bool GetUserPassFromData(const std::vector<unsigned char>& data, + std::wstring* username, + std::wstring* password) { + const PasswordEntry* information = + reinterpret_cast<const PasswordEntry*>(&data.front()); + + // Some expected values. If it's not what we expect we don't even try to + // understand the data. + if (information->pre_header.pre_header_size != sizeof(PreHeader)) + return false; + + if (information->header.item_count != 2) // Username and Password + return false; + + if (information->header.fixed_header_size != sizeof(Header)) + return false; + + const uint8* ptr = &data.front(); + const uint8* offset_to_data = ptr + information->pre_header.header_size + + information->pre_header.pre_header_size; + + const Entry* user_entry = information->entry; + const Entry* pass_entry = user_entry+1; + + *username = reinterpret_cast<const wchar_t*>(offset_to_data + + user_entry->offset); + *password = reinterpret_cast<const wchar_t*>(offset_to_data + + pass_entry->offset); + return true; +} + +std::wstring GetUrlHash(const std::wstring& url) { + HCRYPTPROV prov = NULL; + HCRYPTHASH hash = NULL; + + std::wstring lower_case_url = StringToLowerASCII(url); + BOOL result = CryptAcquireContext(&prov, 0, 0, PROV_RSA_FULL, 0); + if (!result) { + if (GetLastError() == NTE_BAD_KEYSET) { + // The keyset does not exist. Create one. + result = CryptAcquireContext(&prov, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET); + } + } + + if (!result) { + DCHECK(false); + return std::wstring(); + } + + // Initialize the hash. + if (!CryptCreateHash(prov, CALG_SHA1, 0, 0, &hash)) { + CleanupHashContext(prov, hash); + DCHECK(false); + return std::wstring(); + } + + // Add the data to the hash. + const unsigned char* buffer = + reinterpret_cast<const unsigned char*>(lower_case_url.c_str()); + DWORD data_len = static_cast<DWORD>((lower_case_url.size() + 1) * + sizeof(wchar_t)); + if (!CryptHashData(hash, buffer, data_len, 0)) { + CleanupHashContext(prov, hash); + DCHECK(false); + return std::wstring(); + } + + // Get the size of the resulting hash. + DWORD hash_len = 0; + DWORD buffer_size = sizeof(hash_len); + if (!CryptGetHashParam(hash, HP_HASHSIZE, + reinterpret_cast<unsigned char*>(&hash_len), + &buffer_size, 0)) { + CleanupHashContext(prov, hash); + DCHECK(false); + return std::wstring(); + } + + // Get the hash data. + scoped_array<unsigned char> new_buffer(new unsigned char[hash_len]); + if (!CryptGetHashParam(hash, HP_HASHVAL, new_buffer.get(), &hash_len, 0)) { + CleanupHashContext(prov, hash); + DCHECK(false); + return std::wstring(); + } + + std::wstring url_hash; + + // Transform the buffer to an hexadecimal string. + unsigned char checksum = 0; + for (DWORD i = 0; i < hash_len; ++i) { + checksum += new_buffer.get()[i]; + url_hash += StringPrintf(L"%2.2X", new_buffer.get()[i]); + } + + url_hash += StringPrintf(L"%2.2X", checksum); + + CleanupHashContext(prov, hash); + return url_hash; +} + +bool DecryptPassword(const std::wstring& url, + const std::vector<unsigned char>& data, + std::wstring* username, std::wstring* password) { + std::wstring lower_case_url = StringToLowerASCII(url); + DATA_BLOB input = {0}; + DATA_BLOB output = {0}; + DATA_BLOB url_key = {0}; + + input.pbData = const_cast<unsigned char*>(&data.front()); + input.cbData = static_cast<DWORD>((data.size()) * + sizeof(std::string::value_type)); + + url_key.pbData = reinterpret_cast<unsigned char*>( + const_cast<wchar_t*>(lower_case_url.data())); + url_key.cbData = static_cast<DWORD>((lower_case_url.size() + 1) * + sizeof(std::wstring::value_type)); + + if (CryptUnprotectData(&input, NULL, &url_key, NULL, NULL, + CRYPTPROTECT_UI_FORBIDDEN, &output)) { + // Now that we have the decrypted information, we need to understand it. + std::vector<unsigned char> decrypted_data; + decrypted_data.resize(output.cbData); + memcpy(&decrypted_data.front(), output.pbData, output.cbData); + + GetUserPassFromData(decrypted_data, username, password); + + LocalFree(output.pbData); + return true; + } + + return false; +} + +} // namespace ie7_password |