1 // Copyright 2014 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/auth/key.h"
6
7 #include "base/base64.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "crypto/sha2.h"
13 #include "crypto/symmetric_key.h"
14
15 namespace chromeos {
16
17 namespace {
18
19 // Parameters for the transformation to KEY_TYPE_SALTED_AES256_1234.
20 const int kNumIterations = 1234;
21 const int kKeySizeInBits = 256;
22
23 } // namespace
24
Key()25 Key::Key() : key_type_(KEY_TYPE_PASSWORD_PLAIN) {
26 }
27
Key(const Key & other)28 Key::Key(const Key& other) : key_type_(other.key_type_),
29 salt_(other.salt_),
30 secret_(other.secret_),
31 label_(other.label_) {
32 }
33
Key(const std::string & plain_text_password)34 Key::Key(const std::string& plain_text_password)
35 : key_type_(KEY_TYPE_PASSWORD_PLAIN),
36 secret_(plain_text_password) {
37 }
38
Key(KeyType key_type,const std::string & salt,const std::string & secret)39 Key::Key(KeyType key_type, const std::string& salt, const std::string& secret)
40 : key_type_(key_type),
41 salt_(salt),
42 secret_(secret) {
43
44 }
45
~Key()46 Key::~Key() {
47 }
48
operator ==(const Key & other) const49 bool Key::operator==(const Key& other) const {
50 return other.key_type_ == key_type_ &&
51 other.salt_ == salt_ &&
52 other.secret_ == secret_ &&
53 other.label_ == label_;
54 }
55
GetKeyType() const56 Key::KeyType Key::GetKeyType() const {
57 return key_type_;
58 }
59
GetSecret() const60 const std::string& Key::GetSecret() const {
61 return secret_;
62 }
63
GetLabel() const64 const std::string& Key::GetLabel() const {
65 return label_;
66 }
67
SetLabel(const std::string & label)68 void Key::SetLabel(const std::string& label) {
69 label_ = label;
70 }
71
ClearSecret()72 void Key::ClearSecret() {
73 secret_.clear();
74 }
75
Transform(KeyType target_key_type,const std::string & salt)76 void Key::Transform(KeyType target_key_type, const std::string& salt) {
77 if (key_type_ != KEY_TYPE_PASSWORD_PLAIN) {
78 NOTREACHED();
79 return;
80 }
81
82 switch (target_key_type) {
83 case KEY_TYPE_SALTED_SHA256_TOP_HALF: {
84 // TODO(stevenjb/nkostylev): Handle empty salt gracefully.
85 CHECK(!salt.empty());
86 char hash[crypto::kSHA256Length];
87 crypto::SHA256HashString(salt + secret_, &hash, sizeof(hash));
88
89 // Keep only the first half of the hash for 'weak' hashing so that the
90 // plain text secret cannot be reconstructed even if the hashing is
91 // reversed.
92 secret_ = StringToLowerASCII(base::HexEncode(
93 reinterpret_cast<const void*>(hash), sizeof(hash) / 2));
94 break;
95 } case KEY_TYPE_SALTED_PBKDF2_AES256_1234: {
96 scoped_ptr<crypto::SymmetricKey> key(
97 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
98 secret_,
99 salt,
100 kNumIterations,
101 kKeySizeInBits));
102 std::string raw_secret;
103 key->GetRawKey(&raw_secret);
104 base::Base64Encode(raw_secret, &secret_);
105 break;
106 } default:
107 // The resulting key will be sent to cryptohomed. It should always be
108 // hashed. If hashing fails, crash instead of sending a plain-text key.
109 CHECK(false);
110 return;
111 }
112
113 key_type_ = target_key_type;
114 salt_ = salt;
115 }
116
117 } // namespace chromeos
118