diff --git a/libraries/libstratosphere/include/stratosphere/fssystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem.hpp index d870584fa..c36b85f65 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem.hpp @@ -49,6 +49,6 @@ #include #include #include -#include +#include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_i_hash_256_generator.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_i_hash_256_generator.hpp index 934eadf7e..027a5fcd9 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_i_hash_256_generator.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_i_hash_256_generator.hpp @@ -18,7 +18,12 @@ namespace ams::fssystem { - /* ACCURATE_TO_VERSION: 13.4.0.0 */ + enum HashAlgorithmType : u8 { + HashAlgorithmType_Sha2 = 0, + HashAlgorithmType_Sha3 = 1, + }; + + /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IHash256Generator { public: static constexpr size_t HashSize = 256 / BITSIZEOF(u8); @@ -49,7 +54,7 @@ namespace ams::fssystem { virtual void DoGetHash(void *dst, size_t dst_size) = 0; }; - /* ACCURATE_TO_VERSION: 13.4.0.0 */ + /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IHash256GeneratorFactory { public: constexpr IHash256GeneratorFactory() = default; @@ -78,9 +83,9 @@ namespace ams::fssystem { constexpr IHash256GeneratorFactorySelector() = default; virtual constexpr ~IHash256GeneratorFactorySelector() { /* ... */ } - IHash256GeneratorFactory *GetFactory() { return this->DoGetFactory(); } + IHash256GeneratorFactory *GetFactory(HashAlgorithmType alg) { return this->DoGetFactory(alg); } protected: - virtual IHash256GeneratorFactory *DoGetFactory() = 0; + virtual IHash256GeneratorFactory *DoGetFactory(HashAlgorithmType alg) = 0; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp index d7bbb7abc..c2e28c5a6 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp @@ -111,7 +111,7 @@ namespace ams::fssystem { NcaHeader::EncryptionType m_header_encryption_type; bool m_is_header_sign1_signature_valid; GetDecompressorFunction m_get_decompressor; - IHash256GeneratorFactory *m_hash_generator_factory; + IHash256GeneratorFactorySelector *m_hash_generator_factory_selector; public: NcaReader(); ~NcaReader(); @@ -154,7 +154,7 @@ namespace ams::fssystem { Result ReadHeader(NcaFsHeader *dst, s32 index) const; GetDecompressorFunction GetDecompressor() const; - IHash256GeneratorFactory *GetHashGeneratorFactory() const; + IHash256GeneratorFactorySelector *GetHashGeneratorFactorySelector() const; bool GetHeaderSign1Valid() const; @@ -288,9 +288,9 @@ namespace ams::fssystem { Result CreateIndirectStorageMetaStorage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaPatchInfo &patch_info); Result CreateIndirectStorage(std::shared_ptr *out, std::shared_ptr *out_ind, std::shared_ptr base_storage, std::shared_ptr original_data_storage, std::shared_ptr meta_storage, const NcaPatchInfo &patch_info); - Result CreateSha256Storage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data &sha256_data); + Result CreateSha256Storage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data &sha256_data, IHash256GeneratorFactory *hgf); - Result CreateIntegrityVerificationStorage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info); + Result CreateIntegrityVerificationStorage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info, IHash256GeneratorFactory *hgf); Result CreateCompressedStorage(std::shared_ptr *out, std::shared_ptr *out_cmp, std::shared_ptr *out_meta, std::shared_ptr base_storage, const NcaCompressionInfo &compression_info); public: diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp deleted file mode 100644 index dcaf79d50..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 . - */ -#pragma once -#include -#include - -namespace ams::fssystem { - - /* ACCURATE_TO_VERSION: 13.4.0.0 */ - - class Sha256HashGenerator final : public ::ams::fssystem::IHash256Generator, public ::ams::fs::impl::Newable { - NON_COPYABLE(Sha256HashGenerator); - NON_MOVEABLE(Sha256HashGenerator); - private: - crypto::Sha256Generator m_generator; - public: - Sha256HashGenerator() = default; - protected: - virtual void DoInitialize() override { - m_generator.Initialize(); - } - - virtual void DoUpdate(const void *data, size_t size) override { - m_generator.Update(data, size); - } - - virtual void DoGetHash(void *dst, size_t dst_size) override { - m_generator.GetHash(dst, dst_size); - } - }; - - class Sha256HashGeneratorFactory final : public IHash256GeneratorFactory, public ::ams::fs::impl::Newable { - NON_COPYABLE(Sha256HashGeneratorFactory); - NON_MOVEABLE(Sha256HashGeneratorFactory); - public: - Sha256HashGeneratorFactory() = default; - protected: - virtual std::unique_ptr DoCreate() override { - return std::unique_ptr(new Sha256HashGenerator()); - } - - virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) override { - crypto::GenerateSha256(dst, dst_size, src, src_size); - } - }; - - class Sha256HashGeneratorFactorySelector final : public IHash256GeneratorFactorySelector, public ::ams::fs::impl::Newable { - NON_COPYABLE(Sha256HashGeneratorFactorySelector); - NON_MOVEABLE(Sha256HashGeneratorFactorySelector); - private: - Sha256HashGeneratorFactory m_factory; - public: - Sha256HashGeneratorFactorySelector() = default; - protected: - virtual IHash256GeneratorFactory *DoGetFactory() override { - return std::addressof(m_factory); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha_hash_generator.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha_hash_generator.hpp new file mode 100644 index 000000000..89c10100c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha_hash_generator.hpp @@ -0,0 +1,107 @@ +/* + * 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 . + */ +#pragma once +#include +#include + +namespace ams::fssystem { + + /* ACCURATE_TO_VERSION: 14.3.0.0 */ + + namespace impl { + + template + class ShaHashGenerator final : public ::ams::fssystem::IHash256Generator, public ::ams::fs::impl::Newable { + static_assert(Traits::Generator::HashSize == IHash256Generator::HashSize); + NON_COPYABLE(ShaHashGenerator); + NON_MOVEABLE(ShaHashGenerator); + private: + Traits::Generator m_generator; + public: + ShaHashGenerator() = default; + protected: + virtual void DoInitialize() override { + m_generator.Initialize(); + } + + virtual void DoUpdate(const void *data, size_t size) override { + m_generator.Update(data, size); + } + + virtual void DoGetHash(void *dst, size_t dst_size) override { + m_generator.GetHash(dst, dst_size); + } + }; + + template + class ShaHashGeneratorFactory final : public IHash256GeneratorFactory, public ::ams::fs::impl::Newable { + static_assert(Traits::Generator::HashSize == IHash256Generator::HashSize); + NON_COPYABLE(ShaHashGeneratorFactory); + NON_MOVEABLE(ShaHashGeneratorFactory); + public: + constexpr ShaHashGeneratorFactory() = default; + protected: + virtual std::unique_ptr DoCreate() override { + return std::unique_ptr(new ShaHashGenerator()); + } + + virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) override { + Traits::Generate(dst, dst_size, src, src_size); + } + }; + + struct Sha256Traits { + using Generator = crypto::Sha256Generator; + + static ALWAYS_INLINE void Generate(void *dst, size_t dst_size, const void *src, size_t src_size) { + return crypto::GenerateSha256(dst, dst_size, src, src_size); + } + }; + + struct Sha3256Traits { + using Generator = crypto::Sha3256Generator; + + static ALWAYS_INLINE void Generate(void *dst, size_t dst_size, const void *src, size_t src_size) { + return crypto::GenerateSha3256(dst, dst_size, src, src_size); + } + }; + } + + using Sha256HashGenerator = impl::ShaHashGenerator; + using Sha256HashGeneratorFactory = impl::ShaHashGeneratorFactory; + + using Sha3256HashGenerator = impl::ShaHashGenerator; + using Sha3256HashGeneratorFactory = impl::ShaHashGeneratorFactory; + + class ShaHashGeneratorFactorySelector final : public IHash256GeneratorFactorySelector, public ::ams::fs::impl::Newable { + NON_COPYABLE(ShaHashGeneratorFactorySelector); + NON_MOVEABLE(ShaHashGeneratorFactorySelector); + private: + Sha256HashGeneratorFactory m_sha256_factory; + Sha3256HashGeneratorFactory m_sha3_256_factory; + public: + constexpr ShaHashGeneratorFactorySelector() = default; + protected: + virtual IHash256GeneratorFactory *DoGetFactory(HashAlgorithmType alg) override { + switch (alg) { + case HashAlgorithmType_Sha2: return std::addressof(m_sha256_factory); + case HashAlgorithmType_Sha3: return std::addressof(m_sha3_256_factory); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + }; + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_hash_generator_factory_selector.cpp b/libraries/libstratosphere/source/fs/impl/fs_hash_generator_factory_selector.cpp index 3a2876212..38a15ae60 100644 --- a/libraries/libstratosphere/source/fs/impl/fs_hash_generator_factory_selector.cpp +++ b/libraries/libstratosphere/source/fs/impl/fs_hash_generator_factory_selector.cpp @@ -19,16 +19,16 @@ namespace ams::fs::impl { namespace { - constinit fssystem::Sha256HashGeneratorFactorySelector g_sha256_hash_generator_factory_selector; + constinit fssystem::ShaHashGeneratorFactorySelector g_sha_hash_generator_factory_selector; } fssystem::IHash256GeneratorFactorySelector *GetNcaHashGeneratorFactorySelector() { - return std::addressof(g_sha256_hash_generator_factory_selector); + return std::addressof(g_sha_hash_generator_factory_selector); } fssystem::IHash256GeneratorFactorySelector *GetSaveDataHashGeneratorFactorySelector() { - return std::addressof(g_sha256_hash_generator_factory_selector); + return std::addressof(g_sha_hash_generator_factory_selector); } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp b/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp index 1976133f3..f55d1d753 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp @@ -450,10 +450,10 @@ namespace ams::fssystem { /* Process hash/integrity layer. */ switch (header_reader->GetHashType()) { case NcaFsHeader::HashType::HierarchicalSha256Hash: - R_TRY(this->CreateSha256Storage(std::addressof(storage), std::move(storage), header_reader->GetHashData().hierarchical_sha256_data)); + R_TRY(this->CreateSha256Storage(std::addressof(storage), std::move(storage), header_reader->GetHashData().hierarchical_sha256_data, m_hash_generator_factory_selector->GetFactory(fssystem::HashAlgorithmType_Sha2))); break; case NcaFsHeader::HashType::HierarchicalIntegrityHash: - R_TRY(this->CreateIntegrityVerificationStorage(std::addressof(storage), std::move(storage), header_reader->GetHashData().integrity_meta_info)); + R_TRY(this->CreateIntegrityVerificationStorage(std::addressof(storage), std::move(storage), header_reader->GetHashData().integrity_meta_info, m_hash_generator_factory_selector->GetFactory(fssystem::HashAlgorithmType_Sha2))); break; default: return fs::ResultInvalidNcaFsHeaderHashType(); @@ -988,7 +988,7 @@ namespace ams::fssystem { return ResultSuccess(); } - Result NcaFileSystemDriver::CreateSha256Storage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data &hash_data) { + Result NcaFileSystemDriver::CreateSha256Storage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data &hash_data, IHash256GeneratorFactory *hgf) { /* Validate preconditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(base_storage != nullptr); @@ -1040,7 +1040,7 @@ namespace ams::fssystem { }; /* Initialize the verification storage. */ - R_TRY(verification_storage->Initialize(layer_storages, util::size(layer_storages), hash_data.hash_block_size, buffer_hold_storage->GetBuffer(), hash_buffer_size, m_hash_generator_factory_selector->GetFactory())); + R_TRY(verification_storage->Initialize(layer_storages, util::size(layer_storages), hash_data.hash_block_size, buffer_hold_storage->GetBuffer(), hash_buffer_size, hgf)); /* Make the cache storage. */ auto cache_storage = fssystem::AllocateShared(std::move(verification_storage), hash_data.hash_block_size, static_cast(buffer_hold_storage->GetBuffer()) + hash_buffer_size, cache_buffer_size, CacheBlockCount); @@ -1055,7 +1055,7 @@ namespace ams::fssystem { return ResultSuccess(); } - Result NcaFileSystemDriver::CreateIntegrityVerificationStorage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info) { + Result NcaFileSystemDriver::CreateIntegrityVerificationStorage(std::shared_ptr *out, std::shared_ptr base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info, IHash256GeneratorFactory *hgf) { /* Validate preconditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(base_storage != nullptr); @@ -1094,7 +1094,7 @@ namespace ams::fssystem { R_UNLESS(integrity_storage != nullptr, fs::ResultAllocationMemoryFailedAllocateShared()); /* Initialize the integrity storage. */ - R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, m_buffer_manager, m_hash_generator_factory_selector->GetFactory())); + R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, m_buffer_manager, hgf)); /* Set the output. */ *out = std::move(integrity_storage); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp b/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp index 3a2608514..41740dece 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp @@ -35,7 +35,7 @@ namespace ams::fssystem { } - 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() { + 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_selector() { 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)); @@ -118,6 +118,9 @@ namespace ams::fssystem { /* Validate the key index. */ R_UNLESS(m_header.key_index < NcaCryptoConfiguration::KeyAreaEncryptionKeyIndexCount, fs::ResultInvalidNcaKeyIndex()); + /* Set our hash generator factory selector. */ + m_hash_generator_factory_selector = hgf_selector; + /* Check if we have a rights id. */ constexpr const u8 ZeroRightsId[NcaHeader::RightsIdSize] = {}; if (crypto::IsSameBytes(ZeroRightsId, m_header.rights_id, NcaHeader::RightsIdSize)) { @@ -145,10 +148,6 @@ namespace ams::fssystem { /* 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 = std::move(base_storage); @@ -351,9 +350,9 @@ namespace ams::fssystem { return m_get_decompressor; } - IHash256GeneratorFactory *NcaReader::GetHashGeneratorFactory() const { - AMS_ASSERT(m_hash_generator_factory != nullptr); - return m_hash_generator_factory; + IHash256GeneratorFactorySelector *NcaReader::GetHashGeneratorFactorySelector() const { + AMS_ASSERT(m_hash_generator_factory_selector != nullptr); + return m_hash_generator_factory_selector; } NcaHeader::EncryptionType NcaReader::GetEncryptionType() const { @@ -384,11 +383,12 @@ namespace ams::fssystem { } void NcaReader::GetHeaderSign2TargetHash(void *dst, size_t size) const { - AMS_ASSERT(m_hash_generator_factory != nullptr); + AMS_ASSERT(m_hash_generator_factory_selector!= nullptr); AMS_ASSERT(dst != nullptr); AMS_ASSERT(size == IHash256Generator::HashSize); - return m_hash_generator_factory->GenerateHash(dst, size, static_cast(std::addressof(m_header.magic)), NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount); + auto * const factory = m_hash_generator_factory_selector->GetFactory(fssystem::HashAlgorithmType_Sha2); + return factory->GenerateHash(dst, size, static_cast(std::addressof(m_header.magic)), NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount); } Result NcaFsHeaderReader::Initialize(const NcaReader &reader, s32 index) {