Makes the is_blocking method public.
[chromium-blink-merge.git] / chromeos / cryptohome / cryptohome_library.cc
blobae045606a46c887e50d61cbe60e9c8c6d01075cd
1 // Copyright (c) 2012 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.
5 #include "chromeos/cryptohome/cryptohome_library.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/chromeos/chromeos_version.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "chromeos/dbus/cryptohome_client.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "crypto/encryptor.h"
17 #include "crypto/nss_util.h"
18 #include "crypto/sha2.h"
19 #include "crypto/symmetric_key.h"
21 namespace chromeos {
23 namespace {
25 const char kStubSystemSalt[] = "stub_system_salt";
26 const size_t kNonceSize = 16;
28 // Does nothing. Used as a Cryptohome::VoidMethodCallback.
29 void DoNothing(DBusMethodCallStatus call_status) {}
31 } // namespace
33 // This class handles the interaction with the ChromeOS cryptohome library APIs.
34 class CryptohomeLibraryImpl : public CryptohomeLibrary {
35 public:
36 CryptohomeLibraryImpl() : weak_ptr_factory_(this) {
39 virtual ~CryptohomeLibraryImpl() {
42 virtual bool TpmIsEnabled() OVERRIDE {
43 bool result = false;
44 DBusThreadManager::Get()->GetCryptohomeClient()->CallTpmIsEnabledAndBlock(
45 &result);
46 return result;
49 virtual bool TpmIsOwned() OVERRIDE {
50 bool result = false;
51 DBusThreadManager::Get()->GetCryptohomeClient()->CallTpmIsOwnedAndBlock(
52 &result);
53 return result;
56 virtual bool TpmIsBeingOwned() OVERRIDE {
57 bool result = false;
58 DBusThreadManager::Get()->GetCryptohomeClient()->
59 CallTpmIsBeingOwnedAndBlock(&result);
60 return result;
63 virtual void TpmCanAttemptOwnership() OVERRIDE {
64 DBusThreadManager::Get()->GetCryptohomeClient()->TpmCanAttemptOwnership(
65 base::Bind(&DoNothing));
68 virtual void TpmClearStoredPassword() OVERRIDE {
69 DBusThreadManager::Get()->GetCryptohomeClient()->
70 CallTpmClearStoredPasswordAndBlock();
73 virtual bool InstallAttributesGet(
74 const std::string& name, std::string* value) OVERRIDE {
75 std::vector<uint8> buf;
76 bool success = false;
77 DBusThreadManager::Get()->GetCryptohomeClient()->
78 InstallAttributesGet(name, &buf, &success);
79 if (success) {
80 // Cryptohome returns 'buf' with a terminating '\0' character.
81 DCHECK(!buf.empty());
82 DCHECK_EQ(buf.back(), 0);
83 value->assign(reinterpret_cast<char*>(buf.data()), buf.size() - 1);
85 return success;
88 virtual bool InstallAttributesSet(
89 const std::string& name, const std::string& value) OVERRIDE {
90 std::vector<uint8> buf(value.c_str(), value.c_str() + value.size() + 1);
91 bool success = false;
92 DBusThreadManager::Get()->GetCryptohomeClient()->
93 InstallAttributesSet(name, buf, &success);
94 return success;
97 virtual bool InstallAttributesFinalize() OVERRIDE {
98 bool success = false;
99 DBusThreadManager::Get()->GetCryptohomeClient()->
100 InstallAttributesFinalize(&success);
101 return success;
104 virtual bool InstallAttributesIsInvalid() OVERRIDE {
105 bool result = false;
106 DBusThreadManager::Get()->GetCryptohomeClient()->
107 InstallAttributesIsInvalid(&result);
108 return result;
111 virtual bool InstallAttributesIsFirstInstall() OVERRIDE {
112 bool result = false;
113 DBusThreadManager::Get()->GetCryptohomeClient()->
114 InstallAttributesIsFirstInstall(&result);
115 return result;
118 virtual std::string GetSystemSalt() OVERRIDE {
119 LoadSystemSalt(); // no-op if it's already loaded.
120 return StringToLowerASCII(base::HexEncode(
121 reinterpret_cast<const void*>(system_salt_.data()),
122 system_salt_.size()));
125 virtual std::string EncryptWithSystemSalt(const std::string& token) OVERRIDE {
126 // Don't care about token encryption while debugging.
127 if (!base::chromeos::IsRunningOnChromeOS())
128 return token;
130 if (!LoadSystemSaltKey()) {
131 LOG(WARNING) << "System salt key is not available for encrypt.";
132 return std::string();
134 return EncryptTokenWithKey(system_salt_key_.get(),
135 GetSystemSalt(),
136 token);
139 virtual std::string DecryptWithSystemSalt(
140 const std::string& encrypted_token_hex) OVERRIDE {
141 // Don't care about token encryption while debugging.
142 if (!base::chromeos::IsRunningOnChromeOS())
143 return encrypted_token_hex;
145 if (!LoadSystemSaltKey()) {
146 LOG(WARNING) << "System salt key is not available for decrypt.";
147 return std::string();
149 return DecryptTokenWithKey(system_salt_key_.get(),
150 GetSystemSalt(),
151 encrypted_token_hex);
154 private:
155 void LoadSystemSalt() {
156 if (!system_salt_.empty())
157 return;
158 DBusThreadManager::Get()->GetCryptohomeClient()->
159 GetSystemSalt(&system_salt_);
160 CHECK(!system_salt_.empty());
161 CHECK_EQ(system_salt_.size() % 2, 0U);
164 // TODO: should this use the system salt for both the password and the salt
165 // value, or should this use a separate salt value?
166 bool LoadSystemSaltKey() {
167 if (!system_salt_key_.get())
168 system_salt_key_.reset(PassphraseToKey(GetSystemSalt(), GetSystemSalt()));
169 return system_salt_key_.get();
172 crypto::SymmetricKey* PassphraseToKey(const std::string& passphrase,
173 const std::string& salt) {
174 return crypto::SymmetricKey::DeriveKeyFromPassword(
175 crypto::SymmetricKey::AES, passphrase, salt, 1000, 256);
179 // Encrypts (AES) the token given |key| and |salt|.
180 std::string EncryptTokenWithKey(crypto::SymmetricKey* key,
181 const std::string& salt,
182 const std::string& token) {
183 crypto::Encryptor encryptor;
184 if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) {
185 LOG(WARNING) << "Failed to initialize Encryptor.";
186 return std::string();
188 std::string nonce = salt.substr(0, kNonceSize);
189 std::string encoded_token;
190 CHECK(encryptor.SetCounter(nonce));
191 if (!encryptor.Encrypt(token, &encoded_token)) {
192 LOG(WARNING) << "Failed to encrypt token.";
193 return std::string();
196 return StringToLowerASCII(base::HexEncode(
197 reinterpret_cast<const void*>(encoded_token.data()),
198 encoded_token.size()));
201 // Decrypts (AES) hex encoded encrypted token given |key| and |salt|.
202 std::string DecryptTokenWithKey(crypto::SymmetricKey* key,
203 const std::string& salt,
204 const std::string& encrypted_token_hex) {
205 std::vector<uint8> encrypted_token_bytes;
206 if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) {
207 LOG(WARNING) << "Corrupt encrypted token found.";
208 return std::string();
211 std::string encrypted_token(
212 reinterpret_cast<char*>(encrypted_token_bytes.data()),
213 encrypted_token_bytes.size());
214 crypto::Encryptor encryptor;
215 if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) {
216 LOG(WARNING) << "Failed to initialize Encryptor.";
217 return std::string();
220 std::string nonce = salt.substr(0, kNonceSize);
221 std::string token;
222 CHECK(encryptor.SetCounter(nonce));
223 if (!encryptor.Decrypt(encrypted_token, &token)) {
224 LOG(WARNING) << "Failed to decrypt token.";
225 return std::string();
227 return token;
230 base::WeakPtrFactory<CryptohomeLibraryImpl> weak_ptr_factory_;
231 std::vector<uint8> system_salt_;
232 // A key based on the system salt. Useful for encrypting device-level
233 // data for which we have no additional credentials.
234 scoped_ptr<crypto::SymmetricKey> system_salt_key_;
236 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl);
239 class CryptohomeLibraryStubImpl : public CryptohomeLibrary {
240 public:
241 CryptohomeLibraryStubImpl()
242 : locked_(false) {}
243 virtual ~CryptohomeLibraryStubImpl() {}
245 virtual bool TpmIsEnabled() OVERRIDE {
246 return true;
249 virtual bool TpmIsOwned() OVERRIDE {
250 return true;
253 virtual bool TpmIsBeingOwned() OVERRIDE {
254 return true;
257 virtual void TpmCanAttemptOwnership() OVERRIDE {}
259 virtual void TpmClearStoredPassword() OVERRIDE {}
261 virtual bool InstallAttributesGet(
262 const std::string& name, std::string* value) OVERRIDE {
263 if (install_attrs_.find(name) != install_attrs_.end()) {
264 *value = install_attrs_[name];
265 return true;
267 return false;
270 virtual bool InstallAttributesSet(
271 const std::string& name, const std::string& value) OVERRIDE {
272 install_attrs_[name] = value;
273 return true;
276 virtual bool InstallAttributesFinalize() OVERRIDE {
277 locked_ = true;
278 return true;
281 virtual bool InstallAttributesIsInvalid() OVERRIDE {
282 return false;
285 virtual bool InstallAttributesIsFirstInstall() OVERRIDE {
286 return !locked_;
289 virtual std::string GetSystemSalt() OVERRIDE {
290 return kStubSystemSalt;
293 virtual std::string EncryptWithSystemSalt(const std::string& token) OVERRIDE {
294 return token;
297 virtual std::string DecryptWithSystemSalt(
298 const std::string& encrypted_token_hex) OVERRIDE {
299 return encrypted_token_hex;
302 private:
303 std::map<std::string, std::string> install_attrs_;
304 bool locked_;
305 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl);
308 CryptohomeLibrary::CryptohomeLibrary() {}
309 CryptohomeLibrary::~CryptohomeLibrary() {}
311 static CryptohomeLibrary* g_cryptohome_library = NULL;
312 static CryptohomeLibrary* g_test_cryptohome_library = NULL;
314 // static
315 void CryptohomeLibrary::Initialize() {
316 CHECK(!g_cryptohome_library);
317 if (base::chromeos::IsRunningOnChromeOS())
318 g_cryptohome_library = new CryptohomeLibraryImpl();
319 else
320 g_cryptohome_library = new CryptohomeLibraryStubImpl();
323 // static
324 bool CryptohomeLibrary::IsInitialized() {
325 return g_cryptohome_library;
328 // static
329 void CryptohomeLibrary::Shutdown() {
330 CHECK(g_cryptohome_library);
331 delete g_cryptohome_library;
332 g_cryptohome_library = NULL;
335 // static
336 CryptohomeLibrary* CryptohomeLibrary::Get() {
337 CHECK(g_cryptohome_library || g_test_cryptohome_library)
338 << "CryptohomeLibrary::Get() called before Initialize()";
339 if (g_test_cryptohome_library)
340 return g_test_cryptohome_library;
341 return g_cryptohome_library;
344 // static
345 void CryptohomeLibrary::SetForTest(CryptohomeLibrary* impl) {
346 CHECK(!g_test_cryptohome_library || !impl);
347 g_test_cryptohome_library = impl;
350 // static
351 CryptohomeLibrary* CryptohomeLibrary::GetTestImpl() {
352 return new CryptohomeLibraryStubImpl();
355 } // namespace chromeos