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

Side by Side Diff: chrome/browser/chromeos/login/parallel_authenticator.cc

Issue 3442009: [Chrome OS] Attempt offline and online login simultaneously (Closed)
Patch Set: Fix crash on data recover Created 10 years, 2 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
(Empty)
1 // Copyright (c) 2010 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/chromeos/login/parallel_authenticator.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/file_path.h"
11 #include "base/file_util.h"
12 #include "base/lock.h"
13 #include "base/logging.h"
14 #include "base/path_service.h"
15 #include "base/sha2.h"
16 #include "base/string_util.h"
17 #include "base/third_party/nss/blapi.h"
18 #include "base/third_party/nss/sha256.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_thread.h"
21 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
22 #include "chrome/browser/chromeos/login/auth_response_handler.h"
23 #include "chrome/browser/chromeos/login/authentication_notification_details.h"
24 #include "chrome/browser/chromeos/login/login_status_consumer.h"
25 #include "chrome/browser/chromeos/login/ownership_service.h"
26 #include "chrome/browser/profile.h"
27 #include "chrome/browser/profile_manager.h"
28 #include "chrome/common/chrome_paths.h"
29 #include "chrome/common/net/gaia/gaia_authenticator2.h"
30 #include "chrome/common/net/gaia/gaia_constants.h"
31 #include "chrome/common/notification_service.h"
32 #include "net/base/load_flags.h"
33 #include "net/base/net_errors.h"
34 #include "net/url_request/url_request_status.h"
35 #include "third_party/libjingle/source/talk/base/urlencode.h"
36
37 using base::Time;
38 using base::TimeDelta;
39 using file_util::GetFileSize;
40 using file_util::PathExists;
41 using file_util::ReadFile;
42 using file_util::ReadFileToString;
43
44 namespace chromeos {
45
46 // static
47 const char ParallelAuthenticator::kLocalaccountFile[] = "localaccount";
48
49 // static
50 const int ParallelAuthenticator::kClientLoginTimeoutMs = 10000;
51 // static
52 const int ParallelAuthenticator::kLocalaccountRetryIntervalMs = 20;
53
54 const int kPassHashLen = 32;
55
56 ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer)
57 : Authenticator(consumer),
58 already_reported_success_(false),
59 checked_for_localaccount_(false) {
60 CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
61 // If not already owned, this is a no-op. If it is, this loads the owner's
62 // public key off of disk.
63 OwnershipService::GetSharedInstance()->StartLoadOwnerKeyAttempt();
64 }
65
66 ParallelAuthenticator::~ParallelAuthenticator() {}
67
68 bool ParallelAuthenticator::AuthenticateToLogin(
69 Profile* profile,
70 const std::string& username,
71 const std::string& password,
72 const std::string& login_token,
73 const std::string& login_captcha) {
74 current_state_.reset(
75 new AuthAttemptState(Authenticator::Canonicalize(username),
76 password,
77 HashPassword(password),
78 login_token,
79 login_captcha));
80 mounter_ = CryptohomeOp::CreateMountAttempt(current_state_.get(),
81 this,
82 false /* don't create */);
83 current_online_ = new OnlineAttempt(current_state_.get(), this);
84 // Sadly, this MUST be on the UI thread due to sending DBus traffic :-/
85 ChromeThread::PostTask(
86 ChromeThread::UI, FROM_HERE,
87 NewRunnableMethod(mounter_.get(), &CryptohomeOp::Initiate));
88 ChromeThread::PostTask(
89 ChromeThread::IO, FROM_HERE,
90 NewRunnableMethod(current_online_.get(),
91 &OnlineAttempt::Initiate,
92 profile));
93 ChromeThread::PostTask(
94 ChromeThread::FILE, FROM_HERE,
95 NewRunnableMethod(this,
96 &ParallelAuthenticator::LoadLocalaccount,
97 std::string(kLocalaccountFile)));
98 return true;
99 }
100
101 bool ParallelAuthenticator::AuthenticateToUnlock(const std::string& username,
102 const std::string& password) {
103 current_state_.reset(
104 new AuthAttemptState(Authenticator::Canonicalize(username),
105 HashPassword(password)));
106 ChromeThread::PostTask(
107 ChromeThread::FILE, FROM_HERE,
108 NewRunnableMethod(this,
109 &ParallelAuthenticator::LoadLocalaccount,
110 std::string(kLocalaccountFile)));
111 key_checker_ = CryptohomeOp::CreateCheckKeyAttempt(current_state_.get(),
112 this);
113 // Sadly, this MUST be on the UI thread due to sending DBus traffic :-/
114 ChromeThread::PostTask(
115 ChromeThread::UI, FROM_HERE,
116 NewRunnableMethod(key_checker_.get(), &CryptohomeOp::Initiate));
117 return true;
118 }
119
120 void ParallelAuthenticator::LoginOffTheRecord() {
121 current_state_.reset(new AuthAttemptState("", "", "", "", ""));
122 guest_mounter_ =
123 CryptohomeOp::CreateMountGuestAttempt(current_state_.get(), this);
124 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
125 guest_mounter_->Initiate();
126 }
127
128 void ParallelAuthenticator::OnLoginSuccess(
129 const GaiaAuthConsumer::ClientLoginResult& credentials,
130 bool request_pending) {
131 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
132 LOG(INFO) << "Online login success";
133 // Send notification of success
134 AuthenticationNotificationDetails details(true);
135 NotificationService::current()->Notify(
136 NotificationType::LOGIN_AUTHENTICATION,
137 NotificationService::AllSources(),
138 Details<AuthenticationNotificationDetails>(&details));
139 {
140 AutoLock for_this_block(success_lock_);
141 already_reported_success_ = true;
142 }
143 consumer_->OnLoginSuccess(current_state_->username,
144 credentials,
145 request_pending);
146 }
147
148 void ParallelAuthenticator::OnOffTheRecordLoginSuccess() {
149 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
150 // Send notification of success
151 AuthenticationNotificationDetails details(true);
152 NotificationService::current()->Notify(
153 NotificationType::LOGIN_AUTHENTICATION,
154 NotificationService::AllSources(),
155 Details<AuthenticationNotificationDetails>(&details));
156 consumer_->OnOffTheRecordLoginSuccess();
157 }
158
159 void ParallelAuthenticator::OnPasswordChangeDetected(
160 const GaiaAuthConsumer::ClientLoginResult& credentials) {
161 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
162 consumer_->OnPasswordChangeDetected(credentials);
163 }
164
165 void ParallelAuthenticator::CheckLocalaccount(const LoginFailure& error) {
166 {
167 AutoLock for_this_block(localaccount_lock_);
168 LOG(INFO) << "Checking localaccount";
169 if (!checked_for_localaccount_) {
170 ChromeThread::PostDelayedTask(
171 ChromeThread::FILE, FROM_HERE,
172 NewRunnableMethod(this,
173 &ParallelAuthenticator::CheckLocalaccount,
174 error),
175 kLocalaccountRetryIntervalMs);
176 return;
177 }
178 }
179
180 if (!localaccount_.empty() && localaccount_ == current_state_->username) {
181 // Success. Go mount a tmpfs for the profile, if necessary.
182 if (!current_state_->unlock) {
183 guest_mounter_ =
184 CryptohomeOp::CreateMountGuestAttempt(current_state_.get(), this);
185 ChromeThread::PostTask(
186 ChromeThread::UI, FROM_HERE,
187 NewRunnableMethod(guest_mounter_.get(), &CryptohomeOp::Initiate));
188 } else {
189 ChromeThread::PostTask(
190 ChromeThread::UI, FROM_HERE,
191 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
192 GaiaAuthConsumer::ClientLoginResult(), false));
193 }
194 } else {
195 // Not the localaccount. Fail, passing along cached error info.
196 ChromeThread::PostTask(
197 ChromeThread::UI, FROM_HERE,
198 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure, error));
199 }
200 }
201
202 void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) {
203 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
204 // Send notification of failure
205 AuthenticationNotificationDetails details(false);
206 NotificationService::current()->Notify(
207 NotificationType::LOGIN_AUTHENTICATION,
208 NotificationService::AllSources(),
209 Details<AuthenticationNotificationDetails>(&details));
210 LOG(WARNING) << "Login failed: " << error.GetErrorString();
211 consumer_->OnLoginFailure(error);
212 }
213
214 void ParallelAuthenticator::RecoverEncryptedData(
215 const std::string& old_password,
216 const GaiaAuthConsumer::ClientLoginResult& credentials) {
217 std::string old_hash = HashPassword(old_password);
218 key_migrator_ = CryptohomeOp::CreateMigrateAttempt(current_state_.get(),
219 this,
220 true,
221 old_hash);
222 ChromeThread::PostTask(
223 ChromeThread::IO, FROM_HERE,
224 NewRunnableMethod(this,
225 &ParallelAuthenticator::ResyncRecoverHelper,
226 key_migrator_.get()));
227 }
228
229 void ParallelAuthenticator::ResyncEncryptedData(
230 const GaiaAuthConsumer::ClientLoginResult& credentials) {
231 data_remover_ =
232 CryptohomeOp::CreateRemoveAttempt(current_state_.get(), this);
233 ChromeThread::PostTask(
234 ChromeThread::IO, FROM_HERE,
235 NewRunnableMethod(this,
236 &ParallelAuthenticator::ResyncRecoverHelper,
237 data_remover_.get()));
238 }
239
240 void ParallelAuthenticator::ResyncRecoverHelper(CryptohomeOp* to_initiate) {
241 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
242 current_state_->ResetCryptohomeStatus();
243 ChromeThread::PostTask(
244 ChromeThread::UI, FROM_HERE,
245 NewRunnableMethod(to_initiate, &CryptohomeOp::Initiate));
246 }
247
248 void ParallelAuthenticator::RetryAuth(Profile* profile,
249 const std::string& username,
250 const std::string& password,
251 const std::string& login_token,
252 const std::string& login_captcha) {
253 reauth_state_.reset(
254 new AuthAttemptState(Authenticator::Canonicalize(username),
255 password,
256 HashPassword(password),
257 login_token,
258 login_captcha));
259 current_online_ = new OnlineAttempt(reauth_state_.get(), this);
260 ChromeThread::PostTask(
261 ChromeThread::IO, FROM_HERE,
262 NewRunnableMethod(current_online_.get(),
263 &OnlineAttempt::Initiate,
264 profile));
265 }
266
267 void ParallelAuthenticator::Resolve() {
268 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
269 bool request_pending = false;
270 bool create = false;
271 switch (ResolveState()) {
272 case CONTINUE:
273 case POSSIBLE_PW_CHANGE:
274 case NO_MOUNT:
275 // These are intermediate states; we need more info from a request that
276 // is still pending.
277 break;
278 case FAILED_MOUNT:
279 // In this case, whether login succeeded or not, we can't log
280 // the user in because their data is horked. So, override with
281 // the appropriate failure.
282 ChromeThread::PostTask(
283 ChromeThread::UI, FROM_HERE,
284 NewRunnableMethod(
285 this,
286 &ParallelAuthenticator::OnLoginFailure,
287 LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
288 break;
289 case FAILED_REMOVE:
290 // In this case, we tried to remove the user's old cryptohome at her
291 // request, and the remove failed.
292 ChromeThread::PostTask(
293 ChromeThread::UI, FROM_HERE,
294 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure,
295 LoginFailure(LoginFailure::DATA_REMOVAL_FAILED)));
296 break;
297 case FAILED_TMPFS:
298 // In this case, we tried to mount a tmpfs for BWSI or the localaccount
299 // user and failed.
300 ChromeThread::PostTask(
301 ChromeThread::UI, FROM_HERE,
302 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure,
303 LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS)));
304 break;
305 case CREATE_NEW:
306 create = true;
307 case RECOVER_MOUNT:
308 current_state_->ResetCryptohomeStatus();
309 mounter_ = CryptohomeOp::CreateMountAttempt(current_state_.get(),
310 this,
311 create);
312 ChromeThread::PostTask(
313 ChromeThread::UI, FROM_HERE,
314 NewRunnableMethod(mounter_.get(), &CryptohomeOp::Initiate));
315 break;
316 case NEED_OLD_PW:
317 ChromeThread::PostTask(
318 ChromeThread::UI, FROM_HERE,
319 NewRunnableMethod(this,
320 &ParallelAuthenticator::OnPasswordChangeDetected,
321 current_state_->credentials()));
322 break;
323 case ONLINE_FAILED:
324 // In this case, we know online login was rejected because the account
325 // is disabled or something similarly fatal. Sending the user through
326 // the same path they get when their password is rejected is cleaner
327 // for now.
328 // TODO(cmasone): optimize this so that we don't send the user through
329 // the 'changed password' path when we know doing so won't succeed.
330 case NEED_NEW_PW:
331 {
332 AutoLock for_this_block(success_lock_);
333 if (!already_reported_success_) {
334 // This allows us to present the same behavior for "online:
335 // fail, offline: ok", regardless of the order in which we
336 // receive the results. There will be cases in which we get
337 // the online failure some time after the offline success,
338 // so we just force all cases in this category to present like this:
339 // OnLoginSuccess(..., ..., true) -> OnLoginFailure().
340 ChromeThread::PostTask(
341 ChromeThread::UI, FROM_HERE,
342 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
343 current_state_->credentials(), true));
344 }
345 }
346 ChromeThread::PostTask(
347 ChromeThread::UI, FROM_HERE,
348 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure,
349 current_state_->online_outcome()));
350 break;
351 case HAVE_NEW_PW:
352 key_migrator_ =
353 CryptohomeOp::CreateMigrateAttempt(reauth_state_.get(),
354 this,
355 false,
356 reauth_state_->ascii_hash);
357 ChromeThread::PostTask(
358 ChromeThread::UI, FROM_HERE,
359 NewRunnableMethod(key_migrator_.get(), &CryptohomeOp::Initiate));
360 break;
361 case OFFLINE_LOGIN:
362 request_pending = !current_state_->online_complete();
363 // Fall through.
364 case UNLOCK:
365 // Fall through.
366 case ONLINE_LOGIN:
367 ChromeThread::PostTask(
368 ChromeThread::UI, FROM_HERE,
369 NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
370 current_state_->credentials(), request_pending));
371 break;
372 case LOCAL_LOGIN:
373 ChromeThread::PostTask(
374 ChromeThread::UI, FROM_HERE,
375 NewRunnableMethod(
376 this,
377 &ParallelAuthenticator::OnOffTheRecordLoginSuccess));
378 break;
379 case LOGIN_FAILED:
380 current_state_->ResetCryptohomeStatus();
381 ChromeThread::PostTask(
382 ChromeThread::FILE, FROM_HERE,
383 NewRunnableMethod(this, &ParallelAuthenticator::CheckLocalaccount,
384 current_state_->online_outcome()));
385 break;
386 default:
387 NOTREACHED();
388 break;
389 }
390 }
391
392 ParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() {
393 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
394 // If we haven't mounted the user's home dir yet, we can't be done.
395 // We never get past here if a cryptohome op is still pending.
396 // This is an important invariant.
397 if (!current_state_->cryptohome_complete())
398 return CONTINUE;
399
400 AuthState state = (reauth_state_.get() ? ResolveReauthState() : CONTINUE);
401 if (state != CONTINUE)
402 return state;
403
404 if (current_state_->cryptohome_outcome())
405 state = ResolveCryptohomeSuccessState();
406 else
407 state = ResolveCryptohomeFailureState();
408
409 DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds.
410 key_migrator_ = NULL;
411 data_remover_ = NULL;
412 guest_mounter_ = NULL;
413 key_checker_ = NULL;
414
415 if (state != POSSIBLE_PW_CHANGE &&
416 state != NO_MOUNT &&
417 state != OFFLINE_LOGIN)
418 return state;
419
420 if (current_state_->online_complete()) {
421 if (current_state_->online_outcome().reason() == LoginFailure::NONE) {
422 // Online attempt succeeded as well, so combine the results.
423 return ResolveOnlineSuccessState(state);
424 } else {
425 // Online login attempt was rejected or failed to occur.
426 return ResolveOnlineFailureState(state);
427 }
428 }
429 // if online isn't complete yet, just return the offline result.
430 return state;
431 }
432
433 ParallelAuthenticator::AuthState
434 ParallelAuthenticator::ResolveReauthState() {
435 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
436 if (reauth_state_->cryptohome_complete()) {
437 if (!reauth_state_->cryptohome_outcome()) {
438 // If we've tried to migrate and failed, log the error and just wait
439 // til next time the user logs in to migrate their cryptohome key.
440 LOG(ERROR) << "Failed to migrate cryptohome key: "
441 << reauth_state_->cryptohome_code();
442 }
443 reauth_state_.reset(NULL);
444 return ONLINE_LOGIN;
445 }
446 // Haven't tried the migrate yet, must be processing the online auth attempt.
447 if (!reauth_state_->online_complete()) {
448 NOTREACHED(); // Shouldn't be here at all, if online reauth isn't done!
449 return CONTINUE;
450 }
451 if (reauth_state_->online_outcome().reason() == LoginFailure::NONE)
452 return HAVE_NEW_PW;
453 else
454 return NEED_NEW_PW;
455 }
456
457 ParallelAuthenticator::AuthState
458 ParallelAuthenticator::ResolveCryptohomeFailureState() {
459 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
460 if (data_remover_.get()) {
461 return FAILED_REMOVE;
462 } else if (guest_mounter_.get()) {
463 return FAILED_TMPFS;
464 } else if (key_migrator_.get()) {
465 return NEED_OLD_PW;
466 } else if (key_checker_.get()) {
467 return LOGIN_FAILED;
468 } else if (current_state_->cryptohome_code() ==
469 chromeos::kCryptohomeMountErrorKeyFailure) {
470 // If we tried a mount but they used the wrong key, we may need to
471 // ask the user for her old password. We'll only know once we've
472 // done the online check.
473 return POSSIBLE_PW_CHANGE;
474 } else if (current_state_->cryptohome_code() ==
475 chromeos::kCryptohomeMountErrorUserDoesNotExist) {
476 // If we tried a mount but the user did not exist, then we should wait
477 // for online login to succeed and try again with the "create" flag set.
478 return NO_MOUNT;
479 } else {
480 return FAILED_MOUNT;
481 }
482 }
483
484 ParallelAuthenticator::AuthState
485 ParallelAuthenticator::ResolveCryptohomeSuccessState() {
486 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
487 if (data_remover_.get()) {
488 return CREATE_NEW;
489 } else if (guest_mounter_.get()) {
490 return LOCAL_LOGIN;
491 } else if (key_migrator_.get()) {
492 return RECOVER_MOUNT;
493 } else if (key_checker_.get()) {
494 return UNLOCK;
495 } else {
496 return OFFLINE_LOGIN;
497 }
498 }
499
500 ParallelAuthenticator::AuthState
501 ParallelAuthenticator::ResolveOnlineFailureState(
502 ParallelAuthenticator::AuthState offline_state) {
503 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
504 if (offline_state == OFFLINE_LOGIN) {
505 if (current_state_->online_outcome().error().state() ==
506 GoogleServiceAuthError::CONNECTION_FAILED) {
507 // Couldn't do an online check, so just go with the offline result.
508 return OFFLINE_LOGIN;
509 }
510 // Otherwise, online login was rejected!
511 if (current_state_->online_outcome().error().state() ==
512 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
513 return NEED_NEW_PW;
514 } else {
515 return ONLINE_FAILED;
516 }
517 }
518 return LOGIN_FAILED;
519 }
520
521 ParallelAuthenticator::AuthState
522 ParallelAuthenticator::ResolveOnlineSuccessState(
523 ParallelAuthenticator::AuthState offline_state) {
524 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
525 switch (offline_state) {
526 case POSSIBLE_PW_CHANGE:
527 return NEED_OLD_PW;
528 case NO_MOUNT:
529 return CREATE_NEW;
530 case OFFLINE_LOGIN:
531 return ONLINE_LOGIN;
532 default:
533 NOTREACHED();
534 return offline_state;
535 }
536 }
537
538 void ParallelAuthenticator::LoadSystemSalt() {
539 if (!system_salt_.empty())
540 return;
541 system_salt_ = CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt();
542 CHECK(!system_salt_.empty());
543 CHECK_EQ(system_salt_.size() % 2, 0U);
544 }
545
546 void ParallelAuthenticator::LoadLocalaccount(const std::string& filename) {
547 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
548 {
549 AutoLock for_this_block(localaccount_lock_);
550 if (checked_for_localaccount_)
551 return;
552 }
553 FilePath localaccount_file;
554 std::string localaccount;
555 if (PathService::Get(base::DIR_EXE, &localaccount_file)) {
556 localaccount_file = localaccount_file.Append(filename);
557 LOG(INFO) << "looking for localaccount in " << localaccount_file.value();
558
559 ReadFileToString(localaccount_file, &localaccount);
560 TrimWhitespaceASCII(localaccount, TRIM_TRAILING, &localaccount);
561 LOG(INFO) << "Loading localaccount: " << localaccount;
562 } else {
563 LOG(INFO) << "Assuming no localaccount";
564 }
565 SetLocalaccount(localaccount);
566 }
567
568 void ParallelAuthenticator::SetLocalaccount(const std::string& new_name) {
569 localaccount_ = new_name;
570 { // extra braces for clarity about AutoLock scope.
571 AutoLock for_this_block(localaccount_lock_);
572 checked_for_localaccount_ = true;
573 }
574 }
575
576
577 std::string ParallelAuthenticator::HashPassword(const std::string& password) {
578 // Get salt, ascii encode, update sha with that, then update with ascii
579 // of password, then end.
580 std::string ascii_salt = SaltAsAscii();
581 unsigned char passhash_buf[kPassHashLen];
582 char ascii_buf[kPassHashLen + 1];
583
584 // Hash salt and password
585 SHA256Context ctx;
586 SHA256_Begin(&ctx);
587 SHA256_Update(&ctx,
588 reinterpret_cast<const unsigned char*>(ascii_salt.data()),
589 static_cast<unsigned int>(ascii_salt.length()));
590 SHA256_Update(&ctx,
591 reinterpret_cast<const unsigned char*>(password.data()),
592 static_cast<unsigned int>(password.length()));
593 SHA256_End(&ctx,
594 passhash_buf,
595 NULL,
596 static_cast<unsigned int>(sizeof(passhash_buf)));
597
598 std::vector<unsigned char> passhash(passhash_buf,
599 passhash_buf + sizeof(passhash_buf));
600 BinaryToHex(passhash,
601 passhash.size() / 2, // only want top half, at least for now.
602 ascii_buf,
603 sizeof(ascii_buf));
604 return std::string(ascii_buf, sizeof(ascii_buf) - 1);
605 }
606
607 std::string ParallelAuthenticator::SaltAsAscii() {
608 LoadSystemSalt(); // no-op if it's already loaded.
609 unsigned int salt_len = system_salt_.size();
610 char ascii_salt[2 * salt_len + 1];
611 if (ParallelAuthenticator::BinaryToHex(system_salt_,
612 salt_len,
613 ascii_salt,
614 sizeof(ascii_salt))) {
615 return std::string(ascii_salt, sizeof(ascii_salt) - 1);
616 } else {
617 return std::string();
618 }
619 }
620
621 // static
622 bool ParallelAuthenticator::BinaryToHex(
623 const std::vector<unsigned char>& binary,
624 const unsigned int binary_len,
625 char* hex_string,
626 const unsigned int len) {
627 if (len < 2*binary_len)
628 return false;
629 memset(hex_string, 0, len);
630 for (uint i = 0, j = 0; i < binary_len; i++, j+=2)
631 snprintf(hex_string + j, len - j, "%02x", binary[i]);
632 return true;
633 }
634
635 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698