// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include "common/literals.h" #include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h" namespace FileSys { using namespace Common::Literals; class AesCtrCounterExtendedStorage : public IReadOnlyStorage { YUZU_NON_COPYABLE(AesCtrCounterExtendedStorage); YUZU_NON_MOVEABLE(AesCtrCounterExtendedStorage); public: static constexpr size_t BlockSize = 0x10; static constexpr size_t KeySize = 0x10; static constexpr size_t IvSize = 0x10; static constexpr size_t NodeSize = 16_KiB; class IDecryptor { public: virtual ~IDecryptor() {} virtual void Decrypt(u8* buf, size_t buf_size, const std::array& key, const std::array& iv) = 0; }; struct Entry { enum class Encryption : u8 { Encrypted = 0, NotEncrypted = 1, }; std::array offset; Encryption encryption_value; std::array reserved; s32 generation; void SetOffset(s64 value) { std::memcpy(this->offset.data(), std::addressof(value), sizeof(s64)); } s64 GetOffset() const { s64 value; std::memcpy(std::addressof(value), this->offset.data(), sizeof(s64)); return value; } }; static_assert(sizeof(Entry) == 0x10); static_assert(alignof(Entry) == 4); static_assert(std::is_trivial_v); public: static constexpr s64 QueryHeaderStorageSize() { return BucketTree::QueryHeaderStorageSize(); } static constexpr s64 QueryNodeStorageSize(s32 entry_count) { return BucketTree::QueryNodeStorageSize(NodeSize, sizeof(Entry), entry_count); } static constexpr s64 QueryEntryStorageSize(s32 entry_count) { return BucketTree::QueryEntryStorageSize(NodeSize, sizeof(Entry), entry_count); } static Result CreateSoftwareDecryptor(std::unique_ptr* out); private: mutable BucketTree m_table; VirtualFile m_data_storage; std::array m_key; u32 m_secure_value; s64 m_counter_offset; std::unique_ptr m_decryptor; public: AesCtrCounterExtendedStorage() : m_table(), m_data_storage(), m_secure_value(), m_counter_offset(), m_decryptor() {} virtual ~AesCtrCounterExtendedStorage() { this->Finalize(); } Result Initialize(const void* key, size_t key_size, u32 secure_value, s64 counter_offset, VirtualFile data_storage, VirtualFile node_storage, VirtualFile entry_storage, s32 entry_count, std::unique_ptr&& decryptor); void Finalize(); bool IsInitialized() const { return m_table.IsInitialized(); } virtual size_t Read(u8* buffer, size_t size, size_t offset) const override; virtual size_t GetSize() const override { BucketTree::Offsets offsets; ASSERT(R_SUCCEEDED(m_table.GetOffsets(std::addressof(offsets)))); return offsets.end_offset; } Result GetEntryList(Entry* out_entries, s32* out_entry_count, s32 entry_count, s64 offset, s64 size); private: Result Initialize(const void* key, size_t key_size, u32 secure_value, VirtualFile data_storage, VirtualFile table_storage); }; } // namespace FileSys