// 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 "base/base64.h" #include "base/logging.h" #include "base/memory/scoped_ptr.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::StringToLowerASCII(base::HexEncode( reinterpret_cast<const void*>(hash), sizeof(hash) / 2)); break; } case KEY_TYPE_SALTED_PBKDF2_AES256_1234: { scoped_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