Move functions in cryptohome_util into a set of new files
[chromium-blink-merge.git] / chromeos / cryptohome / cryptohome_library.cc
blob721f932aa4ae5beb59a92cd253beaceddd29b62e
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/memory/weak_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/sys_info.h"
14 #include "chromeos/dbus/cryptohome_client.h"
15 #include "chromeos/dbus/dbus_method_call_status.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "crypto/encryptor.h"
18 #include "crypto/nss_util.h"
19 #include "crypto/sha2.h"
20 #include "crypto/symmetric_key.h"
22 namespace chromeos {
24 namespace {
26 const char kStubSystemSalt[] = "stub_system_salt";
27 const size_t kNonceSize = 16;
29 } // namespace
31 // This class handles the interaction with the ChromeOS cryptohome library APIs.
32 class CryptohomeLibraryImpl : public CryptohomeLibrary {
33 public:
34 CryptohomeLibraryImpl() {
37 virtual ~CryptohomeLibraryImpl() {
40 virtual std::string GetSystemSalt() OVERRIDE {
41 LoadSystemSalt(); // no-op if it's already loaded.
42 return system_salt_;
45 virtual std::string EncryptWithSystemSalt(const std::string& token) OVERRIDE {
46 // Don't care about token encryption while debugging.
47 if (!base::SysInfo::IsRunningOnChromeOS())
48 return token;
50 if (!LoadSystemSaltKey()) {
51 LOG(WARNING) << "System salt key is not available for encrypt.";
52 return std::string();
54 return EncryptTokenWithKey(system_salt_key_.get(),
55 system_salt_,
56 token);
59 virtual std::string DecryptWithSystemSalt(
60 const std::string& encrypted_token_hex) OVERRIDE {
61 // Don't care about token encryption while debugging.
62 if (!base::SysInfo::IsRunningOnChromeOS())
63 return encrypted_token_hex;
65 if (!LoadSystemSaltKey()) {
66 LOG(WARNING) << "System salt key is not available for decrypt.";
67 return std::string();
69 return DecryptTokenWithKey(system_salt_key_.get(),
70 system_salt_,
71 encrypted_token_hex);
74 private:
75 void LoadSystemSalt() {
76 if (!system_salt_.empty())
77 return;
78 std::vector<uint8> salt;
79 DBusThreadManager::Get()->GetCryptohomeClient()->GetSystemSalt(&salt);
80 if (salt.empty() || salt.size() % 2 != 0U) {
81 LOG(WARNING) << "System salt not available";
82 return;
84 system_salt_ = StringToLowerASCII(base::HexEncode(
85 reinterpret_cast<const void*>(salt.data()), salt.size()));
88 // TODO: should this use the system salt for both the password and the salt
89 // value, or should this use a separate salt value?
90 bool LoadSystemSaltKey() {
91 if (system_salt_.empty())
92 return false;
93 if (!system_salt_key_.get())
94 system_salt_key_.reset(PassphraseToKey(system_salt_, system_salt_));
95 return system_salt_key_.get();
98 crypto::SymmetricKey* PassphraseToKey(const std::string& passphrase,
99 const std::string& salt) {
100 return crypto::SymmetricKey::DeriveKeyFromPassword(
101 crypto::SymmetricKey::AES, passphrase, salt, 1000, 256);
105 // Encrypts (AES) the token given |key| and |salt|.
106 std::string EncryptTokenWithKey(crypto::SymmetricKey* key,
107 const std::string& salt,
108 const std::string& token) {
109 crypto::Encryptor encryptor;
110 if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) {
111 LOG(WARNING) << "Failed to initialize Encryptor.";
112 return std::string();
114 std::string nonce = salt.substr(0, kNonceSize);
115 std::string encoded_token;
116 CHECK(encryptor.SetCounter(nonce));
117 if (!encryptor.Encrypt(token, &encoded_token)) {
118 LOG(WARNING) << "Failed to encrypt token.";
119 return std::string();
122 return StringToLowerASCII(base::HexEncode(
123 reinterpret_cast<const void*>(encoded_token.data()),
124 encoded_token.size()));
127 // Decrypts (AES) hex encoded encrypted token given |key| and |salt|.
128 std::string DecryptTokenWithKey(crypto::SymmetricKey* key,
129 const std::string& salt,
130 const std::string& encrypted_token_hex) {
131 std::vector<uint8> encrypted_token_bytes;
132 if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) {
133 LOG(WARNING) << "Corrupt encrypted token found.";
134 return std::string();
137 std::string encrypted_token(
138 reinterpret_cast<char*>(encrypted_token_bytes.data()),
139 encrypted_token_bytes.size());
140 crypto::Encryptor encryptor;
141 if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) {
142 LOG(WARNING) << "Failed to initialize Encryptor.";
143 return std::string();
146 std::string nonce = salt.substr(0, kNonceSize);
147 std::string token;
148 CHECK(encryptor.SetCounter(nonce));
149 if (!encryptor.Decrypt(encrypted_token, &token)) {
150 LOG(WARNING) << "Failed to decrypt token.";
151 return std::string();
153 return token;
156 std::string system_salt_;
157 // A key based on the system salt. Useful for encrypting device-level
158 // data for which we have no additional credentials.
159 scoped_ptr<crypto::SymmetricKey> system_salt_key_;
161 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl);
164 class CryptohomeLibraryStubImpl : public CryptohomeLibrary {
165 public:
166 CryptohomeLibraryStubImpl()
167 : locked_(false) {}
168 virtual ~CryptohomeLibraryStubImpl() {}
170 virtual std::string GetSystemSalt() OVERRIDE {
171 return kStubSystemSalt;
174 virtual std::string EncryptWithSystemSalt(const std::string& token) OVERRIDE {
175 return token;
178 virtual std::string DecryptWithSystemSalt(
179 const std::string& encrypted_token_hex) OVERRIDE {
180 return encrypted_token_hex;
183 private:
184 std::map<std::string, std::string> install_attrs_;
185 bool locked_;
186 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl);
189 CryptohomeLibrary::CryptohomeLibrary() {}
190 CryptohomeLibrary::~CryptohomeLibrary() {}
192 static CryptohomeLibrary* g_cryptohome_library = NULL;
193 static CryptohomeLibrary* g_test_cryptohome_library = NULL;
195 // static
196 void CryptohomeLibrary::Initialize() {
197 CHECK(!g_cryptohome_library);
198 if (base::SysInfo::IsRunningOnChromeOS())
199 g_cryptohome_library = new CryptohomeLibraryImpl();
200 else
201 g_cryptohome_library = new CryptohomeLibraryStubImpl();
204 // static
205 bool CryptohomeLibrary::IsInitialized() {
206 return g_cryptohome_library;
209 // static
210 void CryptohomeLibrary::Shutdown() {
211 CHECK(g_cryptohome_library);
212 delete g_cryptohome_library;
213 g_cryptohome_library = NULL;
216 // static
217 CryptohomeLibrary* CryptohomeLibrary::Get() {
218 CHECK(g_cryptohome_library || g_test_cryptohome_library)
219 << "CryptohomeLibrary::Get() called before Initialize()";
220 if (g_test_cryptohome_library)
221 return g_test_cryptohome_library;
222 return g_cryptohome_library;
225 // static
226 void CryptohomeLibrary::SetForTest(CryptohomeLibrary* impl) {
227 CHECK(!g_test_cryptohome_library || !impl);
228 g_test_cryptohome_library = impl;
231 // static
232 CryptohomeLibrary* CryptohomeLibrary::GetTestImpl() {
233 return new CryptohomeLibraryStubImpl();
236 } // namespace chromeos