OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/cros/cryptohome_library.h" | 5 #include "chromeos/cryptohome/cryptohome_library.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/chromeos/chromeos_version.h" | |
10 #include "base/memory/weak_ptr.h" | 11 #include "base/memory/weak_ptr.h" |
11 #include "base/string_util.h" | 12 #include "base/string_util.h" |
12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
13 #include "chromeos/dbus/cryptohome_client.h" | 14 #include "chromeos/dbus/cryptohome_client.h" |
14 #include "chromeos/dbus/dbus_thread_manager.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" | |
15 | 20 |
16 namespace chromeos { | 21 namespace chromeos { |
17 | 22 |
18 namespace { | 23 namespace { |
19 | 24 |
20 const char kStubSystemSalt[] = "stub_system_salt"; | 25 const char kStubSystemSalt[] = "stub_system_salt"; |
26 const size_t kKeySize = 16; | |
Ryan Sleevi
2013/04/26 18:38:20
nit: This is really kNonceSize.
A bit confusing,
| |
21 | 27 |
22 // Does nothing. Used as a Cryptohome::VoidMethodCallback. | 28 // Does nothing. Used as a Cryptohome::VoidMethodCallback. |
23 void DoNothing(DBusMethodCallStatus call_status) {} | 29 void DoNothing(DBusMethodCallStatus call_status) {} |
24 | 30 |
25 } // namespace | 31 } // namespace |
26 | 32 |
27 // This class handles the interaction with the ChromeOS cryptohome library APIs. | 33 // This class handles the interaction with the ChromeOS cryptohome library APIs. |
28 class CryptohomeLibraryImpl : public CryptohomeLibrary { | 34 class CryptohomeLibraryImpl : public CryptohomeLibrary { |
29 public: | 35 public: |
30 CryptohomeLibraryImpl() : weak_ptr_factory_(this) { | 36 CryptohomeLibraryImpl() : weak_ptr_factory_(this) { |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
109 return result; | 115 return result; |
110 } | 116 } |
111 | 117 |
112 virtual std::string GetSystemSalt() OVERRIDE { | 118 virtual std::string GetSystemSalt() OVERRIDE { |
113 LoadSystemSalt(); // no-op if it's already loaded. | 119 LoadSystemSalt(); // no-op if it's already loaded. |
114 return StringToLowerASCII(base::HexEncode( | 120 return StringToLowerASCII(base::HexEncode( |
115 reinterpret_cast<const void*>(system_salt_.data()), | 121 reinterpret_cast<const void*>(system_salt_.data()), |
116 system_salt_.size())); | 122 system_salt_.size())); |
117 } | 123 } |
118 | 124 |
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; | |
129 | |
130 if (!LoadSystemSaltKey()) { | |
131 LOG(WARNING) << "System salt key is not available for encrypt."; | |
132 return std::string(); | |
133 } | |
134 return EncryptTokenWithKey(system_salt_key_.get(), | |
135 GetSystemSalt(), | |
136 token); | |
137 } | |
138 | |
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; | |
144 | |
145 if (!LoadSystemSaltKey()) { | |
146 LOG(WARNING) << "System salt key is not available for decrypt."; | |
147 return std::string(); | |
148 } | |
149 return DecryptTokenWithKey(system_salt_key_.get(), | |
150 GetSystemSalt(), | |
151 encrypted_token_hex); | |
152 } | |
153 | |
119 private: | 154 private: |
120 void LoadSystemSalt() { | 155 void LoadSystemSalt() { |
121 if (!system_salt_.empty()) | 156 if (!system_salt_.empty()) |
122 return; | 157 return; |
123 DBusThreadManager::Get()->GetCryptohomeClient()-> | 158 DBusThreadManager::Get()->GetCryptohomeClient()-> |
124 GetSystemSalt(&system_salt_); | 159 GetSystemSalt(&system_salt_); |
125 CHECK(!system_salt_.empty()); | 160 CHECK(!system_salt_.empty()); |
126 CHECK_EQ(system_salt_.size() % 2, 0U); | 161 CHECK_EQ(system_salt_.size() % 2, 0U); |
127 } | 162 } |
128 | 163 |
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(); | |
170 } | |
171 | |
172 crypto::SymmetricKey* PassphraseToKey(const std::string& passprhase, | |
Ryan Sleevi
2013/04/26 18:38:20
typo: passprhase -> passphrase
| |
173 const std::string& salt) { | |
174 return crypto::SymmetricKey::DeriveKeyFromPassword( | |
175 crypto::SymmetricKey::AES, passprhase, salt, 1000, 256); | |
176 } | |
177 | |
178 | |
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(); | |
187 } | |
188 std::string nonce = salt.substr(0, kKeySize); | |
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(); | |
194 } | |
195 | |
196 return StringToLowerASCII(base::HexEncode( | |
197 reinterpret_cast<const void*>(encoded_token.data()), | |
198 encoded_token.size())); | |
199 } | |
200 | |
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(); | |
209 } | |
210 | |
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(); | |
218 } | |
219 | |
220 std::string nonce = salt.substr(0, kKeySize); | |
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(); | |
226 } | |
227 return token; | |
228 } | |
229 | |
129 base::WeakPtrFactory<CryptohomeLibraryImpl> weak_ptr_factory_; | 230 base::WeakPtrFactory<CryptohomeLibraryImpl> weak_ptr_factory_; |
130 std::vector<uint8> system_salt_; | 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_; | |
131 | 235 |
132 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl); | 236 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl); |
133 }; | 237 }; |
134 | 238 |
135 class CryptohomeLibraryStubImpl : public CryptohomeLibrary { | 239 class CryptohomeLibraryStubImpl : public CryptohomeLibrary { |
136 public: | 240 public: |
137 CryptohomeLibraryStubImpl() | 241 CryptohomeLibraryStubImpl() |
138 : locked_(false) {} | 242 : locked_(false) {} |
139 virtual ~CryptohomeLibraryStubImpl() {} | 243 virtual ~CryptohomeLibraryStubImpl() {} |
140 | 244 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 } | 283 } |
180 | 284 |
181 virtual bool InstallAttributesIsFirstInstall() OVERRIDE { | 285 virtual bool InstallAttributesIsFirstInstall() OVERRIDE { |
182 return !locked_; | 286 return !locked_; |
183 } | 287 } |
184 | 288 |
185 virtual std::string GetSystemSalt() OVERRIDE { | 289 virtual std::string GetSystemSalt() OVERRIDE { |
186 return kStubSystemSalt; | 290 return kStubSystemSalt; |
187 } | 291 } |
188 | 292 |
293 virtual std::string EncryptWithSystemSalt(const std::string& token) { | |
294 return token; | |
295 } | |
296 | |
297 virtual std::string DecryptWithSystemSalt( | |
298 const std::string& encrypted_token_hex) { | |
299 return encrypted_token_hex; | |
300 } | |
301 | |
189 private: | 302 private: |
190 std::map<std::string, std::string> install_attrs_; | 303 std::map<std::string, std::string> install_attrs_; |
191 bool locked_; | 304 bool locked_; |
192 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl); | 305 DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl); |
193 }; | 306 }; |
194 | 307 |
195 CryptohomeLibrary::CryptohomeLibrary() {} | 308 CryptohomeLibrary::CryptohomeLibrary() {} |
196 CryptohomeLibrary::~CryptohomeLibrary() {} | 309 CryptohomeLibrary::~CryptohomeLibrary() {} |
197 | 310 |
311 static CryptohomeLibrary* g_cryptohome_library = NULL; | |
312 static CryptohomeLibrary* g_test_cryptohome_library = NULL; | |
313 | |
198 // static | 314 // static |
199 CryptohomeLibrary* CryptohomeLibrary::GetImpl(bool stub) { | 315 void CryptohomeLibrary::Initialize() { |
200 CryptohomeLibrary* impl; | 316 CHECK(!g_cryptohome_library); |
201 if (stub) | 317 if (base::chromeos::IsRunningOnChromeOS()) |
202 impl = new CryptohomeLibraryStubImpl(); | 318 g_cryptohome_library = new CryptohomeLibraryStubImpl(); |
203 else | 319 else |
204 impl = new CryptohomeLibraryImpl(); | 320 g_cryptohome_library = new CryptohomeLibraryImpl(); |
205 return impl; | 321 } |
322 | |
323 // static | |
324 bool CryptohomeLibrary::IsInitialized() { | |
325 return g_cryptohome_library; | |
326 } | |
327 | |
328 // static | |
329 void CryptohomeLibrary::Shutdown() { | |
330 CHECK(g_cryptohome_library); | |
331 delete g_cryptohome_library; | |
332 g_cryptohome_library = NULL; | |
333 } | |
334 | |
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; | |
342 } | |
343 | |
344 // static | |
345 void CryptohomeLibrary::SetForTest(CryptohomeLibrary* impl) { | |
346 CHECK(!g_test_cryptohome_library || !impl); | |
347 g_test_cryptohome_library = impl; | |
348 } | |
349 | |
350 // static | |
351 CryptohomeLibrary* CryptohomeLibrary::GetTestImpl() { | |
352 return new CryptohomeLibraryStubImpl(); | |
206 } | 353 } |
207 | 354 |
208 } // namespace chromeos | 355 } // namespace chromeos |
OLD | NEW |