token_encryptor.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright 2013 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 "chrome/browser/chromeos/settings/token_encryptor.h"
6
7#include <vector>
8
9#include "base/logging.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/string_util.h"
12#include "base/sys_info.h"
13#include "chromeos/cryptohome/cryptohome_library.h"
14#include "crypto/encryptor.h"
15#include "crypto/nss_util.h"
16#include "crypto/sha2.h"
17#include "crypto/symmetric_key.h"
18
19namespace chromeos {
20
21namespace {
22const size_t kNonceSize = 16;
23}  // namespace
24
25CryptohomeTokenEncryptor::CryptohomeTokenEncryptor() {
26}
27
28CryptohomeTokenEncryptor::~CryptohomeTokenEncryptor() {
29}
30
31std::string CryptohomeTokenEncryptor::EncryptWithSystemSalt(
32    const std::string& token) {
33  // Don't care about token encryption while debugging.
34  if (!base::SysInfo::IsRunningOnChromeOS())
35    return token;
36
37  if (!LoadSystemSaltKey()) {
38    LOG(WARNING) << "System salt key is not available for encrypt.";
39    return std::string();
40  }
41  return EncryptTokenWithKey(system_salt_key_.get(),
42                             system_salt_,
43                             token);
44}
45
46std::string CryptohomeTokenEncryptor::DecryptWithSystemSalt(
47    const std::string& encrypted_token_hex) {
48  // Don't care about token encryption while debugging.
49  if (!base::SysInfo::IsRunningOnChromeOS())
50    return encrypted_token_hex;
51
52  if (!LoadSystemSaltKey()) {
53    LOG(WARNING) << "System salt key is not available for decrypt.";
54    return std::string();
55  }
56  return DecryptTokenWithKey(system_salt_key_.get(),
57                             system_salt_,
58                             encrypted_token_hex);
59}
60
61// TODO: should this use the system salt for both the password and the salt
62// value, or should this use a separate salt value?
63bool CryptohomeTokenEncryptor::LoadSystemSaltKey() {
64  // Assume the system salt should be obtained beforehand at login time.
65  if (system_salt_.empty())
66    system_salt_ = CryptohomeLibrary::Get()->GetCachedSystemSalt();
67  if (system_salt_.empty())
68    return false;
69  if (!system_salt_key_.get())
70    system_salt_key_.reset(PassphraseToKey(system_salt_, system_salt_));
71  return system_salt_key_.get();
72}
73
74crypto::SymmetricKey* CryptohomeTokenEncryptor::PassphraseToKey(
75    const std::string& passphrase,
76    const std::string& salt) {
77  return crypto::SymmetricKey::DeriveKeyFromPassword(
78      crypto::SymmetricKey::AES, passphrase, salt, 1000, 256);
79}
80
81std::string CryptohomeTokenEncryptor::EncryptTokenWithKey(
82    crypto::SymmetricKey* key,
83    const std::string& salt,
84    const std::string& token) {
85  crypto::Encryptor encryptor;
86  if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) {
87    LOG(WARNING) << "Failed to initialize Encryptor.";
88    return std::string();
89  }
90  std::string nonce = salt.substr(0, kNonceSize);
91  std::string encoded_token;
92  CHECK(encryptor.SetCounter(nonce));
93  if (!encryptor.Encrypt(token, &encoded_token)) {
94    LOG(WARNING) << "Failed to encrypt token.";
95    return std::string();
96  }
97
98  return StringToLowerASCII(base::HexEncode(
99      reinterpret_cast<const void*>(encoded_token.data()),
100      encoded_token.size()));
101}
102
103std::string CryptohomeTokenEncryptor::DecryptTokenWithKey(
104    crypto::SymmetricKey* key,
105    const std::string& salt,
106    const std::string& encrypted_token_hex) {
107  std::vector<uint8> encrypted_token_bytes;
108  if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) {
109    LOG(WARNING) << "Corrupt encrypted token found.";
110    return std::string();
111  }
112
113  std::string encrypted_token(
114      reinterpret_cast<char*>(encrypted_token_bytes.data()),
115      encrypted_token_bytes.size());
116  crypto::Encryptor encryptor;
117  if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) {
118    LOG(WARNING) << "Failed to initialize Encryptor.";
119    return std::string();
120  }
121
122  std::string nonce = salt.substr(0, kNonceSize);
123  std::string token;
124  CHECK(encryptor.SetCounter(nonce));
125  if (!encryptor.Decrypt(encrypted_token, &token)) {
126    LOG(WARNING) << "Failed to decrypt token.";
127    return std::string();
128  }
129  return token;
130}
131
132}  // namespace chromeos
133