[libnx|nstool] Added HierarchicalSha256Header and HierarchicalIntegrityHeader

This commit is contained in:
jakcron 2018-05-20 21:57:38 +08:00
parent d93116863e
commit 446927b53e
10 changed files with 170 additions and 152 deletions

View file

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <nx/hierarchicalsha256.h> #include <nx/hierarchicalintegrity.h>
#include <fnd/MemoryBlob.h> #include <fnd/MemoryBlob.h>
#include <fnd/List.h> #include <fnd/List.h>
#include <fnd/ISerialiseableBinary.h> #include <fnd/ISerialiseableBinary.h>
@ -14,21 +14,21 @@ namespace nx
{ {
size_t offset; size_t offset;
size_t size; size_t size;
size_t hash_block_size; size_t block_size;
void operator=(const sLayer& other) void operator=(const sLayer& other)
{ {
offset = other.offset; offset = other.offset;
size = other.size; 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); return !(*this == other);
} }

View file

@ -21,12 +21,12 @@ namespace nx
size = other.size; size = other.size;
} }
bool operator==(const sLayer& other) bool operator==(const sLayer& other) const
{ {
return (offset == other.offset && size == other.size); return (offset == other.offset && size == other.size);
} }
bool operator!=(const sLayer& other) bool operator!=(const sLayer& other) const
{ {
return !(*this == other); return !(*this == other);
} }

View file

@ -10,9 +10,9 @@ namespace nx
namespace hierarchicalintegrity namespace hierarchicalintegrity
{ {
const std::string kStructSig = "IVFC"; const std::string kStructSig = "IVFC";
static const uint32_t kTypeId = 0x20000; static const uint32_t kRomfsTypeId = 0x20000;
static const size_t kMaxLayerNum = 7; static const size_t kDefaultLayerNum = 6;
static const size_t kMaxMasterHashNum = 3; static const size_t kHeaderAlignLen = 0x20;
} }
#pragma pack(push,1) #pragma pack(push,1)
@ -22,15 +22,14 @@ namespace nx
le_uint32_t type_id; le_uint32_t type_id;
le_uint32_t master_hash_size; le_uint32_t master_hash_size;
le_uint32_t layer_num; le_uint32_t layer_num;
struct sLayer };
{
le_uint64_t offset; struct sHierarchicalIntegrityLayerInfo // sizeof(0x18)
le_uint64_t size; {
le_uint32_t block_size; le_uint64_t offset;
byte_t reserved[4]; le_uint64_t size;
} layer[hierarchicalintegrity::kMaxLayerNum]; le_uint32_t block_size;
byte_t reserved_00[0x8]; byte_t reserved[4];
crypto::sha::sSha256Hash master_hash[hierarchicalintegrity::kMaxMasterHashNum];
}; };
#pragma pack(pop) #pragma pack(pop)
} }

View file

@ -8,9 +8,8 @@ namespace nx
{ {
namespace hierarchicalsha256 namespace hierarchicalsha256
{ {
static const size_t kDefaultLevelNum = 2; static const size_t kDefaultLayerNum = 2;
static const size_t kMaxLayerNum = 2;
static const size_t kMaxLayoutNum = 2;
} }
#pragma pack(push,1) #pragma pack(push,1)
@ -23,7 +22,7 @@ namespace nx
{ {
le_uint64_t offset; le_uint64_t offset;
le_uint64_t size; le_uint64_t size;
} layer[hierarchicalsha256::kMaxLayoutNum]; } layer[hierarchicalsha256::kMaxLayerNum];
}; };
#pragma pack(pop) #pragma pack(pop)
} }

View file

@ -5,8 +5,6 @@
#include <crypto/sha.h> #include <crypto/sha.h>
#include <crypto/rsa.h> #include <crypto/rsa.h>
#include <fnd/ISerialiseableBinary.h> #include <fnd/ISerialiseableBinary.h>
#include <nx/hierarchicalintegrity.h>
#include <nx/hierarchicalsha256.h>
namespace nx namespace nx
{ {
@ -21,7 +19,7 @@ namespace nx
static const size_t kAesKeyNum = 16; static const size_t kAesKeyNum = 16;
static const size_t kRightsIdLen = 0x10; static const size_t kRightsIdLen = 0x10;
static const size_t kKeyAreaEncryptionKeyNum = 3; static const size_t kKeyAreaEncryptionKeyNum = 3;
static const size_t kFsHeaderHashSuperblockLen = 0x130; static const size_t kFsHeaderHashSuperblockLen = 0x138;
static const uint16_t kDefaultFsHeaderVersion = 2; static const uint16_t kDefaultFsHeaderVersion = 2;
enum ProgramPartitionId enum ProgramPartitionId
@ -120,12 +118,8 @@ namespace nx
byte_t hash_type; byte_t hash_type;
byte_t encryption_type; byte_t encryption_type;
byte_t reserved_0[3]; byte_t reserved_0[3];
union { byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen];
byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen]; byte_t aes_ctr_upper[8];
nx::sHierarchicalSha256Header hierarchicalsha256_header;
nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header;
};
crypto::aes::sAesIvCtr base_ctr;
byte_t reserved_1[0xB8]; byte_t reserved_1[0xB8];
}; };

View file

@ -1,3 +1,4 @@
#include <sstream>
#include <nx/HierarchicalIntegrityHeader.h> #include <nx/HierarchicalIntegrityHeader.h>
nx::HierarchicalIntegrityHeader::HierarchicalIntegrityHeader() nx::HierarchicalIntegrityHeader::HierarchicalIntegrityHeader()
@ -47,7 +48,66 @@ void nx::HierarchicalIntegrityHeader::exportBinary()
void nx::HierarchicalIntegrityHeader::importBinary(const byte_t * bytes, size_t len) 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() void nx::HierarchicalIntegrityHeader::clear()

View file

@ -49,6 +49,8 @@ void nx::HierarchicalSha256Header::exportBinary()
void nx::HierarchicalSha256Header::importBinary(const byte_t * bytes, size_t len) void nx::HierarchicalSha256Header::importBinary(const byte_t * bytes, size_t len)
{ {
std::stringstream error_str;
if (len < sizeof(nx::sHierarchicalSha256Header)) if (len < sizeof(nx::sHierarchicalSha256Header))
{ {
throw fnd::Exception(kModuleName, "Header too small"); 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; 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; error_str.clear();
ss.clear(); error_str << "Invalid layer count. ";
ss << "Invalid layer count. "; error_str << "(actual=" << std::dec << hdr->layer_num.get() << ", expected=" << nx::hierarchicalsha256::kDefaultLayerNum << ")";
ss << "(actual=" << hdr->layer_num.get() << ", expected=" << nx::hierarchicalsha256::kDefaultLevelNum << ")"; throw fnd::Exception(kModuleName, error_str.str());
throw fnd::Exception(kModuleName, ss.str());
} }
mMasterHash = hdr->master_hash; mMasterHash = hdr->master_hash;

View file

@ -50,8 +50,9 @@ byte_t nx::NcaUtils::getMasterKeyRevisionFromKeyGeneration(byte_t key_generation
void nx::NcaUtils::getNcaPartitionAesCtr(const nx::sNcaFsHeader* hdr, byte_t* ctr) 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;
} }
} }

View file

@ -120,7 +120,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
// otherwise decrypt key area // otherwise decrypt key area
else 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) 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); 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]; const nx::NcaHeader::sPartition& partition = mHdr.getPartitions()[i];
nx::sNcaFsHeader& fs_header = mHdrBlock.fs_header[partition.index]; nx::sNcaFsHeader& fs_header = mHdrBlock.fs_header[partition.index];
// output structure
sPartitionInfo& info = mPartitions[partition.index];
// validate header hash // validate header hash
crypto::sha::sSha256Hash calc_hash; crypto::sha::sSha256Hash calc_hash;
crypto::sha::Sha256((const byte_t*)&mHdrBlock.fs_header[partition.index], sizeof(nx::sNcaFsHeader), calc_hash.bytes); 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 // setup AES-CTR
crypto::aes::sAesIvCtr ctr; nx::NcaUtils::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.iv);
nx::NcaUtils::getNcaPartitionAesCtr(&fs_header, ctr.iv);
// save partition config // save partition config
mPartitions[partition.index].reader = nullptr; info.reader = nullptr;
mPartitions[partition.index].offset = partition.offset; info.offset = partition.offset;
mPartitions[partition.index].size = partition.size; info.size = partition.size;
mPartitions[partition.index].format_type = (nx::nca::FormatType)fs_header.format_type; info.version = fs_header.version.get();
mPartitions[partition.index].hash_type = (nx::nca::HashType)fs_header.hash_type; info.format_type = (nx::nca::FormatType)fs_header.format_type;
memcpy(mPartitions[partition.index].hash_superblock, fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); 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 // filter out unrecognised format types
switch (mPartitions[partition.index].format_type) switch (info.format_type)
{ {
case (nx::nca::FORMAT_PFS0): case (nx::nca::FORMAT_PFS0):
case (nx::nca::FORMAT_ROMFS): case (nx::nca::FORMAT_ROMFS):
@ -186,71 +189,45 @@ void NcaProcess::generatePartitionConfiguration()
continue; continue;
} }
// filter out unrecognised hash types // filter out unrecognised hash types, and get data offsets
switch (mPartitions[partition.index].hash_type) switch (info.hash_type)
{ {
case (nx::nca::HASH_NONE): case (nx::nca::HASH_NONE):
info.data_offset = info.offset;
info.data_size = info.size;
break;
case (nx::nca::HASH_HIERARCHICAL_SHA256): 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): 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; break;
default: default:
continue; continue;
} }
// create reader // create reader based on encryption type0
switch(fs_header.encryption_type) switch(fs_header.encryption_type)
{ {
case (nx::nca::CRYPT_AESXTS): case (nx::nca::CRYPT_AESXTS):
case (nx::nca::CRYPT_AESCTREX): case (nx::nca::CRYPT_AESCTREX):
mPartitions[partition.index].reader = nullptr; info.reader = nullptr;
break; break;
case (nx::nca::CRYPT_AESCTR): 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; break;
case (nx::nca::CRYPT_NONE): case (nx::nca::CRYPT_NONE):
mPartitions[partition.index].reader = new CopiedIFile(mReader); info.reader = new CopiedIFile(mReader);
break; break;
default: default:
error.clear(); error.clear();
error << "NCA FS Header [" << partition.index << "] EncryptionType(" << fs_header.encryption_type << "): UNKNOWN \n"; error << "NCA FS Header [" << partition.index << "] EncryptionType(" << fs_header.encryption_type << "): UNKNOWN \n";
throw fnd::Exception(kModuleName, error.str()); 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"); printf(" Partitions:\n");
for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++) for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++)
{ {
const nx::NcaHeader::sPartition& partition = mHdr.getPartitions()[i]; sPartitionInfo& info = mPartitions[i];
nx::sNcaFsHeader& fs_header = mHdrBlock.fs_header[partition.index];
printf(" %lu:\n", i); printf(" %lu:\n", i);
printf(" Index: %d\n", partition.index); printf(" Offset: 0x%" PRIx64 "\n", info.offset);
printf(" Offset: 0x%" PRIx64 "\n", partition.offset); printf(" Size: 0x%" PRIx64 "\n", info.size);
printf(" Size: 0x%" PRIx64 "\n", partition.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(" FsHeader:\n");
printf(" Version: 0x%d\n", fs_header.version.get()); printf(" Version: 0x%d\n", info.version);
printf(" Format Type: %s\n", kFormatTypeStr[fs_header.format_type].c_str()); printf(" Format Type: %s\n", kFormatTypeStr[info.format_type].c_str());
printf(" Hash Type: %s\n", kHashTypeStr[fs_header.hash_type].c_str()); printf(" Hash Type: %s\n", kHashTypeStr[info.hash_type].c_str());
printf(" Enc. Type: %s\n", kEncryptionTypeStr[fs_header.encryption_type].c_str()); printf(" Enc. Type: %s\n", kEncryptionTypeStr[info.enc_type].c_str());
if (fs_header.encryption_type == nx::nca::CRYPT_AESCTR) if (info.enc_type == nx::nca::CRYPT_AESCTR)
{ {
printf(" CTR: "); printf(" AES-CTR: ");
crypto::aes::sAesIvCtr ctr; crypto::aes::sAesIvCtr ctr;
nx::NcaUtils::getNcaPartitionAesCtr(&fs_header, ctr.iv); crypto::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
crypto::aes::AesIncrementCounter(ctr.iv, partition.offset>>4, ctr.iv);
fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(crypto::aes::sAesIvCtr)); 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(" HierarchicalIntegrity Header:\n");
printf(" TypeId: 0x%x\n", hash_hdr.type_id.get()); //printf(" TypeId: 0x%x\n", hash_hdr.type_id.get());
printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get()); //printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get());
printf(" LayerNum: %d\n", hash_hdr.layer_num.get()); //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize());
for (size_t i = 0; i < hash_hdr.layer_num.get(); i++) for (size_t j = 0; j < hash_hdr.getLayerInfo().getSize(); j++)
{ {
printf(" Layer %d:\n", i); printf(" Layer %d:\n", j);
printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.layer[i].offset.get()); printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[j].offset);
printf(" Size: 0x%" PRIx64 "\n", hash_hdr.layer[i].size.get()); printf(" Size: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[j].size);
printf(" BlockSize: 0x%" PRIx32 "\n", hash_hdr.layer[i].block_size.get()); 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); 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(" HierarchicalSha256 Header:\n");
printf(" Master Hash: "); printf(" Master Hash: ");
fnd::SimpleTextOutput::hexDump(hash_hdr.master_hash.bytes, sizeof(crypto::sha::sSha256Hash)); fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHash().bytes, sizeof(crypto::sha::sSha256Hash));
printf(" HashBlockSize: 0x%x\n", hash_hdr.hash_block_size.get()); printf(" HashBlockSize: 0x%x\n", hash_hdr.getHashBlockSize());
printf(" LayerNum: %d\n", hash_hdr.layer_num.get()); //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize());
for (size_t i = 0; i < hash_hdr.layer_num.get(); i++) for (size_t i = 0; i < hash_hdr.getLayerInfo().getSize(); i++)
{ {
printf(" Layer %d:\n", i); printf(" Layer %d:\n", i);
printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.layer[i].offset.get()); printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[i].offset);
printf(" Size: 0x%" PRIx64 "\n", hash_hdr.layer[i].size.get()); printf(" Size: 0x%" PRIx64 "\n", hash_hdr.getLayerInfo()[i].size);
} }
} }
else //else
{ //{
printf(" Hash Superblock:\n"); // printf(" Hash Superblock:\n");
fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen);
} //}
} }
} }

View file

@ -3,6 +3,9 @@
#include <fnd/types.h> #include <fnd/types.h>
#include <fnd/SimpleFile.h> #include <fnd/SimpleFile.h>
#include <nx/NcaHeader.h> #include <nx/NcaHeader.h>
#include <nx/HierarchicalSha256Header.h>
#include <nx/HierarchicalIntegrityHeader.h>
#include "nstool.h" #include "nstool.h"
@ -64,14 +67,15 @@ private:
size_t size; size_t size;
size_t data_offset; size_t data_offset;
size_t data_size; size_t data_size;
// meta data
uint16_t version;
nx::nca::FormatType format_type; nx::nca::FormatType format_type;
nx::nca::HashType hash_type; nx::nca::HashType hash_type;
nx::nca::EncryptionType enc_type;
union { nx::HierarchicalSha256Header hierarchicalsha256_header;
byte_t hash_superblock[nx::nca::kFsHeaderHashSuperblockLen]; nx::HierarchicalIntegrityHeader hierarchicalintergrity_header;
nx::sHierarchicalSha256Header hierarchicalsha256_header; crypto::aes::sAesIvCtr aes_ctr;
nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header;
};
} mPartitions[nx::nca::kPartitionNum]; } mPartitions[nx::nca::kPartitionNum];
void generateNcaBodyEncryptionKeys(); void generateNcaBodyEncryptionKeys();