mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-03 08:08:39 -04:00
fs: revise NcaFileSystemDriver for latest semantics
This commit is contained in:
parent
ccf29a1302
commit
52296fc2dd
37 changed files with 1612 additions and 1026 deletions
|
@ -174,7 +174,7 @@ namespace ams::fssystem {
|
|||
NcaAesCtrUpperIv upper_iv = { .part = { .generation = static_cast<u32>(cur_entry.generation), .secure_value = m_secure_value } };
|
||||
|
||||
u8 iv[IvSize];
|
||||
AesCtrStorage::MakeIv(iv, IvSize, upper_iv.value, counter_offset);
|
||||
AesCtrStorageByPointer::MakeIv(iv, IvSize, upper_iv.value, counter_offset);
|
||||
|
||||
/* Decrypt. */
|
||||
m_decryptor->Decrypt(cur_data, cur_size, m_key, KeySize, iv, IvSize);
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
void AesCtrStorage::MakeIv(void *dst, size_t dst_size, u64 upper, s64 offset) {
|
||||
/* TODO: util::BytePtr? */
|
||||
template<typename BasePointer>
|
||||
void AesCtrStorage<BasePointer>::MakeIv(void *dst, size_t dst_size, u64 upper, s64 offset) {
|
||||
AMS_ASSERT(dst != nullptr);
|
||||
AMS_ASSERT(dst_size == IvSize);
|
||||
AMS_ASSERT(offset >= 0);
|
||||
|
@ -30,7 +30,8 @@ namespace ams::fssystem {
|
|||
util::StoreBigEndian(reinterpret_cast<s64 *>(out_addr + sizeof(u64)), static_cast<s64>(offset / BlockSize));
|
||||
}
|
||||
|
||||
AesCtrStorage::AesCtrStorage(IStorage *base, const void *key, size_t key_size, const void *iv, size_t iv_size) : m_base_storage(base) {
|
||||
template<typename BasePointer>
|
||||
AesCtrStorage<BasePointer>::AesCtrStorage(BasePointer base, const void *key, size_t key_size, const void *iv, size_t iv_size) : m_base_storage(std::move(base)) {
|
||||
AMS_ASSERT(base != nullptr);
|
||||
AMS_ASSERT(key != nullptr);
|
||||
AMS_ASSERT(iv != nullptr);
|
||||
|
@ -42,7 +43,8 @@ namespace ams::fssystem {
|
|||
std::memcpy(m_iv, iv, IvSize);
|
||||
}
|
||||
|
||||
Result AesCtrStorage::Read(s64 offset, void *buffer, size_t size) {
|
||||
template<typename BasePointer>
|
||||
Result AesCtrStorage<BasePointer>::Read(s64 offset, void *buffer, size_t size) {
|
||||
/* Allow zero-size reads. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -71,7 +73,8 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result AesCtrStorage::Write(s64 offset, const void *buffer, size_t size) {
|
||||
template<typename BasePointer>
|
||||
Result AesCtrStorage<BasePointer>::Write(s64 offset, const void *buffer, size_t size) {
|
||||
/* Allow zero-size writes. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -124,20 +127,24 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result AesCtrStorage::Flush() {
|
||||
template<typename BasePointer>
|
||||
Result AesCtrStorage<BasePointer>::Flush() {
|
||||
return m_base_storage->Flush();
|
||||
}
|
||||
|
||||
Result AesCtrStorage::SetSize(s64 size) {
|
||||
template<typename BasePointer>
|
||||
Result AesCtrStorage<BasePointer>::SetSize(s64 size) {
|
||||
AMS_UNUSED(size);
|
||||
return fs::ResultUnsupportedOperationInAesCtrStorageA();
|
||||
}
|
||||
|
||||
Result AesCtrStorage::GetSize(s64 *out) {
|
||||
template<typename BasePointer>
|
||||
Result AesCtrStorage<BasePointer>::GetSize(s64 *out) {
|
||||
return m_base_storage->GetSize(out);
|
||||
}
|
||||
|
||||
Result AesCtrStorage::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
template<typename BasePointer>
|
||||
Result AesCtrStorage<BasePointer>::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
/* Handle the zero size case. */
|
||||
if (size == 0) {
|
||||
if (op_id == fs::OperationId::QueryRange) {
|
||||
|
@ -179,4 +186,7 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
template class AesCtrStorage<fs::IStorage *>;
|
||||
template class AesCtrStorage<std::shared_ptr<fs::IStorage>>;
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,20 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
AesXtsStorage::AesXtsStorage(IStorage *base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size) : m_base_storage(base), m_block_size(block_size), m_mutex() {
|
||||
template<typename BasePointer>
|
||||
void AesXtsStorage<BasePointer>::MakeAesXtsIv(void *dst, size_t dst_size, s64 offset, size_t block_size) {
|
||||
AMS_ASSERT(dst != nullptr);
|
||||
AMS_ASSERT(dst_size == IvSize);
|
||||
AMS_ASSERT(offset >= 0);
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
const uintptr_t out_addr = reinterpret_cast<uintptr_t>(dst);
|
||||
|
||||
util::StoreBigEndian<s64>(reinterpret_cast<s64 *>(out_addr + sizeof(s64)), offset / block_size);
|
||||
}
|
||||
|
||||
template<typename BasePointer>
|
||||
AesXtsStorage<BasePointer>::AesXtsStorage(BasePointer base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size) : m_base_storage(std::move(base)), m_block_size(block_size), m_mutex() {
|
||||
AMS_ASSERT(base != nullptr);
|
||||
AMS_ASSERT(key1 != nullptr);
|
||||
AMS_ASSERT(key2 != nullptr);
|
||||
|
@ -32,7 +45,8 @@ namespace ams::fssystem {
|
|||
std::memcpy(m_iv, iv, IvSize);
|
||||
}
|
||||
|
||||
Result AesXtsStorage::Read(s64 offset, void *buffer, size_t size) {
|
||||
template<typename BasePointer>
|
||||
Result AesXtsStorage<BasePointer>::Read(s64 offset, void *buffer, size_t size) {
|
||||
/* Allow zero-size reads. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -97,7 +111,8 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result AesXtsStorage::Write(s64 offset, const void *buffer, size_t size) {
|
||||
template<typename BasePointer>
|
||||
Result AesXtsStorage<BasePointer>::Write(s64 offset, const void *buffer, size_t size) {
|
||||
/* Allow zero-size writes. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -194,21 +209,25 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result AesXtsStorage::Flush() {
|
||||
template<typename BasePointer>
|
||||
Result AesXtsStorage<BasePointer>::Flush() {
|
||||
return m_base_storage->Flush();
|
||||
}
|
||||
|
||||
Result AesXtsStorage::SetSize(s64 size) {
|
||||
template<typename BasePointer>
|
||||
Result AesXtsStorage<BasePointer>::SetSize(s64 size) {
|
||||
R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultUnexpectedInAesXtsStorageA());
|
||||
|
||||
return m_base_storage->SetSize(size);
|
||||
}
|
||||
|
||||
Result AesXtsStorage::GetSize(s64 *out) {
|
||||
template<typename BasePointer>
|
||||
Result AesXtsStorage<BasePointer>::GetSize(s64 *out) {
|
||||
return m_base_storage->GetSize(out);
|
||||
}
|
||||
|
||||
Result AesXtsStorage::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
template<typename BasePointer>
|
||||
Result AesXtsStorage<BasePointer>::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
/* Handle the zero size case. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -219,4 +238,7 @@ namespace ams::fssystem {
|
|||
return m_base_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
|
||||
}
|
||||
|
||||
template class AesXtsStorage<fs::IStorage *>;
|
||||
template class AesXtsStorage<std::shared_ptr<fs::IStorage>>;
|
||||
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ namespace ams::fssystem {
|
|||
/* TODO FS-REIMPL: Revise for accuracy. */
|
||||
util::ConstructAt(g_rom_fs_creator, GetPointer(g_allocator));
|
||||
util::ConstructAt(g_partition_fs_creator);
|
||||
util::ConstructAt(g_storage_on_nca_creator, GetPointer(g_allocator), *GetNcaCryptoConfiguration(is_prod), is_prod, GetPointer(g_buffer_manager));
|
||||
util::ConstructAt(g_storage_on_nca_creator, GetPointer(g_allocator), *GetNcaCryptoConfiguration(is_prod), *GetNcaCompressionConfiguration(), GetPointer(g_buffer_manager), fs::impl::GetNcaHashGeneratorFactorySelector());
|
||||
|
||||
/* TODO FS-REIMPL: Initialize other creators. */
|
||||
|
||||
|
|
|
@ -33,16 +33,19 @@ namespace ams::fssystem {
|
|||
|
||||
}
|
||||
|
||||
Result HierarchicalSha256Storage::Initialize(IStorage **base_storages, s32 layer_count, size_t htbs, void *hash_buf, size_t hash_buf_size) {
|
||||
template<typename BaseStorageType>
|
||||
Result HierarchicalSha256Storage<BaseStorageType>::Initialize(BaseStorageType *base_storages, s32 layer_count, size_t htbs, void *hash_buf, size_t hash_buf_size, fssystem::IHash256GeneratorFactory *hgf) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(layer_count == LayerCount);
|
||||
AMS_ASSERT(util::IsPowerOfTwo(htbs));
|
||||
AMS_ASSERT(hash_buf != nullptr);
|
||||
AMS_ASSERT(hgf != nullptr);
|
||||
AMS_UNUSED(layer_count);
|
||||
|
||||
/* Set size tracking members. */
|
||||
m_hash_target_block_size = htbs;
|
||||
m_log_size_ratio = Log2(m_hash_target_block_size / HashSize);
|
||||
m_hash_generator_factory = hgf;
|
||||
|
||||
/* Get the base storage size. */
|
||||
R_TRY(base_storages[2]->GetSize(std::addressof(m_base_storage_size)));
|
||||
|
@ -72,13 +75,14 @@ namespace ams::fssystem {
|
|||
|
||||
/* Calculate and verify the master hash. */
|
||||
u8 calc_hash[HashSize];
|
||||
crypto::GenerateSha256Hash(calc_hash, sizeof(calc_hash), m_hash_buffer, static_cast<size_t>(hash_storage_size));
|
||||
m_hash_generator_factory->GenerateHash(calc_hash, sizeof(calc_hash), m_hash_buffer, static_cast<size_t>(hash_storage_size));
|
||||
R_UNLESS(crypto::IsSameBytes(master_hash, calc_hash, HashSize), fs::ResultHierarchicalSha256HashVerificationFailed());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalSha256Storage::Read(s64 offset, void *buffer, size_t size) {
|
||||
template<typename BaseStorageType>
|
||||
Result HierarchicalSha256Storage<BaseStorageType>::Read(s64 offset, void *buffer, size_t size) {
|
||||
/* Succeed if zero-size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -103,7 +107,7 @@ namespace ams::fssystem {
|
|||
/* Generate the hash of the region we're validating. */
|
||||
u8 hash[HashSize];
|
||||
const auto cur_size = static_cast<size_t>(std::min<s64>(m_hash_target_block_size, remaining_size));
|
||||
crypto::GenerateSha256Hash(hash, sizeof(hash), static_cast<u8 *>(buffer) + (cur_offset - offset), cur_size);
|
||||
m_hash_generator_factory->GenerateHash(hash, sizeof(hash), static_cast<u8 *>(buffer) + (cur_offset - offset), cur_size);
|
||||
|
||||
AMS_ASSERT(static_cast<size_t>(cur_offset >> m_log_size_ratio) < m_hash_buffer_size);
|
||||
|
||||
|
@ -125,7 +129,8 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalSha256Storage::Write(s64 offset, const void *buffer, size_t size) {
|
||||
template<typename BaseStorageType>
|
||||
Result HierarchicalSha256Storage<BaseStorageType>::Write(s64 offset, const void *buffer, size_t size) {
|
||||
/* Succeed if zero-size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
@ -147,7 +152,7 @@ namespace ams::fssystem {
|
|||
{
|
||||
/* Temporarily increase our thread priority. */
|
||||
ScopedThreadPriorityChanger cp(+1, ScopedThreadPriorityChanger::Mode::Relative);
|
||||
crypto::GenerateSha256Hash(hash, sizeof(hash), static_cast<const u8 *>(buffer) + (cur_offset - offset), cur_size);
|
||||
m_hash_generator_factory->GenerateHash(hash, sizeof(hash), static_cast<const u8 *>(buffer) + (cur_offset - offset), cur_size);
|
||||
}
|
||||
|
||||
/* Write the data. */
|
||||
|
@ -167,19 +172,26 @@ namespace ams::fssystem {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalSha256Storage::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
/* Succeed if zero-size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
template<typename BaseStorageType>
|
||||
Result HierarchicalSha256Storage<BaseStorageType>::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
if (op_id == fs::OperationId::Invalidate) {
|
||||
return m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size);
|
||||
} else {
|
||||
/* Succeed if zero-size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate preconditions. */
|
||||
R_UNLESS(util::IsAligned(offset, m_hash_target_block_size), fs::ResultInvalidArgument());
|
||||
R_UNLESS(util::IsAligned(size, m_hash_target_block_size), fs::ResultInvalidArgument());
|
||||
/* Validate preconditions. */
|
||||
R_UNLESS(util::IsAligned(offset, m_hash_target_block_size), fs::ResultInvalidArgument());
|
||||
R_UNLESS(util::IsAligned(size, m_hash_target_block_size), fs::ResultInvalidArgument());
|
||||
|
||||
/* Determine size to use. */
|
||||
const auto reduced_size = std::min<s64>(m_base_storage_size, util::AlignUp(offset + size, m_hash_target_block_size)) - offset;
|
||||
/* Determine size to use. */
|
||||
const auto reduced_size = std::min<s64>(m_base_storage_size, util::AlignUp(offset + size, m_hash_target_block_size)) - offset;
|
||||
|
||||
/* Operate on the base storage. */
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, offset, reduced_size, src, src_size);
|
||||
/* Operate on the base storage. */
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, offset, reduced_size, src, src_size);
|
||||
}
|
||||
}
|
||||
|
||||
template class HierarchicalSha256Storage<fs::SubStorage>;
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
template<typename BaseStorageType>
|
||||
class HierarchicalSha256Storage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(HierarchicalSha256Storage);
|
||||
NON_MOVEABLE(HierarchicalSha256Storage);
|
||||
|
@ -25,17 +26,18 @@ namespace ams::fssystem {
|
|||
static constexpr s32 LayerCount = 3;
|
||||
static constexpr size_t HashSize = crypto::Sha256Generator::HashSize;
|
||||
private:
|
||||
os::SdkMutex m_mutex;
|
||||
IStorage *m_base_storage;
|
||||
BaseStorageType m_base_storage;
|
||||
s64 m_base_storage_size;
|
||||
char *m_hash_buffer;
|
||||
size_t m_hash_buffer_size;
|
||||
s32 m_hash_target_block_size;
|
||||
s32 m_log_size_ratio;
|
||||
fssystem::IHash256GeneratorFactory *m_hash_generator_factory;
|
||||
os::SdkMutex m_mutex;
|
||||
public:
|
||||
HierarchicalSha256Storage() : m_mutex() { /* ... */ }
|
||||
|
||||
Result Initialize(IStorage **base_storages, s32 layer_count, size_t htbs, void *hash_buf, size_t hash_buf_size);
|
||||
Result Initialize(BaseStorageType *base_storages, s32 layer_count, size_t htbs, void *hash_buf, size_t hash_buf_size, fssystem::IHash256GeneratorFactory *hgf);
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
|
||||
|
@ -46,7 +48,7 @@ namespace ams::fssystem {
|
|||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess();
|
||||
return m_base_storage->Flush();
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
Result IntegrityRomFsStorage::Initialize(save::HierarchicalIntegrityVerificationInformation level_hash_info, Hash master_hash, save::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation storage_info, IBufferManager *bm) {
|
||||
Result IntegrityRomFsStorage::Initialize(save::HierarchicalIntegrityVerificationInformation level_hash_info, Hash master_hash, save::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation storage_info, IBufferManager *bm, IHash256GeneratorFactory *hgf) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(bm != nullptr);
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace ams::fssystem {
|
|||
}
|
||||
|
||||
/* Initialize our integrity storage. */
|
||||
return m_integrity_storage.Initialize(level_hash_info, storage_info, std::addressof(m_buffers), std::addressof(m_mutex), fs::StorageType_RomFs);
|
||||
return m_integrity_storage.Initialize(level_hash_info, storage_info, std::addressof(m_buffers), hgf, std::addressof(m_mutex), fs::StorageType_RomFs);
|
||||
}
|
||||
|
||||
void IntegrityRomFsStorage::Finalize() {
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class MemoryResourceBufferHoldStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(MemoryResourceBufferHoldStorage);
|
||||
NON_MOVEABLE(MemoryResourceBufferHoldStorage);
|
||||
private:
|
||||
std::shared_ptr<fs::IStorage> m_storage;
|
||||
MemoryResource *m_memory_resource;
|
||||
void *m_buffer;
|
||||
size_t m_buffer_size;
|
||||
public:
|
||||
MemoryResourceBufferHoldStorage(std::shared_ptr<fs::IStorage> storage, MemoryResource *mr, size_t buffer_size) : m_storage(std::move(storage)), m_memory_resource(mr), m_buffer(m_memory_resource->Allocate(buffer_size)), m_buffer_size(buffer_size) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~MemoryResourceBufferHoldStorage() {
|
||||
/* If we have a buffer, deallocate it. */
|
||||
if (m_buffer != nullptr) {
|
||||
m_memory_resource->Deallocate(m_buffer, m_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool IsValid() const { return m_buffer != nullptr; }
|
||||
ALWAYS_INLINE void *GetBuffer() const { return m_buffer; }
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_storage != nullptr);
|
||||
|
||||
return m_storage->Read(offset, buffer, size);
|
||||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_storage != nullptr);
|
||||
|
||||
return m_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_storage != nullptr);
|
||||
|
||||
return m_storage->GetSize(out);
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_storage != nullptr);
|
||||
|
||||
return m_storage->Flush();
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_storage != nullptr);
|
||||
|
||||
return m_storage->Write(offset, buffer, size);
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_storage != nullptr);
|
||||
|
||||
return m_storage->SetSize(size);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -20,6 +20,7 @@ namespace ams::fssystem {
|
|||
u8 NcaHeader::GetProperKeyGeneration() const {
|
||||
return std::max(this->key_generation, this->key_generation_2);
|
||||
}
|
||||
|
||||
bool NcaPatchInfo::HasIndirectTable() const {
|
||||
return this->indirect_size != 0;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace ams::fssystem {
|
|||
|
||||
}
|
||||
|
||||
NcaReader::NcaReader() : m_shared_base_storage(), m_header_storage(), m_body_storage(), m_decrypt_aes_ctr(), m_decrypt_aes_ctr_external(), m_is_software_aes_prioritized(false), m_header_encryption_type(NcaHeader::EncryptionType::Auto) {
|
||||
NcaReader::NcaReader() : m_body_storage(), m_header_storage(), m_decrypt_aes_ctr(), m_decrypt_aes_ctr_external(), m_is_software_aes_prioritized(false), m_header_encryption_type(NcaHeader::EncryptionType::Auto), m_get_decompressor(), m_hash_generator_factory() {
|
||||
std::memset(std::addressof(m_header), 0, sizeof(m_header));
|
||||
std::memset(std::addressof(m_decryption_keys), 0, sizeof(m_decryption_keys));
|
||||
std::memset(std::addressof(m_external_decryption_key), 0, sizeof(m_external_decryption_key));
|
||||
|
@ -45,33 +45,33 @@ namespace ams::fssystem {
|
|||
/* ... */
|
||||
}
|
||||
|
||||
Result NcaReader::Initialize(std::shared_ptr<fs::IStorage> base_storage, const NcaCryptoConfiguration &crypto_cfg) {
|
||||
m_shared_base_storage = base_storage;
|
||||
return this->Initialize(m_shared_base_storage.get(), crypto_cfg);
|
||||
}
|
||||
|
||||
Result NcaReader::Initialize(fs::IStorage *base_storage, const NcaCryptoConfiguration &crypto_cfg) {
|
||||
Result NcaReader::Initialize(std::shared_ptr<fs::IStorage> base_storage, const NcaCryptoConfiguration &crypto_cfg, const NcaCompressionConfiguration &compression_cfg, IHash256GeneratorFactorySelector *hgf_selector) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(base_storage != nullptr);
|
||||
AMS_ASSERT(hgf_selector != nullptr);
|
||||
AMS_ASSERT(m_body_storage == nullptr);
|
||||
|
||||
/* Check that the crypto config is valid. */
|
||||
R_UNLESS(crypto_cfg.generate_key != nullptr, fs::ResultInvalidArgument());
|
||||
|
||||
/* Generate keys for header. */
|
||||
using AesXtsStorageForNcaHeader = AesXtsStorageBySharedPointer;
|
||||
|
||||
u8 header_decryption_keys[NcaCryptoConfiguration::HeaderEncryptionKeyCount][NcaCryptoConfiguration::Aes128KeySize];
|
||||
for (size_t i = 0; i < NcaCryptoConfiguration::HeaderEncryptionKeyCount; i++) {
|
||||
crypto_cfg.generate_key(header_decryption_keys[i], AesXtsStorage::KeySize, crypto_cfg.header_encrypted_encryption_keys[i], AesXtsStorage::KeySize, static_cast<s32>(KeyType::NcaHeaderKey), crypto_cfg);
|
||||
crypto_cfg.generate_key(header_decryption_keys[i], AesXtsStorageForNcaHeader::KeySize, crypto_cfg.header_encrypted_encryption_keys[i], AesXtsStorageForNcaHeader::KeySize, static_cast<s32>(KeyType::NcaHeaderKey), crypto_cfg);
|
||||
}
|
||||
|
||||
/* Create the header storage. */
|
||||
const u8 header_iv[AesXtsStorage::IvSize] = {};
|
||||
std::unique_ptr<fs::IStorage> work_header_storage = std::make_unique<AesXtsStorage>(base_storage, header_decryption_keys[0], header_decryption_keys[1], AesXtsStorage::KeySize, header_iv, AesXtsStorage::IvSize, NcaHeader::XtsBlockSize);
|
||||
const u8 header_iv[AesXtsStorageForNcaHeader::IvSize] = {};
|
||||
std::unique_ptr<fs::IStorage> work_header_storage = std::make_unique<AesXtsStorageForNcaHeader>(base_storage, header_decryption_keys[0], header_decryption_keys[1], AesXtsStorageForNcaHeader::KeySize, header_iv, AesXtsStorageForNcaHeader::IvSize, NcaHeader::XtsBlockSize);
|
||||
R_UNLESS(work_header_storage != nullptr, fs::ResultAllocationFailureInNcaReaderA());
|
||||
|
||||
/* Read the header. */
|
||||
R_TRY(work_header_storage->Read(0, std::addressof(m_header), sizeof(m_header)));
|
||||
|
||||
/* Validate the magic. */
|
||||
if (Result magic_result = CheckNcaMagic(m_header.magic); R_FAILED(magic_result)) {
|
||||
if (const Result magic_result = CheckNcaMagic(m_header.magic); R_FAILED(magic_result)) {
|
||||
/* If we're not allowed to use plaintext headers, stop here. */
|
||||
R_UNLESS(crypto_cfg.is_plaintext_header_available, magic_result);
|
||||
|
||||
|
@ -85,6 +85,7 @@ namespace ams::fssystem {
|
|||
work_header_storage.reset(new fs::SubStorage(base_storage, 0, base_storage_size));
|
||||
R_UNLESS(work_header_storage != nullptr, fs::ResultAllocationFailureInNcaReaderA());
|
||||
|
||||
/* Set encryption type as plaintext. */
|
||||
m_header_encryption_type = NcaHeader::EncryptionType::None;
|
||||
}
|
||||
|
||||
|
@ -101,6 +102,7 @@ namespace ams::fssystem {
|
|||
const size_t exp_size = NcaCryptoConfiguration::Rsa2048KeyPublicExponentSize;
|
||||
const u8 *msg = static_cast<const u8 *>(static_cast<const void *>(std::addressof(m_header.magic)));
|
||||
const size_t msg_size = NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount;
|
||||
|
||||
const bool is_signature_valid = crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size);
|
||||
R_UNLESS(is_signature_valid, fs::ResultNcaHeaderSignature1VerificationFailed());
|
||||
}
|
||||
|
@ -128,14 +130,22 @@ namespace ams::fssystem {
|
|||
m_decrypt_aes_ctr = crypto_cfg.decrypt_aes_ctr;
|
||||
m_decrypt_aes_ctr_external = crypto_cfg.decrypt_aes_ctr_external;
|
||||
|
||||
/* Set our decompressor function getter. */
|
||||
m_get_decompressor = compression_cfg.get_decompressor;
|
||||
|
||||
/* Set our hash generator factory. */
|
||||
m_hash_generator_factory = hgf_selector->GetFactory();
|
||||
AMS_ASSERT(m_hash_generator_factory != nullptr);
|
||||
|
||||
/* Set our storages. */
|
||||
m_header_storage = std::move(work_header_storage);
|
||||
m_body_storage = base_storage;
|
||||
m_body_storage = std::move(base_storage);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
fs::IStorage *NcaReader::GetBodyStorage() {
|
||||
std::shared_ptr<fs::IStorage> NcaReader::GetSharedBodyStorage() {
|
||||
AMS_ASSERT(m_body_storage != nullptr);
|
||||
return m_body_storage;
|
||||
}
|
||||
|
||||
|
@ -270,7 +280,7 @@ namespace ams::fssystem {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NcaReader::HasInternalDecryptionKeyForAesHardwareSpeedEmulation() const {
|
||||
bool NcaReader::HasInternalDecryptionKeyForAesHw() const {
|
||||
constexpr const u8 ZeroKey[crypto::AesDecryptor128::KeySize] = {};
|
||||
return !crypto::IsSameBytes(ZeroKey, this->GetDecryptionKey(NcaHeader::DecryptionKey_AesCtrHw), crypto::AesDecryptor128::KeySize);
|
||||
}
|
||||
|
@ -319,6 +329,16 @@ namespace ams::fssystem {
|
|||
return m_decrypt_aes_ctr_external;
|
||||
}
|
||||
|
||||
GetDecompressorFunction NcaReader::GetDecompressor() const {
|
||||
AMS_ASSERT(m_get_decompressor != nullptr);
|
||||
return m_get_decompressor;
|
||||
}
|
||||
|
||||
IHash256GeneratorFactory *NcaReader::GetHashGeneratorFactory() const {
|
||||
AMS_ASSERT(m_hash_generator_factory != nullptr);
|
||||
return m_hash_generator_factory;
|
||||
}
|
||||
|
||||
NcaHeader::EncryptionType NcaReader::GetEncryptionType() const {
|
||||
return m_header_encryption_type;
|
||||
}
|
||||
|
@ -331,20 +351,19 @@ namespace ams::fssystem {
|
|||
return m_header_storage->Read(offset, dst, sizeof(NcaFsHeader));
|
||||
}
|
||||
|
||||
Result NcaReader::VerifyHeaderSign2(const void *mod, size_t mod_size) {
|
||||
AMS_ASSERT(m_body_storage != nullptr);
|
||||
constexpr const u8 HeaderSign2KeyPublicExponent[] = { 0x01, 0x00, 0x01 };
|
||||
void NcaReader::GetHeaderSign2(void *dst, size_t size) {
|
||||
AMS_ASSERT(dst != nullptr);
|
||||
AMS_ASSERT(size == NcaHeader::HeaderSignSize);
|
||||
|
||||
const u8 *sig = m_header.header_sign_2;
|
||||
const size_t sig_size = NcaHeader::HeaderSignSize;
|
||||
const u8 *exp = HeaderSign2KeyPublicExponent;
|
||||
const size_t exp_size = sizeof(HeaderSign2KeyPublicExponent);
|
||||
const u8 *msg = static_cast<const u8 *>(static_cast<const void *>(std::addressof(m_header.magic)));
|
||||
const size_t msg_size = NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount;
|
||||
const bool is_signature_valid = crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size);
|
||||
R_UNLESS(is_signature_valid, fs::ResultNcaHeaderSignature2VerificationFailed());
|
||||
std::memcpy(dst, m_header.header_sign_2, size);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
void NcaReader::GetHeaderSign2TargetHash(void *dst, size_t size) {
|
||||
AMS_ASSERT(m_hash_generator_factory != nullptr);
|
||||
AMS_ASSERT(dst != nullptr);
|
||||
AMS_ASSERT(size == IHash256Generator::HashSize);
|
||||
|
||||
return m_hash_generator_factory->GenerateHash(dst, size, static_cast<const void *>(std::addressof(m_header.magic)), NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount);
|
||||
}
|
||||
|
||||
Result NcaFsHeaderReader::Initialize(const NcaReader &reader, s32 index) {
|
||||
|
@ -440,4 +459,19 @@ namespace ams::fssystem {
|
|||
return m_data.sparse_info;
|
||||
}
|
||||
|
||||
bool NcaFsHeaderReader::ExistsCompressionLayer() const {
|
||||
AMS_ASSERT(this->IsInitialized());
|
||||
return m_data.compression_info.bucket.offset != 0 && m_data.compression_info.bucket.size != 0;
|
||||
}
|
||||
|
||||
NcaCompressionInfo &NcaFsHeaderReader::GetCompressionInfo() {
|
||||
AMS_ASSERT(this->IsInitialized());
|
||||
return m_data.compression_info;
|
||||
}
|
||||
|
||||
const NcaCompressionInfo &NcaFsHeaderReader::GetCompressionInfo() const {
|
||||
AMS_ASSERT(this->IsInitialized());
|
||||
return m_data.compression_info;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ namespace ams::fssystem {
|
|||
private:
|
||||
os::SdkMutex m_mutex;
|
||||
BlockCache m_block_cache;
|
||||
fs::IStorage * const m_base_storage;
|
||||
std::shared_ptr<fs::IStorage> m_base_storage;
|
||||
s32 m_block_size;
|
||||
public:
|
||||
ReadOnlyBlockCacheStorage(IStorage *bs, s32 bsz, char *buf, size_t buf_size, s32 cache_block_count) : m_mutex(), m_block_cache(), m_base_storage(bs), m_block_size(bsz) {
|
||||
ReadOnlyBlockCacheStorage(std::shared_ptr<fs::IStorage> bs, s32 bsz, char *buf, size_t buf_size, s32 cache_block_count) : m_mutex(), m_block_cache(), m_base_storage(std::move(bs)), m_block_size(bsz) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(buf_size >= static_cast<size_t>(m_block_size));
|
||||
AMS_ASSERT(util::IsPowerOfTwo(m_block_size));
|
||||
|
@ -88,32 +88,21 @@ namespace ams::fssystem {
|
|||
}
|
||||
}
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(util::IsAligned(offset, m_block_size));
|
||||
AMS_ASSERT(util::IsAligned(size, m_block_size));
|
||||
|
||||
/* If invalidating cache, invalidate our blocks. */
|
||||
if (op_id == fs::OperationId::Invalidate) {
|
||||
R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
|
||||
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
const size_t cache_block_count = m_block_cache.GetSize();
|
||||
BlockCache valid_cache;
|
||||
|
||||
for (size_t count = 0; count < cache_block_count; ++count) {
|
||||
for (size_t i = 0; i < cache_block_count; ++i) {
|
||||
auto lru = m_block_cache.PopLruNode();
|
||||
if (offset <= lru->m_key && lru->m_key < offset + size) {
|
||||
m_block_cache.PushMruNode(std::move(lru), -1);
|
||||
} else {
|
||||
valid_cache.PushMruNode(std::move(lru), lru->m_key);
|
||||
}
|
||||
m_block_cache.PushMruNode(std::move(lru), -1);
|
||||
}
|
||||
|
||||
while (!valid_cache.IsEmpty()) {
|
||||
auto lru = valid_cache.PopLruNode();
|
||||
m_block_cache.PushMruNode(std::move(lru), lru->m_key);
|
||||
}
|
||||
return ResultSuccess();
|
||||
} else {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(util::IsAligned(offset, m_block_size));
|
||||
AMS_ASSERT(util::IsAligned(size, m_block_size));
|
||||
}
|
||||
|
||||
/* Operate on the base storage. */
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace ams::fssystem::save {
|
|||
m_storage = fs::SubStorage();
|
||||
}
|
||||
|
||||
Result HierarchicalIntegrityVerificationStorage::Initialize(const HierarchicalIntegrityVerificationInformation &info, HierarchicalStorageInformation storage, FileSystemBufferManagerSet *bufs, os::SdkRecursiveMutex *mtx, fs::StorageType storage_type) {
|
||||
Result HierarchicalIntegrityVerificationStorage::Initialize(const HierarchicalIntegrityVerificationInformation &info, HierarchicalStorageInformation storage, FileSystemBufferManagerSet *bufs, IHash256GeneratorFactory *hgf, os::SdkRecursiveMutex *mtx, fs::StorageType storage_type) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(bufs != nullptr);
|
||||
AMS_ASSERT(IntegrityMinLayerCount <= info.max_layers && info.max_layers <= IntegrityMaxLayerCount);
|
||||
|
@ -168,7 +168,7 @@ namespace ams::fssystem::save {
|
|||
{
|
||||
fs::HashSalt mac;
|
||||
crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[0].key, KeyArray[0].size);
|
||||
m_verify_storages[0].Initialize(storage[HierarchicalStorageInformation::MasterStorage], storage[HierarchicalStorageInformation::Layer1Storage], static_cast<s64>(1) << info.info[0].block_order, HashSize, m_buffers->buffers[m_max_layers - 2], mac, false, storage_type);
|
||||
m_verify_storages[0].Initialize(storage[HierarchicalStorageInformation::MasterStorage], storage[HierarchicalStorageInformation::Layer1Storage], static_cast<s64>(1) << info.info[0].block_order, HashSize, m_buffers->buffers[m_max_layers - 2], hgf, mac, false, storage_type);
|
||||
}
|
||||
|
||||
/* Ensure we don't leak state if further initialization goes wrong. */
|
||||
|
@ -203,7 +203,7 @@ namespace ams::fssystem::save {
|
|||
fs::SubStorage buffer_storage(std::addressof(m_buffer_storages[level]), 0, info.info[level].size);
|
||||
fs::HashSalt mac;
|
||||
crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size);
|
||||
m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast<s64>(1) << info.info[level + 1].block_order, static_cast<s64>(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], mac, false, storage_type);
|
||||
m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast<s64>(1) << info.info[level + 1].block_order, static_cast<s64>(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], hgf, mac, false, storage_type);
|
||||
}
|
||||
|
||||
/* Initialize the buffer storage. */
|
||||
|
@ -217,7 +217,7 @@ namespace ams::fssystem::save {
|
|||
fs::SubStorage buffer_storage(std::addressof(m_buffer_storages[level]), 0, info.info[level].size);
|
||||
fs::HashSalt mac;
|
||||
crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size);
|
||||
m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast<s64>(1) << info.info[level + 1].block_order, static_cast<s64>(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], mac, true, storage_type);
|
||||
m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast<s64>(1) << info.info[level + 1].block_order, static_cast<s64>(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], hgf, mac, true, storage_type);
|
||||
}
|
||||
|
||||
/* Initialize the buffer storage. */
|
||||
|
|
|
@ -17,15 +17,19 @@
|
|||
|
||||
namespace ams::fssystem::save {
|
||||
|
||||
Result IntegrityVerificationStorage::Initialize(fs::SubStorage hs, fs::SubStorage ds, s64 verif_block_size, s64 upper_layer_verif_block_size, IBufferManager *bm, const fs::HashSalt &salt, bool is_real_data, fs::StorageType storage_type) {
|
||||
Result IntegrityVerificationStorage::Initialize(fs::SubStorage hs, fs::SubStorage ds, s64 verif_block_size, s64 upper_layer_verif_block_size, IBufferManager *bm, fssystem::IHash256GeneratorFactory *hgf, const fs::HashSalt &salt, bool is_real_data, fs::StorageType storage_type) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(verif_block_size >= HashSize);
|
||||
AMS_ASSERT(bm != nullptr);
|
||||
AMS_ASSERT(hgf != nullptr);
|
||||
|
||||
/* Set storages. */
|
||||
m_hash_storage = hs;
|
||||
m_data_storage = ds;
|
||||
|
||||
/* Set hash generator factory. */
|
||||
m_hash_generator_factory = hgf;
|
||||
|
||||
/* Set verification block sizes. */
|
||||
m_verification_block_size = verif_block_size;
|
||||
m_verification_block_order = ILog2(static_cast<u32>(verif_block_size));
|
||||
|
@ -111,14 +115,17 @@ namespace ams::fssystem::save {
|
|||
clear_guard.Cancel();
|
||||
}
|
||||
|
||||
/* Verify the signatures. */
|
||||
Result verify_hash_result = ResultSuccess();
|
||||
|
||||
/* Create hash generator. */
|
||||
auto generator = m_hash_generator_factory->Create();
|
||||
|
||||
/* Prepare to validate the signatures. */
|
||||
const auto signature_count = size >> m_verification_block_order;
|
||||
PooledBuffer signature_buffer(signature_count * sizeof(BlockHash), sizeof(BlockHash));
|
||||
const auto buffer_count = std::min(signature_count, signature_buffer.GetSize() / sizeof(BlockHash));
|
||||
|
||||
/* Verify the signatures. */
|
||||
Result verify_hash_result = ResultSuccess();
|
||||
|
||||
size_t verified_count = 0;
|
||||
while (verified_count < signature_count) {
|
||||
/* Read the current signatures. */
|
||||
|
@ -132,7 +139,7 @@ namespace ams::fssystem::save {
|
|||
for (size_t i = 0; i < cur_count && R_SUCCEEDED(cur_result); ++i) {
|
||||
const auto verified_size = (verified_count + i) << m_verification_block_order;
|
||||
u8 *cur_buf = static_cast<u8 *>(buffer) + verified_size;
|
||||
cur_result = this->VerifyHash(cur_buf, reinterpret_cast<BlockHash *>(signature_buffer.GetBuffer()) + i);
|
||||
cur_result = this->VerifyHash(cur_buf, reinterpret_cast<BlockHash *>(signature_buffer.GetBuffer()) + i, generator);
|
||||
|
||||
/* If the data is corrupted, clear the corrupted parts. */
|
||||
if (fs::ResultIntegrityVerificationStorageCorrupted::Includes(cur_result)) {
|
||||
|
@ -211,6 +218,8 @@ namespace ams::fssystem::save {
|
|||
PooledBuffer signature_buffer(signature_count * sizeof(BlockHash), sizeof(BlockHash));
|
||||
const auto buffer_count = std::min(signature_count, signature_buffer.GetSize() / sizeof(BlockHash));
|
||||
|
||||
auto generator = m_hash_generator_factory->Create();
|
||||
|
||||
while (updated_count < signature_count) {
|
||||
const auto cur_count = std::min(buffer_count, signature_count - updated_count);
|
||||
|
||||
|
@ -220,7 +229,7 @@ namespace ams::fssystem::save {
|
|||
|
||||
for (size_t i = 0; i < cur_count; ++i) {
|
||||
const auto updated_size = (updated_count + i) << m_verification_block_order;
|
||||
this->CalcBlockHash(reinterpret_cast<BlockHash *>(signature_buffer.GetBuffer()) + i, reinterpret_cast<const u8 *>(buffer) + updated_size);
|
||||
this->CalcBlockHash(reinterpret_cast<BlockHash *>(signature_buffer.GetBuffer()) + i, reinterpret_cast<const u8 *>(buffer) + updated_size, generator);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,19 +369,18 @@ namespace ams::fssystem::save {
|
|||
}
|
||||
}
|
||||
|
||||
void IntegrityVerificationStorage::CalcBlockHash(BlockHash *out, const void *buffer, size_t block_size) const {
|
||||
/* Create a sha256 generator. */
|
||||
crypto::Sha256Generator sha;
|
||||
sha.Initialize();
|
||||
void IntegrityVerificationStorage::CalcBlockHash(BlockHash *out, const void *buffer, size_t block_size, std::unique_ptr<fssystem::IHash256Generator> &generator) const {
|
||||
/* Initialize the generator. */
|
||||
generator->Initialize();
|
||||
|
||||
/* If calculating for save data, hash the salt. */
|
||||
if (m_storage_type == fs::StorageType_SaveData) {
|
||||
sha.Update(m_salt.value, sizeof(m_salt));
|
||||
generator->Update(m_salt.value, sizeof(m_salt));
|
||||
}
|
||||
|
||||
/* Update with the buffer and get the hash. */
|
||||
sha.Update(buffer, block_size);
|
||||
sha.GetHash(out, sizeof(*out));
|
||||
generator->Update(buffer, block_size);
|
||||
generator->GetHash(out, sizeof(*out));
|
||||
|
||||
/* Set the validation bit, if the hash is for save data. */
|
||||
if (m_storage_type == fs::StorageType_SaveData) {
|
||||
|
@ -428,7 +436,7 @@ namespace ams::fssystem::save {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result IntegrityVerificationStorage::VerifyHash(const void *buf, BlockHash *hash) {
|
||||
Result IntegrityVerificationStorage::VerifyHash(const void *buf, BlockHash *hash, std::unique_ptr<fssystem::IHash256Generator> &generator) {
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(buf != nullptr);
|
||||
AMS_ASSERT(hash != nullptr);
|
||||
|
@ -445,7 +453,7 @@ namespace ams::fssystem::save {
|
|||
|
||||
/* Get the calculated hash. */
|
||||
BlockHash calc_hash;
|
||||
this->CalcBlockHash(std::addressof(calc_hash), buf);
|
||||
this->CalcBlockHash(std::addressof(calc_hash), buf, generator);
|
||||
|
||||
/* Check that the signatures are equal. */
|
||||
if (!crypto::IsSameBytes(std::addressof(cmp_hash), std::addressof(calc_hash), sizeof(BlockHash))) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue