1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
// Copyright 2023 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_ASYNC_COMMON_ENCRYPTOR_H_
#define COMPONENTS_OS_CRYPT_ASYNC_COMMON_ENCRYPTOR_H_
#include <map>
#include <optional>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "mojo/public/cpp/bindings/default_construct_tag.h"
namespace mojo {
template <typename DataViewType, typename T>
struct StructTraits;
} // namespace mojo
namespace os_crypt_async {
namespace mojom {
enum class Algorithm;
class EncryptorDataView;
class KeyDataView;
} // namespace mojom
class EncryptorTestBase;
class OSCryptAsync;
class TestOSCryptAsync;
// This class is used for data encryption. A thread-safe instance can be
// obtained by calling `os_crypt_async::OSCryptAsync::GetInstance`.
class COMPONENT_EXPORT(OS_CRYPT_ASYNC) Encryptor {
public:
// A class used by the Encryptor to hold an encryption key and carry out
// encryption and decryption operations using the specified Algorithm and
// encryption key.
class COMPONENT_EXPORT(OS_CRYPT_ASYNC) Key {
public:
// Moveable, not copyable.
Key(Key&& other);
Key& operator=(Key&& other);
Key(const Key&) = delete;
Key& operator=(const Key&) = delete;
~Key();
static constexpr size_t kAES256GCMKeySize = 256u / 8u;
static constexpr size_t kAES128CBCKeySize = 128u / 8u;
// Mojo uses this public constructor for serialization.
explicit Key(mojo::DefaultConstruct::Tag);
Key(base::span<const uint8_t> key, const mojom::Algorithm& algo);
bool operator==(const Key& other) const = default;
private:
friend class Encryptor;
// OSCryptAsync and tests need to be able to Clone() keys.
friend class OSCryptAsync;
friend class TestOSCryptAsync;
friend class EncryptorTestBase;
friend struct mojo::StructTraits<os_crypt_async::mojom::KeyDataView,
os_crypt_async::Encryptor::Key>;
FRIEND_TEST_ALL_PREFIXES(EncryptorTestWithOSCrypt, MultipleKeys);
FRIEND_TEST_ALL_PREFIXES(EncryptorTraitsTest, TraitsRoundTrip);
Key(base::span<const uint8_t> key,
const mojom::Algorithm& algo,
bool encrypted);
std::vector<uint8_t> Encrypt(base::span<const uint8_t> plaintext) const;
std::optional<std::vector<uint8_t>> Decrypt(
base::span<const uint8_t> ciphertext) const;
Key Clone() const;
// Algorithm. Can only be std::nullopt if the instance is in the process of
// being serialized to/from mojo.
std::optional<mojom::Algorithm> algorithm_;
std::vector<uint8_t> key_;
#if BUILDFLAG(IS_WIN)
bool encrypted_ = false;
#endif
};
enum class Option {
// No Encryptor options.
kNone = 0,
// Indicates that the Encryptor returned should be data-compatible with
// OSCrypt Sync for both Encrypt and Decrypt operations. Note that Decrypt
// operations are always backwards compatible with previous Encrypt
// operations from OSCrypt Sync even if no option is specified: this option
// only affects the behavior of Encrypt operations.
kEncryptSyncCompat = 1,
};
// Flags that can be set by the Encryptor during a Decrypt call. Pass to a
// Decrypt operation to obtain these flags.
struct DecryptFlags {
// Set by the Encryptor upon success to indicate to the caller that the data
// that has just been returned from the Decrypt operation should be
// re-encrypted with a call to Encrypt, as the key has been rotated or a new
// key is available that provides a different security level.
bool should_reencrypt = false;
// Set by the Encryptor upon failure to indicate to the caller that the
// decryption failed because the key was temporarily unavailable. The
// failure could be because the key provider temporarily was unable to
// provide a key, but might be able to provide the key at a later time, e.g.
// the keychain is temporarily unlocked, or encryption services are
// temporarily unavailable for another reason. If a failure in decryption
// occurs and this flag is not set, it can be assumed that the data is not
// recoverable e.g. the encrypted data is corrupt or the key that encrypted
// the data has been permanently lost.
bool temporarily_unavailable = false;
};
using KeyRing = std::map</*tag=*/std::string, std::optional<Key>>;
// Mojo uses this public constructor for serialization.
explicit Encryptor(mojo::DefaultConstruct::Tag);
virtual ~Encryptor();
// Moveable, not copyable.
Encryptor(Encryptor&& other);
Encryptor& operator=(Encryptor&& other);
Encryptor(const Encryptor&) = delete;
Encryptor& operator=(const Encryptor&) = delete;
// Encrypt a string with the current Encryptor configuration. This can be
// called on any thread.
[[nodiscard]] std::optional<std::vector<uint8_t>> EncryptString(
const std::string& data) const;
// Decrypt data previously encrypted using `EncryptData`. This can be called
// on any thread. If a non-null `flags` is passed, then a set of flags is
// returned to indicate additional information for the caller. See
// `DecryptFlags` struct above.
[[nodiscard]] std::optional<std::string> DecryptData(
base::span<const uint8_t> data,
DecryptFlags* flags = nullptr) const;
// These four APIs are provided for backwards compatibility with OSCrypt. They
// just call the above functions. For these functions, `flags` is optional.
[[nodiscard]] bool EncryptString(const std::string& plaintext,
std::string* ciphertext) const;
[[nodiscard]] bool DecryptString(const std::string& ciphertext,
std::string* plaintext,
DecryptFlags* flags = nullptr) const;
[[nodiscard]] bool EncryptString16(const std::u16string& plaintext,
std::string* ciphertext) const;
[[nodiscard]] bool DecryptString16(const std::string& ciphertext,
std::u16string* plaintext,
DecryptFlags* flags = nullptr) const;
// Returns true if there is at least one key contained within the encryptor
// that could be used for encryption, otherwise, it will return the value of
// OSCrypt::IsEncryptionAvailable.
virtual bool IsEncryptionAvailable() const;
// Returns true if there is at least one key contained within the encryptor
// that might be able to decrypt data, otherwise it will return the value of
// OSCrypt::IsEncryptionAvailable. Note that if this function returns true
// then there is no guarantee that arbitrary data can be decrypted, as the
// correct key to decrypt the data might not be available.
virtual bool IsDecryptionAvailable() const;
protected:
// Create an encryptor with a set of `keys`. This is used by the Clone()
// function and internally by tests. The `provider_for_encryption` specifies
// which provider is used for encryption, and must have a corresponding key in
// `keys`. The `provider_for_os_crypt_sync_compatible_encryption` is the
// filtered version of `provider_for_encryption` that only contains the
// encryption provider if it's marked itself as being compatible with OSCrypt
// Sync.
Encryptor(
KeyRing keys,
const std::string& provider_for_encryption,
const std::string& provider_for_os_crypt_sync_compatible_encryption);
// Clone is used internally by the factory to vend instances.
Encryptor Clone(Option option) const;
private:
friend class EncryptorTestBase;
friend class OSCryptAsync;
friend class TestEncryptor;
friend struct mojo::StructTraits<os_crypt_async::mojom::EncryptorDataView,
os_crypt_async::Encryptor>;
FRIEND_TEST_ALL_PREFIXES(EncryptorTraitsTest, TraitsRoundTrip);
FRIEND_TEST_ALL_PREFIXES(EncryptorTestBase, Clone);
// Create an encryptor with no keys or encryption provider. In this case, all
// encryption operations will be delegated to OSCrypt.
Encryptor();
// Returns whether `provider_for_encryption_` is set, and it contains an entry
// in the `keys_` keyring holding a valid key. This means encryption with
// OSCrypt Async is available.
bool DefaultEncryptionProviderAvailable() const;
// A KeyRing consists of a set of provider names and Key values. Encrypted
// data is always tagged with the provider name and this is used to look up
// the correct key to use for decryption. This can be empty, meaning
// encryption will fall back to OSCrypt Sync.
KeyRing keys_;
// The provider with this tag is used when encrypting any new data, the Key to
// use for the encryption is looked up from the entry in the KeyRing. This can
// be empty string, which means that providers are registered for decryption
// only, but encryption will fall back to OSCrypt Sync.
std::string provider_for_encryption_;
// Provider for OSCrypt Sync compatible encryption. This could be the same as
// the `provider_for_encryption_` if all keys are OSCrypt compatible, and/or
// if this Encryptor has been cloned from an Encryptor using the
// `kEncryptSyncCompat` `Option`.
std::string provider_for_os_crypt_sync_compatible_encryption_;
};
} // namespace os_crypt_async
#endif // COMPONENTS_OS_CRYPT_ASYNC_COMMON_ENCRYPTOR_H_
|