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
15namespace chromeos {
16
17namespace {
18
19// Parameters for the transformation to KEY_TYPE_SALTED_AES256_1234.
20const int kNumIterations = 1234;
21const int kKeySizeInBits = 256;
22
23}  // namespace
24
25Key::Key() : key_type_(KEY_TYPE_PASSWORD_PLAIN) {
26}
27
28Key::Key(const Key& other)
29    : key_type_(other.key_type_),
30      salt_(other.salt_),
31      secret_(other.secret_),
32      label_(other.label_) {
33}
34
35Key::Key(const std::string& plain_text_password)
36    : key_type_(KEY_TYPE_PASSWORD_PLAIN), secret_(plain_text_password) {
37}
38
39Key::Key(KeyType key_type, const std::string& salt, const std::string& secret)
40    : key_type_(key_type), salt_(salt), secret_(secret) {
41}
42
43Key::~Key() {
44}
45
46bool 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
51Key::KeyType Key::GetKeyType() const {
52  return key_type_;
53}
54
55const std::string& Key::GetSecret() const {
56  return secret_;
57}
58
59const std::string& Key::GetLabel() const {
60  return label_;
61}
62
63void Key::SetLabel(const std::string& label) {
64  label_ = label;
65}
66
67void Key::ClearSecret() {
68  secret_.clear();
69}
70
71void 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