11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// found in the LICENSE file. 41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/signin/local_auth.h" 61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/base64.h" 81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/logging.h" 91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/metrics/histogram.h" 111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/pref_service.h" 121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/string_util.h" 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/browser_process.h" 141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h" 161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/common/pref_names.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/os_crypt/os_crypt.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h" 191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "crypto/random.h" 201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "crypto/secure_util.h" 211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "crypto/symmetric_key.h" 221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace { 241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// WARNING: Changing these values will make it impossible to do off-line 261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// authentication until the next successful on-line authentication. To change 271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// these safely, change the "encoding" version below and make verification 281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// handle multiple values. 291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const char kHash1Encoding = '1'; 301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const unsigned kHash1Bits = 256; 311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const unsigned kHash1Bytes = kHash1Bits / 8; 321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const unsigned kHash1IterationCount = 100000; 331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)std::string CreateSecurePasswordHash(const std::string& salt, 351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const std::string& password, 361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) char encoding) { 371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(kHash1Bytes, salt.length()); 381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(kHash1Encoding, encoding); // Currently support only one method. 391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Time start_time = base::Time::Now(); 411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Library call to create secure password hash as SymmetricKey (uses PBKDF2). 431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) scoped_ptr<crypto::SymmetricKey> password_key( 441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) crypto::SymmetricKey::DeriveKeyFromPassword( 451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) crypto::SymmetricKey::AES, 461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) password, salt, 471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) kHash1IterationCount, kHash1Bits)); 481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string password_hash; 491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const bool success = password_key->GetRawKey(&password_hash); 501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(success); 511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(kHash1Bytes, password_hash.length()); 521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) UMA_HISTOGRAM_TIMES("PasswordHash.CreateTime", 541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Time::Now() - start_time); 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return password_hash; 571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)std::string EncodePasswordHashRecord(const std::string& record, 601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) char encoding) { 611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(kHash1Encoding, encoding); // Currently support only one method. 621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Encrypt the hash using the OS account-password protection (if available). 641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string encoded; 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const bool success = OSCrypt::EncryptString(record, &encoded); 661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(success); 671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Convert binary record to text for preference database. 691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string encoded64; 701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Base64Encode(encoded, &encoded64); 711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Stuff the "encoding" value into the first byte. 731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) encoded64.insert(0, &encoding, sizeof(encoding)); 741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return encoded64; 761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool DecodePasswordHashRecord(const std::string& encoded, 791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string* decoded, 801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) char* encoding) { 811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Extract the "encoding" value from the first byte and validate. 821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (encoded.length() < 1) 831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *encoding = encoded[0]; 851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (*encoding != kHash1Encoding) 861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Stored record is base64; convert to binary. 891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string unbase64; 901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!base::Base64Decode(encoded.substr(1), &unbase64)) 911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Decrypt the record using the OS account-password protection (if available). 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return OSCrypt::DecryptString(unbase64, decoded); 951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccisize_t GetProfileInfoIndexOfProfile(const Profile* profile) { 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(profile); 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ProfileInfoCache& info = 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci g_browser_process->profile_manager()->GetProfileInfoCache(); 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return info.GetIndexOfProfileWithPath(profile->GetPath()); 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} // namespace 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace chrome { 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void RegisterLocalAuthPrefs(user_prefs::PrefRegistrySyncable* registry) { 1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) registry->RegisterStringPref( 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) prefs::kGoogleServicesPasswordHash, 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string(), 1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SetLocalAuthCredentials(size_t info_index, 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const std::string& password) { 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (info_index == std::string::npos) { 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci NOTREACHED(); 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(password.length()); 1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Salt should be random data, as long as the hash length, and different with 1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // every save. 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string salt_str; 1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) crypto::RandBytes(WriteInto(&salt_str, kHash1Bytes + 1), kHash1Bytes); 1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(kHash1Bytes, salt_str.length()); 1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Perform secure hash of password for storage. 1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string password_hash = CreateSecurePasswordHash( 1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) salt_str, password, kHash1Encoding); 1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK_EQ(kHash1Bytes, password_hash.length()); 1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Group all fields into a single record for storage; 1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string record; 1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) record.append(salt_str); 1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) record.append(password_hash); 1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Encode it and store it. 1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string encoded = EncodePasswordHashRecord(record, kHash1Encoding); 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProfileInfoCache& info = 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) g_browser_process->profile_manager()->GetProfileInfoCache(); 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) info.SetLocalAuthCredentialsOfProfileAtIndex(info_index, encoded); 1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SetLocalAuthCredentials(const Profile* profile, 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& password) { 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), password); 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ValidateLocalAuthCredentials(size_t info_index, 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& password) { 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (info_index == std::string::npos) { 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NOTREACHED(); 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string record; 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) char encoding; 1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProfileInfoCache& info = 163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) g_browser_process->profile_manager()->GetProfileInfoCache(); 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string encodedhash = 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) info.GetLocalAuthCredentialsOfProfileAtIndex(info_index); 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (encodedhash.length() == 0 && password.length() == 0) 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!DecodePasswordHashRecord(encodedhash, &record, &encoding)) 1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string password_hash; 1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const char* password_saved; 1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const char* password_check; 1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) size_t password_length; 1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (encoding == '1') { 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Validate correct length; extract salt and password hash. 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (record.length() != 2 * kHash1Bytes) 1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string salt_str(record.data(), kHash1Bytes); 1821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) password_saved = record.data() + kHash1Bytes; 1831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) password_hash = CreateSecurePasswordHash(salt_str, password, encoding); 1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) password_check = password_hash.data(); 1851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) password_length = kHash1Bytes; 1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 1871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // unknown encoding 1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return crypto::SecureMemEqual(password_saved, password_check, 1921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) password_length); 1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ValidateLocalAuthCredentials(const Profile* profile, 196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& password) { 1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return ValidateLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), 1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci password); 199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} // namespace chrome 202