blob: e901d7b3c7dba3da9debf67819ca0bd135e9f248 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OS_CRYPT_OS_CRYPT_H_
#define COMPONENTS_OS_CRYPT_OS_CRYPT_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#if BUILDFLAG(IS_LINUX)
class KeyStorageLinux;
#endif // BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
class PrefRegistrySimple;
class PrefService;
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE)
namespace crypto {
class SymmetricKey;
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE)
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_CHROMECAST))
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_CHROMECAST))
} // 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)
// 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 false as OSCryptImpl will use
// a hardcoded key.
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_CHROMECAST))
// 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_CHROMECAST))
private:
#if BUILDFLAG(IS_APPLE)
// Generates a newly allocated SymmetricKey object based on the password found
// in the Keychain. The generated key is for AES encryption. Returns NULL
// key in the case password access is denied or key generation error occurs.
crypto::SymmetricKey* GetEncryptionKey();
#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)
// Create the KeyStorage. Will be null if no service is found. A Config must
// be set before every call to this method.
std::unique_ptr<KeyStorageLinux> CreateKeyStorage();
// Returns a cached string of "peanuts". Is thread-safe.
crypto::SymmetricKey* GetPasswordV10();
// Caches and returns the password from the KeyStorage or null if there is no
// service. Is thread-safe.
crypto::SymmetricKey* GetPasswordV11();
// For password_v10, nullptr means uninitialised.
std::unique_ptr<crypto::SymmetricKey> password_v10_cache_;
// For password_v11, nullptr means no backend.
std::unique_ptr<crypto::SymmetricKey> password_v11_cache_;
bool is_password_v11_cached_ = false;
// |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_;
#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)
// true if |cached_encryption_key_| has been initialized.
bool key_is_cached_ = false;
// The cached AES encryption key.
std::unique_ptr<crypto::SymmetricKey> cached_encryption_key_;
// TODO(dhollowa): 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_OS_CRYPT_H_