mirror of https://github.com/yuzu-emu/yuzu
115 lines
3.5 KiB
C++
115 lines
3.5 KiB
C++
|
// 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);
|
||
|
|
||
|
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;
|
||
|
|
||
|
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);
|
||
|
};
|
||
|
|
||
|
} // namespace FileSys
|