Index: chromeos/cryptohome/cryptohome_library.cc |
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.cc b/chromeos/cryptohome/cryptohome_library.cc |
similarity index 50% |
rename from chrome/browser/chromeos/cros/cryptohome_library.cc |
rename to chromeos/cryptohome/cryptohome_library.cc |
index 20c92b3760dcbc128a2f7b7db40e9b418957b627..6aae891fa02ea2cc8bf5532f99a1eb338d393332 100644 |
--- a/chrome/browser/chromeos/cros/cryptohome_library.cc |
+++ b/chromeos/cryptohome/cryptohome_library.cc |
@@ -2,22 +2,28 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "chrome/browser/chromeos/cros/cryptohome_library.h" |
+#include "chromeos/cryptohome/cryptohome_library.h" |
#include <map> |
#include "base/bind.h" |
+#include "base/chromeos/chromeos_version.h" |
#include "base/memory/weak_ptr.h" |
#include "base/string_util.h" |
#include "base/strings/string_number_conversions.h" |
#include "chromeos/dbus/cryptohome_client.h" |
#include "chromeos/dbus/dbus_thread_manager.h" |
+#include "crypto/encryptor.h" |
+#include "crypto/nss_util.h" |
+#include "crypto/sha2.h" |
+#include "crypto/symmetric_key.h" |
namespace chromeos { |
namespace { |
const char kStubSystemSalt[] = "stub_system_salt"; |
+const size_t kKeySize = 16; |
// Does nothing. Used as a Cryptohome::VoidMethodCallback. |
void DoNothing(DBusMethodCallStatus call_status) {} |
@@ -116,6 +122,35 @@ class CryptohomeLibraryImpl : public CryptohomeLibrary { |
system_salt_.size())); |
} |
+ virtual std::string EncryptWithSystemSalt(const std::string& token) OVERRIDE { |
+ // Don't care about token encryption while debugging. |
+ if (!base::chromeos::IsRunningOnChromeOS()) |
+ return token; |
+ |
+ if (!LoadSystemSaltKey()) { |
+ LOG(WARNING) << "System salt key is not available for encrypt."; |
+ return std::string(); |
+ } |
+ return EncryptTokenWithKey(system_salt_key_.get(), |
+ GetSystemSalt(), |
+ token); |
+ } |
+ |
+ virtual std::string DecryptWithSystemSalt( |
+ const std::string& encrypted_token_hex) OVERRIDE { |
+ // Don't care about token encryption while debugging. |
+ if (!base::chromeos::IsRunningOnChromeOS()) |
+ return encrypted_token_hex; |
+ |
+ if (!LoadSystemSaltKey()) { |
+ LOG(WARNING) << "System salt key is not available for decrypt."; |
+ return std::string(); |
+ } |
+ return DecryptTokenWithKey(system_salt_key_.get(), |
+ GetSystemSalt(), |
+ encrypted_token_hex); |
+ } |
+ |
private: |
void LoadSystemSalt() { |
if (!system_salt_.empty()) |
@@ -126,8 +161,77 @@ class CryptohomeLibraryImpl : public CryptohomeLibrary { |
CHECK_EQ(system_salt_.size() % 2, 0U); |
} |
+ // TODO: should this use the system salt for both the password and the salt |
+ // value, or should this use a separate salt value? |
+ bool LoadSystemSaltKey() { |
+ if (!system_salt_key_.get()) |
+ system_salt_key_.reset(PassphraseToKey(GetSystemSalt(), GetSystemSalt())); |
+ return system_salt_key_.get(); |
+ } |
+ |
+ crypto::SymmetricKey* PassphraseToKey(const std::string& passprhase, |
+ const std::string& salt) { |
+ return crypto::SymmetricKey::DeriveKeyFromPassword( |
+ crypto::SymmetricKey::AES, passprhase, salt, 1000, 256); |
+ } |
+ |
+ |
+ // Encrypts (AES) the token given |key| and |salt|. |
+ std::string EncryptTokenWithKey(crypto::SymmetricKey* key, |
+ const std::string& salt, |
+ const std::string& token) { |
+ crypto::Encryptor encryptor; |
+ if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) { |
+ LOG(WARNING) << "Failed to initialize Encryptor."; |
+ return std::string(); |
+ } |
+ std::string nonce = salt.substr(0, kKeySize); |
+ std::string encoded_token; |
+ CHECK(encryptor.SetCounter(nonce)); |
+ if (!encryptor.Encrypt(token, &encoded_token)) { |
+ LOG(WARNING) << "Failed to encrypt token."; |
+ return std::string(); |
+ } |
+ |
+ return StringToLowerASCII(base::HexEncode( |
+ reinterpret_cast<const void*>(encoded_token.data()), |
+ encoded_token.size())); |
+ } |
+ |
+ // Decrypts (AES) hex encoded encrypted token given |key| and |salt|. |
+ std::string DecryptTokenWithKey(crypto::SymmetricKey* key, |
+ const std::string& salt, |
+ const std::string& encrypted_token_hex) { |
+ std::vector<uint8> encrypted_token_bytes; |
+ if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) { |
+ LOG(WARNING) << "Corrupt encrypted token found."; |
+ return std::string(); |
+ } |
+ |
+ std::string encrypted_token( |
+ reinterpret_cast<char*>(encrypted_token_bytes.data()), |
+ encrypted_token_bytes.size()); |
+ crypto::Encryptor encryptor; |
+ if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) { |
+ LOG(WARNING) << "Failed to initialize Encryptor."; |
+ return std::string(); |
+ } |
+ |
+ std::string nonce = salt.substr(0, kKeySize); |
+ std::string token; |
+ CHECK(encryptor.SetCounter(nonce)); |
+ if (!encryptor.Decrypt(encrypted_token, &token)) { |
+ LOG(WARNING) << "Failed to decrypt token."; |
+ return std::string(); |
+ } |
+ return token; |
+ } |
+ |
base::WeakPtrFactory<CryptohomeLibraryImpl> weak_ptr_factory_; |
std::vector<uint8> system_salt_; |
+ // A key based on the system salt. Useful for encrypting device-level |
+ // data for which we have no additional credentials. |
+ scoped_ptr<crypto::SymmetricKey> system_salt_key_; |
DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl); |
}; |
@@ -186,6 +290,15 @@ class CryptohomeLibraryStubImpl : public CryptohomeLibrary { |
return kStubSystemSalt; |
} |
+ virtual std::string EncryptWithSystemSalt(const std::string& token) { |
+ return token; |
+ } |
+ |
+ virtual std::string DecryptWithSystemSalt( |
+ const std::string& encrypted_token_hex) { |
+ return encrypted_token_hex; |
+ } |
+ |
private: |
std::map<std::string, std::string> install_attrs_; |
bool locked_; |
@@ -195,14 +308,48 @@ class CryptohomeLibraryStubImpl : public CryptohomeLibrary { |
CryptohomeLibrary::CryptohomeLibrary() {} |
CryptohomeLibrary::~CryptohomeLibrary() {} |
+static CryptohomeLibrary* g_cryptohome_library = NULL; |
+static CryptohomeLibrary* g_test_cryptohome_library = NULL; |
+ |
// static |
-CryptohomeLibrary* CryptohomeLibrary::GetImpl(bool stub) { |
- CryptohomeLibrary* impl; |
- if (stub) |
- impl = new CryptohomeLibraryStubImpl(); |
+void CryptohomeLibrary::Initialize() { |
+ CHECK(!g_cryptohome_library); |
+ if (base::chromeos::IsRunningOnChromeOS()) |
+ g_cryptohome_library = new CryptohomeLibraryStubImpl(); |
else |
- impl = new CryptohomeLibraryImpl(); |
- return impl; |
+ g_cryptohome_library = new CryptohomeLibraryImpl(); |
+} |
+ |
+// static |
+bool CryptohomeLibrary::IsInitialized() { |
+ return g_cryptohome_library; |
+} |
+ |
+// static |
+void CryptohomeLibrary::Shutdown() { |
+ CHECK(g_cryptohome_library); |
+ delete g_cryptohome_library; |
+ g_cryptohome_library = NULL; |
+} |
+ |
+// static |
+CryptohomeLibrary* CryptohomeLibrary::Get() { |
+ CHECK(g_cryptohome_library || g_test_cryptohome_library) |
+ << "CryptohomeLibrary::Get() called before Initialize()"; |
+ if (g_test_cryptohome_library) |
+ return g_test_cryptohome_library; |
+ return g_cryptohome_library; |
+} |
+ |
+// static |
+void CryptohomeLibrary::SetForTest(CryptohomeLibrary* impl) { |
+ CHECK(!g_test_cryptohome_library || !impl); |
+ g_test_cryptohome_library = impl; |
+} |
+ |
+// static |
+CryptohomeLibrary* CryptohomeLibrary::GetTestImpl() { |
+ return new CryptohomeLibraryStubImpl(); |
} |
} // namespace chromeos |