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 "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)
29 : key_type_(other.key_type_),
30 salt_(other.salt_),
31 secret_(other.secret_),
32 label_(other.label_) {
33 }
34
Key(const std::string & plain_text_password)35 Key::Key(const std::string& plain_text_password)
36 : key_type_(KEY_TYPE_PASSWORD_PLAIN), 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), salt_(salt), secret_(secret) {
41 }
42
~Key()43 Key::~Key() {
44 }
45
operator ==(const Key & other) const46 bool Key::operator==(const Key& other) const {
47 return other.key_type_ == key_type_ && other.salt_ == salt_ &&
48 other.secret_ == secret_ && other.label_ == label_;
49 }
50
GetKeyType() const51 Key::KeyType Key::GetKeyType() const {
52 return key_type_;
53 }
54
GetSecret() const55 const std::string& Key::GetSecret() const {
56 return secret_;
57 }
58
GetLabel() const59 const std::string& Key::GetLabel() const {
60 return label_;
61 }
62
SetLabel(const std::string & label)63 void Key::SetLabel(const std::string& label) {
64 label_ = label;
65 }
66
ClearSecret()67 void Key::ClearSecret() {
68 secret_.clear();
69 }
70
Transform(KeyType target_key_type,const std::string & salt)71 void Key::Transform(KeyType target_key_type, const std::string& salt) {
72 if (key_type_ != KEY_TYPE_PASSWORD_PLAIN) {
73 NOTREACHED();
74 return;
75 }
76
77 switch (target_key_type) {
78 case KEY_TYPE_SALTED_SHA256_TOP_HALF: {
79 // TODO(stevenjb/nkostylev): Handle empty salt gracefully.
80 CHECK(!salt.empty());
81 char hash[crypto::kSHA256Length];
82 crypto::SHA256HashString(salt + secret_, &hash, sizeof(hash));
83
84 // Keep only the first half of the hash for 'weak' hashing so that the
85 // plain text secret cannot be reconstructed even if the hashing is
86 // reversed.
87 secret_ = base::StringToLowerASCII(base::HexEncode(
88 reinterpret_cast<const void*>(hash), sizeof(hash) / 2));
89 break;
90 }
91 case KEY_TYPE_SALTED_PBKDF2_AES256_1234: {
92 scoped_ptr<crypto::SymmetricKey> key(
93 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
94 secret_,
95 salt,
96 kNumIterations,
97 kKeySizeInBits));
98 std::string raw_secret;
99 key->GetRawKey(&raw_secret);
100 base::Base64Encode(raw_secret, &secret_);
101 break;
102 }
103 case KEY_TYPE_SALTED_SHA256:
104 base::Base64Encode(crypto::SHA256HashString(salt + secret_), &secret_);
105 break;
106
107 default:
108 // The resulting key will be sent to cryptohomed. It should always be
109 // hashed. If hashing fails, crash instead of sending a plain-text key.
110 CHECK(false);
111 return;
112 }
113
114 key_type_ = target_key_type;
115 salt_ = salt;
116 }
117
118 } // namespace chromeos
119