blob: e9dada20f0af13d8cc4f131c35346ed2d4c293c8 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/login/auth/key.h"
#include <memory>
#include "base/base64.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "crypto/sha2.h"
#include "crypto/symmetric_key.h"
namespace chromeos {
namespace {
// Parameters for the transformation to KEY_TYPE_SALTED_AES256_1234.
const int kNumIterations = 1234;
const int kKeySizeInBits = 256;
} // namespace
Key::Key() : key_type_(KEY_TYPE_PASSWORD_PLAIN) {
}
Key::Key(const Key& other)
: key_type_(other.key_type_),
salt_(other.salt_),
secret_(other.secret_),
label_(other.label_) {
}
Key::Key(const std::string& plain_text_password)
: key_type_(KEY_TYPE_PASSWORD_PLAIN), secret_(plain_text_password) {
}
Key::Key(KeyType key_type, const std::string& salt, const std::string& secret)
: key_type_(key_type), salt_(salt), secret_(secret) {
}
Key::~Key() {
}
bool Key::operator==(const Key& other) const {
return other.key_type_ == key_type_ && other.salt_ == salt_ &&
other.secret_ == secret_ && other.label_ == label_;
}
Key::KeyType Key::GetKeyType() const {
return key_type_;
}
const std::string& Key::GetSecret() const {
return secret_;
}
const std::string& Key::GetLabel() const {
return label_;
}
void Key::SetLabel(const std::string& label) {
label_ = label;
}
void Key::ClearSecret() {
secret_.clear();
}
void Key::Transform(KeyType target_key_type, const std::string& salt) {
if (key_type_ != KEY_TYPE_PASSWORD_PLAIN) {
NOTREACHED();
return;
}
switch (target_key_type) {
case KEY_TYPE_SALTED_SHA256_TOP_HALF: {
// TODO(stevenjb/nkostylev): Handle empty salt gracefully.
CHECK(!salt.empty());
char hash[crypto::kSHA256Length];
crypto::SHA256HashString(salt + secret_, &hash, sizeof(hash));
// Keep only the first half of the hash for 'weak' hashing so that the
// plain text secret cannot be reconstructed even if the hashing is
// reversed.
secret_ = base::ToLowerASCII(base::HexEncode(
reinterpret_cast<const void*>(hash), sizeof(hash) / 2));
break;
}
case KEY_TYPE_SALTED_PBKDF2_AES256_1234: {
std::unique_ptr<crypto::SymmetricKey> key(
crypto::SymmetricKey::DeriveKeyFromPassword(
crypto::SymmetricKey::AES, secret_, salt, kNumIterations,
kKeySizeInBits));
std::string raw_secret;
key->GetRawKey(&raw_secret);
base::Base64Encode(raw_secret, &secret_);
break;
}
case KEY_TYPE_SALTED_SHA256:
base::Base64Encode(crypto::SHA256HashString(salt + secret_), &secret_);
break;
default:
// The resulting key will be sent to cryptohomed. It should always be
// hashed. If hashing fails, crash instead of sending a plain-text key.
CHECK(false);
return;
}
key_type_ = target_key_type;
salt_ = salt;
}
} // namespace chromeos