| // Copyright 2024 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_ENTERPRISE_OBFUSCATION_CORE_UTILS_H_ |
| #define COMPONENTS_ENTERPRISE_OBFUSCATION_CORE_UTILS_H_ |
| |
| #include <array> |
| #include <vector> |
| |
| #include "base/component_export.h" |
| #include "base/containers/span.h" |
| #include "base/feature_list.h" |
| #include "base/files/file_path.h" |
| #include "base/types/expected.h" |
| |
| namespace enterprise_obfuscation { |
| |
| // Default key and derived key size, nonce length and max tag length in |
| // BoringSSL's implementation of AES-256 GCM used by the crypto library. |
| // TODO(b/356473947): Consider switching to 128-bit key for performance. |
| static constexpr size_t kKeySize = 32u; |
| static constexpr size_t kNonceSize = 12u; |
| static constexpr size_t kAuthTagSize = 16u; |
| |
| // Nonce prefix and header size based on Tink streaming AEAD implementation |
| // (https://developers.google.com/tink/streaming-aead/aes_gcm_hkdf_streaming). |
| static constexpr size_t kNoncePrefixSize = 7u; |
| static constexpr size_t kSaltSize = kKeySize; |
| |
| // Length of the header is encoded as a single byte. |
| static constexpr size_t kHeaderSize = 1u + kSaltSize + kNoncePrefixSize; |
| |
| // Maximum size of a data chunk for obfuscation/deobfuscation. |
| // |
| // This size is chosen to be the default buffer size in bytes used for downloads |
| // (kDefaultDownloadFileBufferSize = 524288) plus the auth tag length. |
| static constexpr size_t kMaxChunkSize = 512u * 1024u + kAuthTagSize; |
| |
| // Size of the chunk size prefix for variable size. |
| static constexpr size_t kChunkSizePrefixSize = 4u; |
| |
| // Obfuscation result and error type histogram name. |
| static constexpr char kObfuscationResultHistogram[] = |
| "Enterprise.FileDownloadObfuscation.Result"; |
| |
| // Feature to enable insecure obfuscation and deobfuscation of files sent to |
| // WebProtect deep scanning service for enterprise users. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| BASE_DECLARE_FEATURE(kEnterpriseFileObfuscation); |
| |
| // Returns true if `kEnterpriseFileObfuscation` feature is enabled. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| bool IsFileObfuscationEnabled(); |
| |
| // Error types for insecure obfuscation and deobfuscation operations. Values are |
| // persisted to logs. Entries should not be renumbered or reused. |
| enum class Error { |
| kSuccess = 0, // No error exits, used for metrics |
| kObfuscationFailed = 1, // Obfuscation process could not be completed |
| kDeobfuscationFailed = 2, // Deobfuscation process could not be completed |
| kFileOperationError = 3, // Error during file read/write operations |
| kDisabled = 4, // Obfuscation/deobfuscation is not enabled |
| kSchemeError = 5, // Error with obfuscation scheme. |
| kMaxValue = kSchemeError |
| }; |
| |
| // Returns the header and populates the derived key and nonce prefix values used |
| // for obfuscating each chunk. |
| // The header structure is: size of header (1 byte) | salt | noncePrefix. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| base::expected<std::vector<uint8_t>, Error> CreateHeader( |
| std::array<uint8_t, kKeySize>* derived_key, |
| std::vector<uint8_t>* nonce_prefix); |
| |
| // Obfuscate data chunk using crypto::Aead |
| // (https://crsrc.org/c/crypto/aead.h) in an insecure way to act as a file |
| // access deterrent. Master key is stored in memory and can be leaked. |
| // Counter increments every chunk to protect against reordering/truncation. |
| // The size of the encrypted chunk is prepended to the returned encrypted chunk. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| base::expected<std::vector<uint8_t>, Error> ObfuscateDataChunk( |
| base::span<const uint8_t> data, |
| base::span<const uint8_t> key, |
| base::span<const uint8_t> nonce_prefix, |
| uint32_t counter, |
| bool is_last_chunk); |
| |
| // Extracts the size of the obfuscated data chunk from the beginning of the |
| // provided data. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| base::expected<size_t, Error> GetObfuscatedChunkSize( |
| base::span<const uint8_t> data); |
| |
| // Holds the derived key and nonce prefix extracted from an obfuscated file |
| // header. |
| struct COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) HeaderData { |
| HeaderData(); |
| HeaderData(base::span<const uint8_t, kKeySize> key, |
| std::vector<uint8_t> prefix); |
| |
| HeaderData(const HeaderData& other); |
| HeaderData& operator=(const HeaderData& other); |
| |
| HeaderData(HeaderData&& other) noexcept; |
| HeaderData& operator=(HeaderData&& other) noexcept; |
| |
| ~HeaderData(); |
| |
| std::array<uint8_t, kKeySize> derived_key; |
| std::vector<uint8_t> nonce_prefix; |
| }; |
| |
| // Computes the derived key and extracts the nonce prefix from the header. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| base::expected<HeaderData, Error> GetHeaderData( |
| base::span<const uint8_t> header); |
| |
| // Deobfuscate data chunk using crypto::Aead (https://crsrc.org/c/crypto/aead.h) |
| // in an insecure way to act as a file access deterrent. Master key is stored in |
| // memory and can be leaked. Counter increments every chunk to protect against |
| // reordering/truncation. |
| // The size of the encrypted chunk is expected to be prepended to the input |
| // data. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| base::expected<std::vector<uint8_t>, Error> DeobfuscateDataChunk( |
| base::span<const uint8_t> data, |
| base::span<const uint8_t> key, |
| base::span<const uint8_t> nonce_prefix, |
| uint32_t counter, |
| bool is_last_chunk); |
| |
| // Insecurely deobfuscate a file by replacing the original file with the |
| // deobfuscated data. Master key is stored in memory and can be leaked. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| base::expected<void, Error> DeobfuscateFileInPlace( |
| const base::FilePath& file_path); |
| |
| // Records result of obfuscation/deobfuscation operations to UMA metrics. |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| void RecordObfuscationResult(Error result); |
| |
| // Helper function to record UMA metrics inline with return statements. |
| // TODO(crbug.com/396499421): Centralize and improve maintainability for metrics |
| // collection. |
| template <typename T> |
| COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) |
| inline base::expected<T, Error> RecordAndReturn( |
| base::expected<T, Error> result) { |
| RecordObfuscationResult(result.has_value() ? Error::kSuccess |
| : result.error()); |
| return result; |
| } |
| |
| } // namespace enterprise_obfuscation |
| |
| #endif // COMPONENTS_ENTERPRISE_OBFUSCATION_CORE_UTILS_H_ |