Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: chrome/browser/signin/local_auth.cc

Issue 862103002: Only store leading 13 bits of password hash. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Pre-review check Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/signin/local_auth.h" 5 #include "chrome/browser/signin/local_auth.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 13 matching lines...) Expand all
24 24
25 // WARNING: Changing these values will make it impossible to do off-line 25 // WARNING: Changing these values will make it impossible to do off-line
26 // authentication until the next successful on-line authentication. To change 26 // authentication until the next successful on-line authentication. To change
27 // these safely, change the "encoding" version below and make verification 27 // these safely, change the "encoding" version below and make verification
28 // handle multiple values. 28 // handle multiple values.
29 const char kHash1Encoding = '1'; 29 const char kHash1Encoding = '1';
30 const unsigned kHash1Bits = 256; 30 const unsigned kHash1Bits = 256;
31 const unsigned kHash1Bytes = kHash1Bits / 8; 31 const unsigned kHash1Bytes = kHash1Bits / 8;
32 const unsigned kHash1IterationCount = 100000; 32 const unsigned kHash1IterationCount = 100000;
33 33
34 // Store 13 bits to provide pin-like security (8192 possible values), without
35 // providing a complete oracle for the user's GAIA password.
36 const unsigned kHash1StoredBits = 13;
bcwhite 2015/01/21 21:04:40 "Hash2" This is storage method #2. Use the same
Mike Lerman 2015/01/27 21:02:26 Done.
37 const unsigned kHash1StoredBytes = (kHash1StoredBits + 7) / 8;
38
34 std::string CreateSecurePasswordHash(const std::string& salt, 39 std::string CreateSecurePasswordHash(const std::string& salt,
35 const std::string& password, 40 const std::string& password,
36 char encoding) { 41 char encoding) {
37 DCHECK_EQ(kHash1Bytes, salt.length()); 42 DCHECK_EQ(kHash1Bytes, salt.length());
38 DCHECK_EQ(kHash1Encoding, encoding); // Currently support only one method. 43 DCHECK_EQ(kHash1Encoding, encoding); // Currently support only one method.
39 44
40 base::Time start_time = base::Time::Now(); 45 base::Time start_time = base::Time::Now();
41 46
42 // Library call to create secure password hash as SymmetricKey (uses PBKDF2). 47 // Library call to create secure password hash as SymmetricKey (uses PBKDF2).
43 scoped_ptr<crypto::SymmetricKey> password_key( 48 scoped_ptr<crypto::SymmetricKey> password_key(
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 // Salt should be random data, as long as the hash length, and different with 129 // Salt should be random data, as long as the hash length, and different with
125 // every save. 130 // every save.
126 std::string salt_str; 131 std::string salt_str;
127 crypto::RandBytes(WriteInto(&salt_str, kHash1Bytes + 1), kHash1Bytes); 132 crypto::RandBytes(WriteInto(&salt_str, kHash1Bytes + 1), kHash1Bytes);
128 DCHECK_EQ(kHash1Bytes, salt_str.length()); 133 DCHECK_EQ(kHash1Bytes, salt_str.length());
129 134
130 // Perform secure hash of password for storage. 135 // Perform secure hash of password for storage.
131 std::string password_hash = CreateSecurePasswordHash( 136 std::string password_hash = CreateSecurePasswordHash(
132 salt_str, password, kHash1Encoding); 137 salt_str, password, kHash1Encoding);
133 DCHECK_EQ(kHash1Bytes, password_hash.length()); 138 DCHECK_EQ(kHash1Bytes, password_hash.length());
139 password_hash = TruncateStringByBits(password_hash, kHash1StoredBits);
134 140
135 // Group all fields into a single record for storage; 141 // Group all fields into a single record for storage;
136 std::string record; 142 std::string record;
137 record.append(salt_str); 143 record.append(salt_str);
138 record.append(password_hash); 144 record.append(password_hash);
139 145
140 // Encode it and store it. 146 // Encode it and store it.
141 std::string encoded = EncodePasswordHashRecord(record, kHash1Encoding); 147 std::string encoded = EncodePasswordHashRecord(record, kHash1Encoding);
142 ProfileInfoCache& info = 148 ProfileInfoCache& info =
143 g_browser_process->profile_manager()->GetProfileInfoCache(); 149 g_browser_process->profile_manager()->GetProfileInfoCache();
144 info.SetLocalAuthCredentialsOfProfileAtIndex(info_index, encoded); 150 info.SetLocalAuthCredentialsOfProfileAtIndex(info_index, encoded);
145 } 151 }
146 152
147 void SetLocalAuthCredentials(const Profile* profile, 153 void SetLocalAuthCredentials(const Profile* profile,
148 const std::string& password) { 154 const std::string& password) {
149 SetLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), password); 155 SetLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), password);
150 } 156 }
151 157
152 bool ValidateLocalAuthCredentials(size_t info_index, 158 bool ValidateLocalAuthCredentials(size_t info_index,
153 const std::string& password) { 159 const std::string& password) {
154 if (info_index == std::string::npos) { 160 if (info_index == std::string::npos) {
155 NOTREACHED(); 161 NOTREACHED();
156 return false; 162 return false;
157 } 163 }
158 164
159 std::string record; 165 std::string record;
160 char encoding; 166 char encoding;
167 bool update_stored_credential = false;
161 168
162 ProfileInfoCache& info = 169 ProfileInfoCache& info =
163 g_browser_process->profile_manager()->GetProfileInfoCache(); 170 g_browser_process->profile_manager()->GetProfileInfoCache();
164 171
165 std::string encodedhash = 172 std::string encodedhash =
166 info.GetLocalAuthCredentialsOfProfileAtIndex(info_index); 173 info.GetLocalAuthCredentialsOfProfileAtIndex(info_index);
167 if (encodedhash.length() == 0 && password.length() == 0) 174 if (encodedhash.length() == 0 && password.length() == 0)
168 return true; 175 return true;
169 if (!DecodePasswordHashRecord(encodedhash, &record, &encoding)) 176 if (!DecodePasswordHashRecord(encodedhash, &record, &encoding))
170 return false; 177 return false;
171 178
172 std::string password_hash; 179 std::string password_hash;
173 const char* password_saved; 180 const char* password_saved;
174 const char* password_check; 181 const char* password_check;
175 size_t password_length; 182 size_t password_length;
176 183
177 if (encoding == '1') { 184 if (encoding == '1') {
bcwhite 2015/01/21 21:04:40 The handling of v1 encoding should never change.
Mike Lerman 2015/01/27 21:02:26 Done.
178 // Validate correct length; extract salt and password hash. 185 // Extract salt.
179 if (record.length() != 2 * kHash1Bytes)
180 return false;
181 std::string salt_str(record.data(), kHash1Bytes); 186 std::string salt_str(record.data(), kHash1Bytes);
182 password_saved = record.data() + kHash1Bytes; 187 password_saved = record.data() + kHash1Bytes;
183 password_hash = CreateSecurePasswordHash(salt_str, password, encoding); 188 // Extract password hash.
189 if (record.length() == 2 * kHash1Bytes) {
190 password_hash = CreateSecurePasswordHash(salt_str, password, encoding);
191 password_length = kHash1Bytes;
192 update_stored_credential = true;
193 } else if (record.length() == kHash1Bytes + kHash1StoredBytes) {
194 password_hash = CreateSecurePasswordHash(salt_str, password, encoding);
jww 2015/01/22 21:48:18 Given bcwhite's comment about never changing the h
bcwhite 2015/01/23 01:28:38 I didn't pass an encoding version to "create" beca
jww 2015/01/26 18:31:51 CreateSecurePasswordHash() is used to validate the
bcwhite 2015/01/27 18:02:25 I guess I always imagined that a new method would
Mike Lerman 2015/01/27 21:02:26 Ok, CreateSecurePasswordHash will call Truncate.
195 password_hash = TruncateStringByBits(password_hash, kHash1StoredBits);
196 password_length = kHash1StoredBytes;
197 } else {
198 // Unknown record length.
199 return false;
200 }
184 password_check = password_hash.data(); 201 password_check = password_hash.data();
185 password_length = kHash1Bytes;
186 } else { 202 } else {
187 // unknown encoding 203 // Unknown encoding.
188 return false; 204 return false;
189 } 205 }
190 206
191 return crypto::SecureMemEqual(password_saved, password_check, 207 bool passwords_match = crypto::SecureMemEqual(
192 password_length); 208 password_saved, password_check, password_length);
209 if (passwords_match && update_stored_credential)
210 SetLocalAuthCredentials(info_index, password);
211 return passwords_match;
193 } 212 }
194 213
195 bool ValidateLocalAuthCredentials(const Profile* profile, 214 bool ValidateLocalAuthCredentials(const Profile* profile,
196 const std::string& password) { 215 const std::string& password) {
197 return ValidateLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), 216 return ValidateLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile),
198 password); 217 password);
199 } 218 }
200 219
220 std::string TruncateStringByBits(const std::string& str,
bcwhite 2015/01/21 21:04:40 Rest of the file calls upward so put this function
Mike Lerman 2015/01/27 21:02:26 Done.
221 const size_t len_bits) {
222 if (len_bits % 8 == 0)
223 return str.substr(0, len_bits / 8);
224
225 // The initial truncation copies whole bytes
226 int number_bytes = (len_bits + 7) / 8;
227 std::string truncated_string = str.substr(0, number_bytes);
228
229 // Keep the prescribed number of bits from the last byte.
230 unsigned last_char_bitmask = pow(2, len_bits % 8) - 1;
bcwhite 2015/01/21 21:04:40 pow(2, len_bits % 8) == (1 << (len_bits % 8))
Mike Lerman 2015/01/27 21:02:26 Done.
231 truncated_string[number_bytes - 1] &= last_char_bitmask;
232 return truncated_string;
233 }
234
201 } // namespace chrome 235 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698