Source code

Revision control

Copy as Markdown

Other Tools

/* 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 <algorithm>
#include <cstddef>
#include <cstdint>
#include "mozilla/EndianUtils.h"
#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
*
* This class only exposes the on-disk (= ciphertext-side) byte regions
* above. The internal layout of CipherMetadata and of the decrypted
* CipherPayload is the responsibility of separate view classes:
*
* - CipherMetadata: version-specific. See
* EncryptedRandomAccessBlockCipherMetadataViewV1 (for V1).
*
* - Decrypted CipherPayload: version-independent. See
* DecryptedRandomAccessBlockCipherPayloadView. The view is applied
* to the decrypted plaintext (held in a separate buffer by the
* caller), not to the encrypted bytes stored in this block.
*/
class EncryptedRandomAccessBlock {
public:
static constexpr size_t BlockSize = 4096;
using VersionType = uint16_t;
static constexpr VersionType kEncryptedRandomAccessBlockLatestVersion = 1;
template <size_t N>
using ConstSpan = Span<const uint8_t, N>;
template <size_t N>
using MutableSpan = Span<uint8_t, N>;
explicit EncryptedRandomAccessBlock(
VersionType aVersion = kEncryptedRandomAccessBlockLatestVersion) {
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);
SetVersion(aVersion);
}
static constexpr size_t CipherMetadataSize = 32;
static constexpr size_t HeaderSize = 32;
private:
static constexpr size_t VersionSize = sizeof(VersionType);
static_assert(VersionSize == 2, "Version should take 2 bytes on disk.");
public:
ConstSpan<HeaderSize> Header() const {
return WholeBlock().Subspan<0, HeaderSize>();
}
VersionType Version() const {
return mozilla::LittleEndian::readUint16(mData.Elements());
}
void SetVersion(VersionType aVersion) {
mozilla::LittleEndian::writeUint16(mData.Elements(), aVersion);
}
ConstSpan<HeaderSize - VersionSize> ReservedBytes() const {
return WholeBlock().Subspan<VersionSize, HeaderSize - VersionSize>();
}
static_assert(HeaderSize - VersionSize == 30,
"Reserved region should take 30 bytes on disk.");
ConstSpan<CipherMetadataSize> CipherMetadata() const {
return WholeBlock().Subspan<HeaderSize, CipherMetadataSize>();
}
MutableSpan<CipherMetadataSize> MutableCipherMetadata() {
return MutableWholeBlock().Subspan<HeaderSize, CipherMetadataSize>();
}
static constexpr size_t CipherPayloadSize =
BlockSize - HeaderSize - CipherMetadataSize;
static_assert(CipherPayloadSize == 4032,
"CipherPayload should take 4032 bytes on disk.");
ConstSpan<CipherPayloadSize> CipherPayload() const {
return WholeBlock()
.Subspan<HeaderSize + CipherMetadataSize, CipherPayloadSize>();
}
MutableSpan<CipherPayloadSize> MutableCipherPayload() {
return MutableWholeBlock()
.Subspan<HeaderSize + CipherMetadataSize, CipherPayloadSize>();
}
ConstSpan<BlockSize> WholeBlock() const { return mData; }
MutableSpan<BlockSize> MutableWholeBlock() { return mData; }
private:
nsTArray<uint8_t> mData;
};
} // namespace mozilla::dom::quota
#endif // DOM_QUOTA_ENCRYPTEDRANDOMACCESSBLOCK_H_