普通文本  |  119行  |  3.23 KB

// 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