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; |
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, |
| 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 |