mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 18:55:29 +00:00
[libnx|nstool] Added HierarchicalSha256Header and HierarchicalIntegrityHeader
This commit is contained in:
parent
d93116863e
commit
446927b53e
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue