From 446927b53ebbe9d836e74f5f554dc4d014d9f721 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 20 May 2018 21:57:38 +0800 Subject: [PATCH] [libnx|nstool] Added HierarchicalSha256Header and HierarchicalIntegrityHeader --- .../include/nx/HierarchicalIntegrityHeader.h | 12 +- .../include/nx/HierarchicalSha256Header.h | 4 +- lib/libnx/include/nx/hierarchicalintegrity.h | 23 ++- lib/libnx/include/nx/hierarchicalsha256.h | 7 +- lib/libnx/include/nx/nca.h | 12 +- .../source/HierarchicalIntegrityHeader.cpp | 62 ++++++- lib/libnx/source/HierarchicalSha256Header.cpp | 13 +- lib/libnx/source/NcaUtils.cpp | 5 +- programs/nstool/source/NcaProcess.cpp | 168 +++++++----------- programs/nstool/source/NcaProcess.h | 16 +- 10 files changed, 170 insertions(+), 152 deletions(-) diff --git a/lib/libnx/include/nx/HierarchicalIntegrityHeader.h b/lib/libnx/include/nx/HierarchicalIntegrityHeader.h index f40f117..ddcb5f9 100644 --- a/lib/libnx/include/nx/HierarchicalIntegrityHeader.h +++ b/lib/libnx/include/nx/HierarchicalIntegrityHeader.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include @@ -14,21 +14,21 @@ namespace nx { size_t offset; size_t size; - size_t hash_block_size; + size_t block_size; void operator=(const sLayer& other) { offset = other.offset; size = other.size; - hash_block_size = other.hash_block_size; + block_size = other.block_size; } - bool operator==(const sLayer& other) + bool operator==(const sLayer& other) const { - return (offset == other.offset && size == other.size && hash_block_size == other.hash_block_size); + return (offset == other.offset && size == other.size && block_size == other.block_size); } - bool operator!=(const sLayer& other) + bool operator!=(const sLayer& other) const { return !(*this == other); } diff --git a/lib/libnx/include/nx/HierarchicalSha256Header.h b/lib/libnx/include/nx/HierarchicalSha256Header.h index a165b5b..f5568e8 100644 --- a/lib/libnx/include/nx/HierarchicalSha256Header.h +++ b/lib/libnx/include/nx/HierarchicalSha256Header.h @@ -21,12 +21,12 @@ namespace nx size = other.size; } - bool operator==(const sLayer& other) + bool operator==(const sLayer& other) const { return (offset == other.offset && size == other.size); } - bool operator!=(const sLayer& other) + bool operator!=(const sLayer& other) const { return !(*this == other); } diff --git a/lib/libnx/include/nx/hierarchicalintegrity.h b/lib/libnx/include/nx/hierarchicalintegrity.h index 02a9297..e60350e 100644 --- a/lib/libnx/include/nx/hierarchicalintegrity.h +++ b/lib/libnx/include/nx/hierarchicalintegrity.h @@ -10,9 +10,9 @@ namespace nx namespace hierarchicalintegrity { const std::string kStructSig = "IVFC"; - static const uint32_t kTypeId = 0x20000; - static const size_t kMaxLayerNum = 7; - static const size_t kMaxMasterHashNum = 3; + static const uint32_t kRomfsTypeId = 0x20000; + static const size_t kDefaultLayerNum = 6; + static const size_t kHeaderAlignLen = 0x20; } #pragma pack(push,1) @@ -22,15 +22,14 @@ namespace nx 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]; + }; + + struct sHierarchicalIntegrityLayerInfo // sizeof(0x18) + { + le_uint64_t offset; + le_uint64_t size; + le_uint32_t block_size; + byte_t reserved[4]; }; #pragma pack(pop) } diff --git a/lib/libnx/include/nx/hierarchicalsha256.h b/lib/libnx/include/nx/hierarchicalsha256.h index a4da019..a620826 100644 --- a/lib/libnx/include/nx/hierarchicalsha256.h +++ b/lib/libnx/include/nx/hierarchicalsha256.h @@ -8,9 +8,8 @@ namespace nx { namespace hierarchicalsha256 { - static const size_t kDefaultLevelNum = 2; - - static const size_t kMaxLayoutNum = 2; + static const size_t kDefaultLayerNum = 2; + static const size_t kMaxLayerNum = 2; } #pragma pack(push,1) @@ -23,7 +22,7 @@ namespace nx { le_uint64_t offset; le_uint64_t size; - } layer[hierarchicalsha256::kMaxLayoutNum]; + } layer[hierarchicalsha256::kMaxLayerNum]; }; #pragma pack(pop) } diff --git a/lib/libnx/include/nx/nca.h b/lib/libnx/include/nx/nca.h index c05ed43..7158813 100644 --- a/lib/libnx/include/nx/nca.h +++ b/lib/libnx/include/nx/nca.h @@ -5,8 +5,6 @@ #include #include #include -#include -#include namespace nx { @@ -21,7 +19,7 @@ namespace nx static const size_t kAesKeyNum = 16; static const size_t kRightsIdLen = 0x10; static const size_t kKeyAreaEncryptionKeyNum = 3; - static const size_t kFsHeaderHashSuperblockLen = 0x130; + static const size_t kFsHeaderHashSuperblockLen = 0x138; static const uint16_t kDefaultFsHeaderVersion = 2; enum ProgramPartitionId @@ -120,12 +118,8 @@ namespace nx byte_t hash_type; byte_t encryption_type; byte_t reserved_0[3]; - union { - byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen]; - nx::sHierarchicalSha256Header hierarchicalsha256_header; - nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header; - }; - crypto::aes::sAesIvCtr base_ctr; + byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen]; + byte_t aes_ctr_upper[8]; byte_t reserved_1[0xB8]; }; diff --git a/lib/libnx/source/HierarchicalIntegrityHeader.cpp b/lib/libnx/source/HierarchicalIntegrityHeader.cpp index 0830653..5c37e16 100644 --- a/lib/libnx/source/HierarchicalIntegrityHeader.cpp +++ b/lib/libnx/source/HierarchicalIntegrityHeader.cpp @@ -1,3 +1,4 @@ +#include #include nx::HierarchicalIntegrityHeader::HierarchicalIntegrityHeader() @@ -47,7 +48,66 @@ void nx::HierarchicalIntegrityHeader::exportBinary() void nx::HierarchicalIntegrityHeader::importBinary(const byte_t * bytes, size_t len) { - throw fnd::Exception(kModuleName, "importBinary() not implemented"); + std::stringstream error_str; + + // validate size for at least header + if (len < sizeof(nx::sHierarchicalIntegrityHeader)) + { + throw fnd::Exception(kModuleName, "Header too small"); + } + + const nx::sHierarchicalIntegrityHeader* hdr = (const nx::sHierarchicalIntegrityHeader*)bytes; + + // Validate Header Sig "IVFC" + if (std::string(hdr->signature, 4) != hierarchicalintegrity::kStructSig) + { + throw fnd::Exception(kModuleName, "Invalid struct magic"); + } + + // Validate TypeId + if (hdr->type_id.get() != nx::hierarchicalintegrity::kRomfsTypeId) + { + error_str.clear(); + error_str << "Unsupported type id (" << std::hex << hdr->type_id.get() << ")"; + throw fnd::Exception(kModuleName, error_str.str()); + } + + // Validate Layer Num + if (hdr->layer_num.get() != hierarchicalintegrity::kDefaultLayerNum+1) + { + error_str.clear(); + error_str << "Invalid layer count. "; + error_str << "(actual=" << std::dec << hdr->layer_num.get() << ", expected=" << nx::hierarchicalintegrity::kDefaultLayerNum+1 << ")"; + throw fnd::Exception(kModuleName, error_str.str()); + } + + // Get Sizes/Offsets + size_t master_hash_offset = align((sizeof(nx::sHierarchicalIntegrityHeader) + sizeof(nx::sHierarchicalIntegrityLayerInfo) * hdr->layer_num.get()), nx::hierarchicalintegrity::kHeaderAlignLen); + size_t total_size = master_hash_offset + hdr->master_hash_size.get(); + + // Validate total size + if (len < total_size) + { + throw fnd::Exception(kModuleName, "Header too small"); + } + + // copy to internal storage + mBinaryBlob.alloc(total_size); + memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize()); + + // save layer info + const nx::sHierarchicalIntegrityLayerInfo* layer_info = (const nx::sHierarchicalIntegrityLayerInfo*)(mBinaryBlob.getBytes() + sizeof(nx::sHierarchicalIntegrityHeader)); + for (size_t i = 0; i < hierarchicalintegrity::kDefaultLayerNum; i++) + { + mLayerInfo.addElement({layer_info[i].offset.get(), layer_info[i].size.get(), layer_info[i].block_size.get()}); + } + + // save hash list + const crypto::sha::sSha256Hash* hash_list = (const crypto::sha::sSha256Hash*)(mBinaryBlob.getBytes() + master_hash_offset); + for (size_t i = 0; i < hdr->master_hash_size.get()/sizeof(crypto::sha::sSha256Hash); i++) + { + mMasterHashList.addElement(hash_list[i]); + } } void nx::HierarchicalIntegrityHeader::clear() diff --git a/lib/libnx/source/HierarchicalSha256Header.cpp b/lib/libnx/source/HierarchicalSha256Header.cpp index de9ca79..a7d288d 100644 --- a/lib/libnx/source/HierarchicalSha256Header.cpp +++ b/lib/libnx/source/HierarchicalSha256Header.cpp @@ -49,6 +49,8 @@ void nx::HierarchicalSha256Header::exportBinary() void nx::HierarchicalSha256Header::importBinary(const byte_t * bytes, size_t len) { + std::stringstream error_str; + if (len < sizeof(nx::sHierarchicalSha256Header)) { throw fnd::Exception(kModuleName, "Header too small"); @@ -56,13 +58,12 @@ void nx::HierarchicalSha256Header::importBinary(const byte_t * bytes, size_t len const nx::sHierarchicalSha256Header* hdr = (const nx::sHierarchicalSha256Header*)bytes; - if (hdr->layer_num.get() != nx::hierarchicalsha256::kDefaultLevelNum) + if (hdr->layer_num.get() != nx::hierarchicalsha256::kDefaultLayerNum) { - std::stringstream ss; - ss.clear(); - ss << "Invalid layer count. "; - ss << "(actual=" << hdr->layer_num.get() << ", expected=" << nx::hierarchicalsha256::kDefaultLevelNum << ")"; - throw fnd::Exception(kModuleName, ss.str()); + error_str.clear(); + error_str << "Invalid layer count. "; + error_str << "(actual=" << std::dec << hdr->layer_num.get() << ", expected=" << nx::hierarchicalsha256::kDefaultLayerNum << ")"; + throw fnd::Exception(kModuleName, error_str.str()); } mMasterHash = hdr->master_hash; diff --git a/lib/libnx/source/NcaUtils.cpp b/lib/libnx/source/NcaUtils.cpp index 0ffa1ad..3ee87a6 100644 --- a/lib/libnx/source/NcaUtils.cpp +++ b/lib/libnx/source/NcaUtils.cpp @@ -50,8 +50,9 @@ byte_t nx::NcaUtils::getMasterKeyRevisionFromKeyGeneration(byte_t key_generation void nx::NcaUtils::getNcaPartitionAesCtr(const nx::sNcaFsHeader* hdr, byte_t* ctr) { - for (size_t i = 0; i < 16; i++) + for (size_t i = 0; i < 8; i++) { - ctr[15-i] = hdr->base_ctr.iv[i]; + ctr[7-i] = hdr->aes_ctr_upper[i]; + ctr[15-i] = 0; } } \ No newline at end of file diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 3ad8048..c302172 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -120,7 +120,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys() // otherwise decrypt key area else { - // if the titlekey_kek is available + // if the key_area_key is available if (mKeyset->nca.key_area_key[keak_index][masterkey_rev] != zero_aesctr_key) { nx::AesKeygen::generateKey(mBodyKeys.aes_ctr.var.key, mHdr.getEncAesKeys()[nx::nca::KEY_AESCTR].key, mKeyset->nca.key_area_key[keak_index][masterkey_rev].key); @@ -153,6 +153,9 @@ void NcaProcess::generatePartitionConfiguration() const nx::NcaHeader::sPartition& partition = mHdr.getPartitions()[i]; nx::sNcaFsHeader& fs_header = mHdrBlock.fs_header[partition.index]; + // output structure + sPartitionInfo& info = mPartitions[partition.index]; + // validate header hash crypto::sha::sSha256Hash calc_hash; crypto::sha::Sha256((const byte_t*)&mHdrBlock.fs_header[partition.index], sizeof(nx::sNcaFsHeader), calc_hash.bytes); @@ -165,19 +168,19 @@ void NcaProcess::generatePartitionConfiguration() // setup AES-CTR - crypto::aes::sAesIvCtr ctr; - nx::NcaUtils::getNcaPartitionAesCtr(&fs_header, ctr.iv); + nx::NcaUtils::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.iv); // save partition config - mPartitions[partition.index].reader = nullptr; - mPartitions[partition.index].offset = partition.offset; - mPartitions[partition.index].size = partition.size; - mPartitions[partition.index].format_type = (nx::nca::FormatType)fs_header.format_type; - mPartitions[partition.index].hash_type = (nx::nca::HashType)fs_header.hash_type; - memcpy(mPartitions[partition.index].hash_superblock, fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); + info.reader = nullptr; + info.offset = partition.offset; + info.size = partition.size; + info.version = fs_header.version.get(); + info.format_type = (nx::nca::FormatType)fs_header.format_type; + info.hash_type = (nx::nca::HashType)fs_header.hash_type; + info.enc_type = (nx::nca::EncryptionType)fs_header.encryption_type; // filter out unrecognised format types - switch (mPartitions[partition.index].format_type) + switch (info.format_type) { case (nx::nca::FORMAT_PFS0): case (nx::nca::FORMAT_ROMFS): @@ -186,71 +189,45 @@ void NcaProcess::generatePartitionConfiguration() continue; } - // filter out unrecognised hash types - switch (mPartitions[partition.index].hash_type) + // filter out unrecognised hash types, and get data offsets + switch (info.hash_type) { case (nx::nca::HASH_NONE): + info.data_offset = info.offset; + info.data_size = info.size; + break; case (nx::nca::HASH_HIERARCHICAL_SHA256): + info.hierarchicalsha256_header.importBinary(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); + info.data_offset = info.hierarchicalsha256_header.getLayerInfo().atBack().offset; + info.data_size = info.hierarchicalsha256_header.getLayerInfo().atBack().size; + break; case (nx::nca::HASH_HIERARCHICAL_INTERGRITY): + info.hierarchicalintergrity_header.importBinary(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); + info.data_offset = info.hierarchicalintergrity_header.getLayerInfo().atBack().offset; + info.data_size = info.hierarchicalintergrity_header.getLayerInfo().atBack().size; break; default: continue; } - // create reader + // create reader based on encryption type0 switch(fs_header.encryption_type) { case (nx::nca::CRYPT_AESXTS): case (nx::nca::CRYPT_AESCTREX): - mPartitions[partition.index].reader = nullptr; + info.reader = nullptr; break; case (nx::nca::CRYPT_AESCTR): - mPartitions[partition.index].reader = mBodyKeys.aes_ctr.isSet? new AesCtrWrappedIFile(mReader, mBodyKeys.aes_ctr.var, ctr) : nullptr; + info.reader = mBodyKeys.aes_ctr.isSet? new AesCtrWrappedIFile(mReader, mBodyKeys.aes_ctr.var, info.aes_ctr) : nullptr; break; case (nx::nca::CRYPT_NONE): - mPartitions[partition.index].reader = new CopiedIFile(mReader); + info.reader = new CopiedIFile(mReader); break; default: error.clear(); error << "NCA FS Header [" << partition.index << "] EncryptionType(" << fs_header.encryption_type << "): UNKNOWN \n"; throw fnd::Exception(kModuleName, error.str()); } - - // 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.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) - { - 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) - { - 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) - { - mPartitions[partition.index].data_offset = 0; - } } } @@ -368,81 +345,64 @@ void NcaProcess::displayHeader() printf(" Partitions:\n"); for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++) { - const nx::NcaHeader::sPartition& partition = mHdr.getPartitions()[i]; - nx::sNcaFsHeader& fs_header = mHdrBlock.fs_header[partition.index]; + sPartitionInfo& info = mPartitions[i]; printf(" %lu:\n", i); - printf(" Index: %d\n", partition.index); - printf(" Offset: 0x%" PRIx64 "\n", partition.offset); - printf(" Size: 0x%" PRIx64 "\n", partition.size); + printf(" Offset: 0x%" PRIx64 "\n", info.offset); + printf(" Size: 0x%" PRIx64 "\n", info.size); - - crypto::sha::sSha256Hash ncaFsHeaderHash; - crypto::sha::Sha256((byte_t*)&fs_header, sizeof(nx::sNcaFsHeader), ncaFsHeaderHash.bytes); - if (partition.hash.compare(ncaFsHeaderHash) == false) - { - throw fnd::Exception(kModuleName, "NcaFsHeader has bad sha256 hash"); - } - - //fnd::SimpleTextOutput::hxdStyleDump((byte_t*)&fs_header, sizeof(nx::sNcaFsHeader)); - - printf(" FsHeader:\n"); - printf(" Version: 0x%d\n", fs_header.version.get()); - printf(" Format Type: %s\n", kFormatTypeStr[fs_header.format_type].c_str()); - printf(" Hash Type: %s\n", kHashTypeStr[fs_header.hash_type].c_str()); - printf(" Enc. Type: %s\n", kEncryptionTypeStr[fs_header.encryption_type].c_str()); - if (fs_header.encryption_type == nx::nca::CRYPT_AESCTR) + printf(" Version: 0x%d\n", info.version); + printf(" Format Type: %s\n", kFormatTypeStr[info.format_type].c_str()); + printf(" Hash Type: %s\n", kHashTypeStr[info.hash_type].c_str()); + printf(" Enc. Type: %s\n", kEncryptionTypeStr[info.enc_type].c_str()); + if (info.enc_type == nx::nca::CRYPT_AESCTR) { - printf(" CTR: "); + printf(" AES-CTR: "); crypto::aes::sAesIvCtr ctr; - nx::NcaUtils::getNcaPartitionAesCtr(&fs_header, ctr.iv); - crypto::aes::AesIncrementCounter(ctr.iv, partition.offset>>4, ctr.iv); + crypto::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(crypto::aes::sAesIvCtr)); } - if (fs_header.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) + if (info.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) { - nx::sHierarchicalIntegrityHeader& hash_hdr = fs_header.hierarchicalintergrity_header; + nx::HierarchicalIntegrityHeader& hash_hdr = info.hierarchicalintergrity_header; printf(" HierarchicalIntegrity Header:\n"); - 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(" 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.getLayerInfo().getSize()); + for (size_t j = 0; j < hash_hdr.getLayerInfo().getSize(); j++) { - 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(" Layer %d:\n", j); + printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[j].offset); + printf(" Size: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[j].size); + printf(" BlockSize: 0x%" PRIx32 "\n", hash_hdr.getLayerInfo()[j].block_size); } - for (size_t j = 0; j < hash_hdr.master_hash_size.get() / sizeof(crypto::sha::sSha256Hash); j++) + for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++) { printf(" Master Hash %d: ", j); - fnd::SimpleTextOutput::hexDump(hash_hdr.master_hash[j].bytes, sizeof(crypto::sha::sSha256Hash)); + fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(crypto::sha::sSha256Hash)); } - - - } - else if (fs_header.hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) + else if (info.hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) { - nx::sHierarchicalSha256Header& hash_hdr = fs_header.hierarchicalsha256_header; + nx::HierarchicalSha256Header& hash_hdr = info.hierarchicalsha256_header; printf(" HierarchicalSha256 Header:\n"); printf(" Master Hash: "); - fnd::SimpleTextOutput::hexDump(hash_hdr.master_hash.bytes, sizeof(crypto::sha::sSha256Hash)); - printf(" HashBlockSize: 0x%x\n", hash_hdr.hash_block_size.get()); - printf(" LayerNum: %d\n", hash_hdr.layer_num.get()); - for (size_t i = 0; i < hash_hdr.layer_num.get(); i++) + fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHash().bytes, sizeof(crypto::sha::sSha256Hash)); + printf(" HashBlockSize: 0x%x\n", hash_hdr.getHashBlockSize()); + //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize()); + for (size_t i = 0; i < hash_hdr.getLayerInfo().getSize(); 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()); + printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[i].offset); + printf(" Size: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[i].size); } } - else - { - printf(" Hash Superblock:\n"); - fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); - } + //else + //{ + // printf(" Hash Superblock:\n"); + // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); + //} } } diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index eb05b47..d6438dc 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -3,6 +3,9 @@ #include #include #include +#include +#include + #include "nstool.h" @@ -64,14 +67,15 @@ private: size_t size; size_t data_offset; size_t data_size; + + // meta data + uint16_t version; nx::nca::FormatType format_type; nx::nca::HashType hash_type; - - union { - byte_t hash_superblock[nx::nca::kFsHeaderHashSuperblockLen]; - nx::sHierarchicalSha256Header hierarchicalsha256_header; - nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header; - }; + nx::nca::EncryptionType enc_type; + nx::HierarchicalSha256Header hierarchicalsha256_header; + nx::HierarchicalIntegrityHeader hierarchicalintergrity_header; + crypto::aes::sAesIvCtr aes_ctr; } mPartitions[nx::nca::kPartitionNum]; void generateNcaBodyEncryptionKeys();