Home | History | Annotate | Download | only in auth
      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 
     25 Key::Key() : key_type_(KEY_TYPE_PASSWORD_PLAIN) {
     26 }
     27 
     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 
     35 Key::Key(const std::string& plain_text_password)
     36     : key_type_(KEY_TYPE_PASSWORD_PLAIN), secret_(plain_text_password) {
     37 }
     38 
     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 
     43 Key::~Key() {
     44 }
     45 
     46 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 
     51 Key::KeyType Key::GetKeyType() const {
     52   return key_type_;
     53 }
     54 
     55 const std::string& Key::GetSecret() const {
     56   return secret_;
     57 }
     58 
     59 const std::string& Key::GetLabel() const {
     60   return label_;
     61 }
     62 
     63 void Key::SetLabel(const std::string& label) {
     64   label_ = label;
     65 }
     66 
     67 void Key::ClearSecret() {
     68   secret_.clear();
     69 }
     70 
     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