diff --git a/lib/libnx/include/nx/HierarchicalIntergrityHeader.h b/lib/libnx/include/nx/HierarchicalIntergrityHeader.h new file mode 100644 index 0000000..9f2e4db --- /dev/null +++ b/lib/libnx/include/nx/HierarchicalIntergrityHeader.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include + +namespace nx +{ + class HierarchicalIntergrityHeader : + public fnd::ISerialiseableBinary + { + public: + + HierarchicalIntergrityHeader(); + HierarchicalIntergrityHeader(const HierarchicalIntergrityHeader& other); + HierarchicalIntergrityHeader(const byte_t* bytes, size_t len); + + bool operator==(const HierarchicalIntergrityHeader& other) const; + bool operator!=(const HierarchicalIntergrityHeader& other) const; + void operator=(const HierarchicalIntergrityHeader& other); + + // to be used after export + const byte_t* getBytes() const; + size_t getSize() const; + + // export/import binary + void exportBinary(); + void importBinary(const byte_t* bytes, size_t len); + + // variables + void clear(); + + + private: + const std::string kModuleName = "HIERARCHICAL_INTERGRITY_HEADER"; + + // binary + fnd::MemoryBlob mBinaryBlob; + + // data + + + uint64_t blockNumToSize(uint32_t block_num) const; + uint32_t sizeToBlockNum(uint64_t real_size) const; + bool isEqual(const HierarchicalIntergrityHeader& other) const; + void copyFrom(const HierarchicalIntergrityHeader& other); + }; + +} \ No newline at end of file diff --git a/lib/libnx/include/nx/HierarchicalSha256Header.h b/lib/libnx/include/nx/HierarchicalSha256Header.h new file mode 100644 index 0000000..3101096 --- /dev/null +++ b/lib/libnx/include/nx/HierarchicalSha256Header.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include + +namespace nx +{ + class HierarchicalSha256Header : + public fnd::ISerialiseableBinary + { + public: + + HierarchicalSha256Header(); + HierarchicalSha256Header(const HierarchicalSha256Header& other); + HierarchicalSha256Header(const byte_t* bytes, size_t len); + + bool operator==(const HierarchicalSha256Header& other) const; + bool operator!=(const HierarchicalSha256Header& other) const; + void operator=(const HierarchicalSha256Header& other); + + // to be used after export + const byte_t* getBytes() const; + size_t getSize() const; + + // export/import binary + void exportBinary(); + void importBinary(const byte_t* bytes, size_t len); + + // variables + void clear(); + + + private: + const std::string kModuleName = "HIERARCHICAL_SHA256_HEADER"; + + // binary + fnd::MemoryBlob mBinaryBlob; + + // data + + + uint64_t blockNumToSize(uint32_t block_num) const; + uint32_t sizeToBlockNum(uint64_t real_size) const; + bool isEqual(const HierarchicalSha256Header& other) const; + void copyFrom(const HierarchicalSha256Header& other); + }; + +} \ No newline at end of file diff --git a/lib/libnx/include/nx/hierarchicalintegrity.h b/lib/libnx/include/nx/hierarchicalintegrity.h new file mode 100644 index 0000000..50677dd --- /dev/null +++ b/lib/libnx/include/nx/hierarchicalintegrity.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include +#include + +namespace nx +{ + // Also known as HierarchicalIntegrity + namespace hierarchicalintegrity + { + const std::string kStructSig = "IVFC"; + static const size_t kMaxLayerNum = 7; + static const uint32_t kTypeId = 0x20000; + static const size_t kMaxMasterHashNum = 3; + } + +#pragma pack(push,1) + struct sHierarchicalIntegrityHeader + { + char signature[4]; + le_uint32_t type_id; + le_uint32_t master_hash_size; + le_uint32_t layer_num; + struct sLayer + { + le_uint64_t offset; + le_uint64_t size; + le_uint32_t block_size; + byte_t reserved[4]; + } layer[hierarchicalintegrity::kMaxLayerNum]; + byte_t reserved_00[0x8]; + crypto::sha::sSha256Hash master_hash[hierarchicalintegrity::kMaxMasterHashNum]; + }; +#pragma pack(pop) +} diff --git a/lib/libnx/include/nx/hierarchicalsha256.h b/lib/libnx/include/nx/hierarchicalsha256.h index 7039dcc..8db3b26 100644 --- a/lib/libnx/include/nx/hierarchicalsha256.h +++ b/lib/libnx/include/nx/hierarchicalsha256.h @@ -9,6 +9,8 @@ namespace nx namespace hierarchicalsha256 { static const size_t kDefaultLevelNum = 2; + + static const size_t kMaxLayoutNum = 2; } #pragma pack(push,1) @@ -16,12 +18,12 @@ namespace nx { crypto::sha::sSha256Hash master_hash; le_uint32_t hash_block_size; - le_uint32_t hash_level_num; + le_uint32_t layer_num; struct sLayout { le_uint64_t offset; le_uint64_t size; - } hash_data, hash_target; + } layer[hierarchicalsha256::kMaxLayoutNum]; }; #pragma pack(pop) } diff --git a/lib/libnx/include/nx/ivfc.h b/lib/libnx/include/nx/ivfc.h deleted file mode 100644 index 0d74426..0000000 --- a/lib/libnx/include/nx/ivfc.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace nx -{ - // Also known as HierarchicalIntegrity - namespace ivfc - { - const std::string kIvfcSig = "IVFC"; - static const size_t kMaxIvfcLevel = 7; - static const uint32_t kIvfcId = 0x20000; - } - -#pragma pack(push,1) - struct sIvfcHeader - { - char signature[4]; - le_uint32_t id; - le_uint32_t master_hash_size; - le_uint32_t level_num; - struct sIvfcLevelHeader - { - le_uint64_t logical_offset; - le_uint64_t hash_data_size; - le_uint32_t block_size; - byte_t reserved[4]; - } level_header[ivfc::kMaxIvfcLevel]; - byte_t reserved_00[0x8]; - crypto::sha::sSha256Hash master_hash; - }; -#pragma pack(pop) -} diff --git a/lib/libnx/include/nx/nca.h b/lib/libnx/include/nx/nca.h index e301ae7..c05ed43 100644 --- a/lib/libnx/include/nx/nca.h +++ b/lib/libnx/include/nx/nca.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include namespace nx @@ -123,7 +123,7 @@ namespace nx union { byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen]; nx::sHierarchicalSha256Header hierarchicalsha256_header; - nx::sIvfcHeader ivfc_header; + nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header; }; crypto::aes::sAesIvCtr base_ctr; byte_t reserved_1[0xB8]; diff --git a/lib/libnx/nx.vcxproj b/lib/libnx/nx.vcxproj index 4d0658a..5fde829 100644 --- a/lib/libnx/nx.vcxproj +++ b/lib/libnx/nx.vcxproj @@ -30,11 +30,13 @@ + + - + @@ -75,6 +77,8 @@ + + diff --git a/lib/libnx/nx.vcxproj.filters b/lib/libnx/nx.vcxproj.filters index f465981..b1e1f7d 100644 --- a/lib/libnx/nx.vcxproj.filters +++ b/lib/libnx/nx.vcxproj.filters @@ -123,9 +123,6 @@ Header Files - - Header Files - Header Files @@ -150,6 +147,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -254,6 +260,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/lib/libnx/source/HierarchicalIntegrityHeader.cpp b/lib/libnx/source/HierarchicalIntegrityHeader.cpp new file mode 100644 index 0000000..e69de29 diff --git a/lib/libnx/source/HierarchicalSha256Header.cpp b/lib/libnx/source/HierarchicalSha256Header.cpp new file mode 100644 index 0000000..e69de29 diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index ae5f678..3ad8048 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -219,20 +219,33 @@ void NcaProcess::generatePartitionConfiguration() // determine the data offset & size if (mPartitions[partition.index].hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) { - mPartitions[partition.index].data_offset = mPartitions[partition.index].hierarchicalsha256_header.hash_target.offset.get(); - mPartitions[partition.index].data_size = mPartitions[partition.index].hierarchicalsha256_header.hash_target.size.get(); + mPartitions[partition.index].data_offset = mPartitions[partition.index].hierarchicalsha256_header.layer[1].offset.get(); + mPartitions[partition.index].data_size = mPartitions[partition.index].hierarchicalsha256_header.layer[1].size.get(); } else if (mPartitions[partition.index].hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) { - for (size_t j = 0; j < nx::ivfc::kMaxIvfcLevel; j++) + mPartitions[partition.index].data_offset = mPartitions[partition.index].hierarchicalintergrity_header.layer[5].offset.get(); + mPartitions[partition.index].data_size = mPartitions[partition.index].hierarchicalintergrity_header.layer[5].size.get(); + /* + if (mPartitions[partition.index].hierarchicalintergrity_header.layer_num.get() > nx::hierarchicalintegrity::kMaxLayerNum) { - if (mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].logical_offset.get() != 0) - { - mPartitions[partition.index].data_offset = mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].logical_offset.get(); - mPartitions[partition.index].data_size = mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].hash_data_size.get(); - break; - } + error.clear(); + error << "NCA FS Header [" << partition.index << "] HierarchicalIntergrity header has an unsupported layer num (" << mPartitions[partition.index].hierarchicalintergrity_header.layer_num.get() << ")\n"; + throw fnd::Exception(kModuleName, error.str()); } + const nx::sHierarchicalIntegrityHeader& hdr = mPartitions[partition.index].hierarchicalintergrity_header; + + for (size_t j = 0; j < nx::hierarchicalintegrity::kMaxLayerNum; j++) + { + size_t index = nx::hierarchicalintegrity::kMaxLayerNum - 1 - j; + if (hdr.layer[index].offset.get() != 0) + { + mPartitions[partition.index].data_offset = hdr.layer[index].offset.get(); + mPartitions[partition.index].data_size = hdr.layer[index].size.get(); + break; + } + } + */ } else if (mPartitions[partition.index].hash_type == nx::nca::HASH_NONE) { @@ -389,19 +402,24 @@ void NcaProcess::displayHeader() } if (fs_header.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) { + nx::sHierarchicalIntegrityHeader& hash_hdr = fs_header.hierarchicalintergrity_header; printf(" HierarchicalIntegrity Header:\n"); - printf(" Id: 0x%x\n", fs_header.ivfc_header.id.get()); - printf(" MasterHashSize: 0x%x\n", fs_header.ivfc_header.master_hash_size.get()); - printf(" LevelNum: %d\n", fs_header.ivfc_header.level_num.get()); - for (size_t i = 0; i < fs_header.ivfc_header.level_num.get(); i++) + printf(" TypeId: 0x%x\n", hash_hdr.type_id.get()); + printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get()); + printf(" LayerNum: %d\n", hash_hdr.layer_num.get()); + for (size_t i = 0; i < hash_hdr.layer_num.get(); i++) { - printf(" Level %d:\n", i); - printf(" LogicalOffset: 0x%" PRIx64 "\n", fs_header.ivfc_header.level_header[i].logical_offset.get()); - printf(" HashDataSize: 0x%" PRIx64 "\n", fs_header.ivfc_header.level_header[i].hash_data_size.get()); - printf(" BlockSize: 0x%" PRIx32 "\n", fs_header.ivfc_header.level_header[i].block_size.get()); + printf(" Layer %d:\n", i); + printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.layer[i].offset.get()); + printf(" Size: 0x%" PRIx64 "\n", hash_hdr.layer[i].size.get()); + printf(" BlockSize: 0x%" PRIx32 "\n", hash_hdr.layer[i].block_size.get()); } - printf(" Master Hash: "); - fnd::SimpleTextOutput::hexDump(fs_header.ivfc_header.master_hash.bytes, 0x20); + for (size_t j = 0; j < hash_hdr.master_hash_size.get() / sizeof(crypto::sha::sSha256Hash); j++) + { + printf(" Master Hash %d: ", j); + fnd::SimpleTextOutput::hexDump(hash_hdr.master_hash[j].bytes, sizeof(crypto::sha::sSha256Hash)); + } + } @@ -410,14 +428,15 @@ void NcaProcess::displayHeader() nx::sHierarchicalSha256Header& hash_hdr = fs_header.hierarchicalsha256_header; printf(" HierarchicalSha256 Header:\n"); printf(" Master Hash: "); - fnd::SimpleTextOutput::hexDump(hash_hdr.master_hash.bytes, 0x20); + fnd::SimpleTextOutput::hexDump(hash_hdr.master_hash.bytes, sizeof(crypto::sha::sSha256Hash)); printf(" HashBlockSize: 0x%x\n", hash_hdr.hash_block_size.get()); - printf(" HashLevelNum: 0x%x\n", hash_hdr.hash_level_num.get()); - printf(" HashDataOffset: 0x%" PRIx64 "\n", hash_hdr.hash_data.offset.get()); - printf(" HashDataSize: 0x%" PRIx64 "\n", hash_hdr.hash_data.size.get()); - printf(" HashTargetOffset: 0x%" PRIx64 "\n", hash_hdr.hash_target.offset.get()); - printf(" HashTargetSize: 0x%" PRIx64 "\n", hash_hdr.hash_target.size.get()); - + printf(" LayerNum: %d\n", hash_hdr.layer_num.get()); + for (size_t i = 0; i < hash_hdr.layer_num.get(); i++) + { + printf(" Layer %d:\n", i); + printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.layer[i].offset.get()); + printf(" Size: 0x%" PRIx64 "\n", hash_hdr.layer[i].size.get()); + } } else { diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index 1505d77..eb05b47 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -70,7 +70,7 @@ private: union { byte_t hash_superblock[nx::nca::kFsHeaderHashSuperblockLen]; nx::sHierarchicalSha256Header hierarchicalsha256_header; - nx::sIvfcHeader ivfc_header; + nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header; }; } mPartitions[nx::nca::kPartitionNum];