/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DOM_QUOTA_ENCRYPTEDRANDOMACCESSBLOCK_H_ #define DOM_QUOTA_ENCRYPTEDRANDOMACCESSBLOCK_H_ #include #include #include #include #include #include "mozilla/Span.h" #include "nsTArray.h" namespace mozilla::dom::quota { /** * On-disk layout of a single encrypted block (BlockSize = 4096 bytes): * * --------+-----------------------------------------------+ * offset | field size | * --------+-----------------------------------------------+ * 0 | Version (uint16_t, little-endian) 2 bytes | Header * 2 | Reserved (zeroed) 30 bytes | plaintext * --------+-----------------------------------------------+ * 32 | CipherMetadata 32 bytes | plaintext * --------+-----------------------------------------------+ * 64 | CipherPayload 4032 bytes | ciphertext * --------+-----------------------------------------------+ * 4096 * * The layout of CipherMetadata and CipherPayload is version-specific. */ class EncryptedRandomAccessBlock { public: static constexpr size_t BlockSize = 4096; template using ConstSpan = Span; template using MutableSpan = Span; EncryptedRandomAccessBlock() { mData.SetLength(BlockSize); // Zero-initialize the whole block so that reserved/unused bytes do not // expose stale data. This follows the same rationale as EncryptedBlock // (Bug 1867394). std::fill(mData.begin(), mData.end(), 0); } static constexpr size_t CipherMetadataSize = 32; private: static constexpr size_t HeaderSize = 32; using VersionType = uint16_t; static constexpr size_t VersionSize = sizeof(VersionType); static_assert(VersionSize == 2, "Version should take 2 bytes on disk."); static constexpr size_t CipherPayloadSize = BlockSize - HeaderSize - CipherMetadataSize; static_assert(CipherPayloadSize == 4032, "CipherPayload should take 4032 bytes on disk."); public: ConstSpan Header() const { return WholeBlock().Subspan<0, HeaderSize>(); } VersionType Version() const { VersionType version = std::numeric_limits::max(); memcpy(&version, mData.Elements(), VersionSize); return version; } void SetVersion(VersionType aVersion) { memcpy(mData.Elements(), &aVersion, VersionSize); } ConstSpan ReservedBytes() const { return WholeBlock().Subspan(); } static_assert(HeaderSize - VersionSize == 30, "Reserved region should take 30 bytes on disk."); ConstSpan CipherMetadata() const { return WholeBlock().Subspan(); } MutableSpan MutableCipherMetadata() { return MutableWholeBlock().Subspan(); } ConstSpan CipherPayload() const { return WholeBlock() .Subspan(); } MutableSpan MutableCipherPayload() { return MutableWholeBlock() .Subspan(); } void AssignFromBytes(ConstSpan aData) { memcpy(mData.Elements(), aData.data(), BlockSize); } private: ConstSpan WholeBlock() const { return mData; } MutableSpan MutableWholeBlock() { return mData; } nsTArray mData; }; } // namespace mozilla::dom::quota #endif // DOM_QUOTA_ENCRYPTEDRANDOMACCESSBLOCK_H_