diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h b/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h new file mode 100644 index 000000000..d0e9ceed0 --- /dev/null +++ b/src/core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <optional> + +#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<u8, KeySize>& key, + const std::array<u8, IvSize>& iv) = 0; + }; + + struct Entry { + enum class Encryption : u8 { + Encrypted = 0, + NotEncrypted = 1, + }; + + std::array<u8, sizeof(s64)> offset; + Encryption encryption_value; + std::array<u8, 3> 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<Entry>); + +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<IDecryptor>* out); + +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<IDecryptor>&& 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); + +private: + mutable BucketTree m_table; + VirtualFile m_data_storage; + std::array<u8, KeySize> m_key; + u32 m_secure_value; + s64 m_counter_offset; + std::unique_ptr<IDecryptor> m_decryptor; +}; + +} // namespace FileSys |