| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_OS_CRYPT_SYNC_OS_CRYPT_H_ |
| #define COMPONENTS_OS_CRYPT_SYNC_OS_CRYPT_H_ |
| |
| #include <array> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| |
| #include "base/component_export.h" |
| #include "base/functional/callback.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "build/build_config.h" |
| #include "build/chromecast_buildflags.h" |
| #include "crypto/subtle_passkey.h" |
| |
| #if BUILDFLAG(IS_APPLE) |
| namespace crypto::apple { |
| class Keychain; |
| } |
| #endif |
| |
| #if BUILDFLAG(IS_LINUX) |
| class KeyStorageLinux; |
| #endif // BUILDFLAG(IS_LINUX) |
| |
| #if BUILDFLAG(IS_WIN) |
| class PrefRegistrySimple; |
| class PrefService; |
| #endif // BUILDFLAG(IS_WIN) |
| |
| namespace os_crypt { |
| struct Config; |
| } |
| |
| // Temporary interface due to OSCrypt refactor. See OSCryptImpl for descriptions |
| // of what each function does. |
| namespace OSCrypt { |
| #if BUILDFLAG(IS_LINUX) |
| COMPONENT_EXPORT(OS_CRYPT) |
| void SetConfig(std::unique_ptr<os_crypt::Config> config); |
| #endif // BUILDFLAG(IS_LINUX) |
| COMPONENT_EXPORT(OS_CRYPT) bool IsEncryptionAvailable(); |
| COMPONENT_EXPORT(OS_CRYPT) |
| bool EncryptString16(const std::u16string& plaintext, std::string* ciphertext); |
| COMPONENT_EXPORT(OS_CRYPT) |
| bool DecryptString16(const std::string& ciphertext, std::u16string* plaintext); |
| COMPONENT_EXPORT(OS_CRYPT) |
| bool EncryptString(const std::string& plaintext, std::string* ciphertext); |
| COMPONENT_EXPORT(OS_CRYPT) |
| bool DecryptString(const std::string& ciphertext, std::string* plaintext); |
| #if BUILDFLAG(IS_WIN) |
| COMPONENT_EXPORT(OS_CRYPT) |
| void RegisterLocalPrefs(PrefRegistrySimple* registry); |
| COMPONENT_EXPORT(OS_CRYPT) bool Init(PrefService* local_state); |
| |
| // Initialises OSCryptImpl using an encryption key present in the |local_state|. |
| // It is similar to the Init() method above, however, it will not create |
| // a new encryption key if it is not present in the |local_state|. |
| enum InitResult { |
| kSuccess, |
| kKeyDoesNotExist, |
| kInvalidKeyFormat, |
| kDecryptionFailed |
| }; |
| |
| COMPONENT_EXPORT(OS_CRYPT) |
| InitResult InitWithExistingKey(PrefService* local_state); |
| #endif // BUILDFLAG(IS_WIN) |
| #if BUILDFLAG(IS_APPLE) |
| COMPONENT_EXPORT(OS_CRYPT) void UseMockKeychainForTesting(bool use_mock); |
| COMPONENT_EXPORT(OS_CRYPT) |
| void UseLockedMockKeychainForTesting(bool use_locked); |
| #endif // BUILDFLAG(IS_APPLE) |
| COMPONENT_EXPORT(OS_CRYPT) |
| std::string GetRawEncryptionKey(); |
| COMPONENT_EXPORT(OS_CRYPT) |
| void SetRawEncryptionKey(const std::string& key); |
| #if BUILDFLAG(IS_WIN) |
| COMPONENT_EXPORT(OS_CRYPT) void UseMockKeyForTesting(bool use_mock); |
| COMPONENT_EXPORT(OS_CRYPT) void SetLegacyEncryptionForTesting(bool legacy); |
| COMPONENT_EXPORT(OS_CRYPT) void ResetStateForTesting(); |
| #endif // BUILDFLAG(IS_WIN) |
| #if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) |
| COMPONENT_EXPORT(OS_CRYPT) |
| void UseMockKeyStorageForTesting( |
| base::OnceCallback<std::unique_ptr<KeyStorageLinux>()> |
| storage_provider_factory); |
| COMPONENT_EXPORT(OS_CRYPT) void ClearCacheForTesting(); |
| COMPONENT_EXPORT(OS_CRYPT) |
| void SetEncryptionPasswordForTesting(const std::string& password); |
| #endif // (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) |
| #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && \ |
| !(BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| COMPONENT_EXPORT(OS_CRYPT) |
| void SetEncryptionAvailableForTesting(std::optional<bool> available); |
| #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !(BUILDFLAG(IS_LINUX) |
| // && !BUILDFLAG(IS_CASTOS)) || BUILDFLAG(IS_FUCHSIA) |
| } // namespace OSCrypt |
| |
| // The OSCryptImpl class gives access to simple encryption and decryption of |
| // strings. Note that on Mac, access to the system Keychain is required and |
| // these calls can block the current thread to collect user input. The same is |
| // true for Linux, if a password management tool is available. |
| class COMPONENT_EXPORT(OS_CRYPT) OSCryptImpl { |
| public: |
| OSCryptImpl(); |
| ~OSCryptImpl(); |
| OSCryptImpl(const OSCryptImpl&) = delete; |
| OSCryptImpl(OSCryptImpl&&) = delete; |
| OSCryptImpl& operator=(const OSCryptImpl&) = delete; |
| OSCryptImpl& operator=(OSCryptImpl&&) = delete; |
| |
| // Returns singleton instance of OSCryptImpl. |
| static OSCryptImpl* GetInstance(); |
| |
| #if BUILDFLAG(IS_LINUX) |
| // Set the configuration of OSCryptImpl. |
| // This method, or SetRawEncryptionKey(), must be called before using |
| // EncryptString() and DecryptString(). |
| void SetConfig(std::unique_ptr<os_crypt::Config> config); |
| #endif // BUILDFLAG(IS_LINUX) |
| |
| // In production code: |
| // - On Linux, returns true iff the real secret key (not hardcoded one) is |
| // available. |
| // - On MacOS, returns true if Keychain is available (for mock Keychain it |
| // returns true if not using locked Keychain, false if using locked mock |
| // Keychain). |
| // - On Windows, returns true if non mock encryption key is available. |
| // - On other platforms, returns true as OSCryptImpl will use a hardcoded key. |
| // |
| // Tests may override the above behavior. |
| bool IsEncryptionAvailable(); |
| |
| // Encrypt a string16. The output (second argument) is really an array of |
| // bytes, but we're passing it back as a std::string. |
| bool EncryptString16(const std::u16string& plaintext, |
| std::string* ciphertext); |
| |
| // Decrypt an array of bytes obtained with EncryptString16 back into a |
| // string16. Note that the input (first argument) is a std::string, so you |
| // need to first get your (binary) data into a string. |
| bool DecryptString16(const std::string& ciphertext, |
| std::u16string* plaintext); |
| |
| // Encrypt a string. |
| bool EncryptString(const std::string& plaintext, std::string* ciphertext); |
| |
| // Decrypt an array of bytes obtained with EnctryptString back into a string. |
| // Note that the input (first argument) is a std::string, so you need to first |
| // get your (binary) data into a string. |
| bool DecryptString(const std::string& ciphertext, std::string* plaintext); |
| |
| #if BUILDFLAG(IS_WIN) |
| // Registers preferences used by OSCryptImpl. |
| static void RegisterLocalPrefs(PrefRegistrySimple* registry); |
| |
| // Initialises OSCryptImpl. |
| // This method should be called on the main UI thread before any calls to |
| // encryption or decryption. Returns |true| if os_crypt successfully |
| // initialized. |
| bool Init(PrefService* local_state); |
| |
| // Initialises OSCryptImpl using an encryption key present in the |
| // |local_state|. It is similar to the Init() method above, however, it will |
| // not create a new encryption key if it is not present in the |local_state|. |
| |
| OSCrypt::InitResult InitWithExistingKey(PrefService* local_state); |
| #endif |
| |
| #if BUILDFLAG(IS_APPLE) |
| // For unit testing purposes we instruct the Encryptor to use a mock Keychain |
| // on the Mac. The default is to use the real Keychain. Use OSCryptMocker, |
| // instead of calling this method directly. |
| void UseMockKeychainForTesting(bool use_mock); |
| |
| // When Keychain is locked, it's not possible to get the encryption key. This |
| // is used only for testing purposes. Enabling locked Keychain also enables |
| // mock Keychain. Use OSCryptMocker, instead of calling this method directly. |
| void UseLockedMockKeychainForTesting(bool use_locked); |
| #endif |
| |
| // Get the raw encryption key to be used for all AES encryption. The result |
| // can be used to call SetRawEncryptionKey() in another process. Returns an |
| // empty string in some situations, for example: |
| // - password access is denied |
| // - key generation error |
| // - if a hardcoded password is used instead of a random per-user key |
| // This method is thread-safe. |
| std::string GetRawEncryptionKey(); |
| |
| // Set the raw encryption key to be used for all AES encryption. |
| // On platforms that may use a hardcoded key, |key| can be empty and |
| // OSCryptImpl will default to the hardcoded key. This method is thread-safe. |
| void SetRawEncryptionKey(const std::string& key); |
| |
| #if BUILDFLAG(IS_WIN) |
| // For unit testing purposes we instruct the Encryptor to use a mock Key. The |
| // default is to use the real Key bound to profile. Use OSCryptMocker, instead |
| // of calling this method directly. |
| void UseMockKeyForTesting(bool use_mock); |
| |
| // For unit testing purposes, encrypt data using the older DPAPI method rather |
| // than using a session key. |
| void SetLegacyEncryptionForTesting(bool legacy); |
| |
| // For unit testing purposes, reset the state of OSCryptImpl so a new key can |
| // be loaded via Init() or SetRawEncryptionkey(). |
| void ResetStateForTesting(); |
| #endif |
| |
| #if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) |
| // For unit testing purposes, inject methods to be used. |
| // |storage_provider_factory| provides the desired |KeyStorage| |
| // implementation. If the provider returns |nullptr|, a hardcoded password |
| // will be used. If |storage_provider_factory| is null callback, restores the |
| // real implementation. |
| void UseMockKeyStorageForTesting( |
| base::OnceCallback<std::unique_ptr<KeyStorageLinux>()> |
| storage_provider_factory); |
| |
| // Clears any caching and most lazy initialisations performed by the |
| // production code. Should be used after any test which required a password. |
| void ClearCacheForTesting(); |
| |
| // Sets the password with which the encryption key is derived, e.g. "peanuts". |
| void SetEncryptionPasswordForTesting(const std::string& password); |
| #endif // (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) |
| private: |
| #if BUILDFLAG(IS_APPLE) |
| // Return the keychain to use for accessing the encryption key. |
| std::unique_ptr<crypto::apple::Keychain> GetKeychain() const; |
| |
| // Derives an encryption key from data stored in the keychain if necessary. |
| // Returns true if there is an encryption key available and false otherwise. |
| bool DeriveKey(); |
| #endif // BUILDFLAG(IS_APPLE) |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) |
| // This lock is used to make the GetEncryptionKey and |
| // GetRawEncryptionKey methods thread-safe. |
| static base::Lock& GetLock(); |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) |
| |
| #if BUILDFLAG(IS_LINUX) |
| static constexpr size_t kDerivedKeyBytes = 16; |
| |
| crypto::SubtlePassKey MakeCryptoPassKey(); |
| |
| // Derive a new key of `kDerivedKeyBytes` from a given input key using |
| // PBKDF2-HMAC-SHA1. |
| std::array<uint8_t, kDerivedKeyBytes> Pbkdf2(const std::string& key); |
| |
| // Try to fill in `v11_key_` with a V1.1 derived key. Returns true if a v11 |
| // key is now present in `v11_key_` (which may have just been cached |
| // previously) and false if one is not present. If `try_v11_` is false, and |
| // there is no cached v11 key, this method just returns false. |
| bool DeriveV11Key(); |
| |
| // The cached V1.1 derived key. If this is nullopt, no V1.1 key is available |
| // yet, but `DeriveV11Key()` may be able to generate one. |
| std::optional<std::array<uint8_t, kDerivedKeyBytes>> v11_key_; |
| |
| // Whether to try V1.1 key generation at all. When OSCrypt is used in the |
| // network service, V1.1 key generation can't succeed (it is blocked by the |
| // sandbox) so it should never be attempted. |
| bool try_v11_ = true; |
| |
| // |config_| is used to initialise |password_v11_cache_| and then cleared. |
| std::unique_ptr<os_crypt::Config> config_; |
| |
| base::OnceCallback<std::unique_ptr<KeyStorageLinux>()> |
| storage_provider_factory_for_testing_; |
| #endif // BUILDFLAG(IS_LINUX) |
| |
| #if BUILDFLAG(IS_WIN) |
| // Use mock key instead of a real encryption key. Used for testing. |
| bool use_mock_key_ = false; |
| |
| // Store data using the legacy (DPAPI) method rather than session key. |
| bool use_legacy_ = false; |
| |
| // Encryption Key. Set either by calling Init() or SetRawEncryptionKey(). |
| std::string encryption_key_; |
| |
| // Mock Encryption Key. Only set and used if use_mock_key_ is true. |
| std::string mock_encryption_key_; |
| #endif // BUILDFLAG(IS_WIN) |
| |
| #if BUILDFLAG(IS_APPLE) |
| // `try_keychain_` indicates whether this object should try using the keychain |
| // (which may itself be mocked out) to derive an encryption key; it can be |
| // false even if `key_present_` is also false because this object will only |
| // try using the keychain at most once and if the first use fails it will |
| // persistently fail to decrypt. |
| bool try_keychain_ = true; |
| |
| static constexpr size_t kDerivedKeySize = 16; |
| std::optional<std::array<uint8_t, kDerivedKeySize>> key_; |
| // TODO(crbug.com/389737048): Refactor to allow dependency injection of Keychain. |
| bool use_mock_keychain_ = false; |
| // This flag is used to make the GetEncryptionKey method return NULL if used |
| // along with mock Keychain. |
| bool use_locked_mock_keychain_ = false; |
| #endif |
| }; |
| |
| #endif // COMPONENTS_OS_CRYPT_SYNC_OS_CRYPT_H_ |