Start moving towards a more generatlised hash tree system.

This commit is contained in:
jakcron 2018-05-19 11:57:40 +08:00
parent f2021d851a
commit aa1ed007eb
12 changed files with 206 additions and 71 deletions

View file

@ -0,0 +1,49 @@
#pragma once
#include <nx/hierarchicalintergrity.h>
#include <fnd/MemoryBlob.h>
#include <fnd/List.h>
#include <fnd/ISerialiseableBinary.h>
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);
};
}

View file

@ -0,0 +1,49 @@
#pragma once
#include <nx/hierarchicalsha256.h>
#include <fnd/MemoryBlob.h>
#include <fnd/List.h>
#include <fnd/ISerialiseableBinary.h>
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);
};
}

View file

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <fnd/types.h>
#include <crypto/sha.h>
#include <fnd/ISerialiseableBinary.h>
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)
}

View file

@ -9,6 +9,8 @@ namespace nx
namespace hierarchicalsha256 namespace hierarchicalsha256
{ {
static const size_t kDefaultLevelNum = 2; static const size_t kDefaultLevelNum = 2;
static const size_t kMaxLayoutNum = 2;
} }
#pragma pack(push,1) #pragma pack(push,1)
@ -16,12 +18,12 @@ namespace nx
{ {
crypto::sha::sSha256Hash master_hash; crypto::sha::sSha256Hash master_hash;
le_uint32_t hash_block_size; le_uint32_t hash_block_size;
le_uint32_t hash_level_num; le_uint32_t layer_num;
struct sLayout struct sLayout
{ {
le_uint64_t offset; le_uint64_t offset;
le_uint64_t size; le_uint64_t size;
} hash_data, hash_target; } layer[hierarchicalsha256::kMaxLayoutNum];
}; };
#pragma pack(pop) #pragma pack(pop)
} }

View file

@ -1,36 +0,0 @@
#pragma once
#include <string>
#include <fnd/types.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
#include <fnd/ISerialiseableBinary.h>
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)
}

View file

@ -5,7 +5,7 @@
#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/ivfc.h> #include <nx/hierarchicalintegrity.h>
#include <nx/hierarchicalsha256.h> #include <nx/hierarchicalsha256.h>
namespace nx namespace nx
@ -123,7 +123,7 @@ namespace nx
union { union {
byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen]; byte_t hash_superblock[nca::kFsHeaderHashSuperblockLen];
nx::sHierarchicalSha256Header hierarchicalsha256_header; nx::sHierarchicalSha256Header hierarchicalsha256_header;
nx::sIvfcHeader ivfc_header; nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header;
}; };
crypto::aes::sAesIvCtr base_ctr; crypto::aes::sAesIvCtr base_ctr;
byte_t reserved_1[0xB8]; byte_t reserved_1[0xB8];

View file

@ -30,11 +30,13 @@
<ClInclude Include="include\nx\FacHeader.h" /> <ClInclude Include="include\nx\FacHeader.h" />
<ClInclude Include="include\nx\HandleTableSizeEntry.h" /> <ClInclude Include="include\nx\HandleTableSizeEntry.h" />
<ClInclude Include="include\nx\HandleTableSizeHandler.h" /> <ClInclude Include="include\nx\HandleTableSizeHandler.h" />
<ClInclude Include="include\nx\HierarchicalIntergrityHeader.h" />
<ClInclude Include="include\nx\hierarchicalsha256.h" /> <ClInclude Include="include\nx\hierarchicalsha256.h" />
<ClInclude Include="include\nx\HierarchicalSha256Header.h" />
<ClInclude Include="include\nx\IKernelCapabilityHandler.h" /> <ClInclude Include="include\nx\IKernelCapabilityHandler.h" />
<ClInclude Include="include\nx\InteruptEntry.h" /> <ClInclude Include="include\nx\InteruptEntry.h" />
<ClInclude Include="include\nx\InteruptHandler.h" /> <ClInclude Include="include\nx\InteruptHandler.h" />
<ClInclude Include="include\nx\ivfc.h" /> <ClInclude Include="include\nx\hierarchicalintegrity.h" />
<ClInclude Include="include\nx\KcBinary.h" /> <ClInclude Include="include\nx\KcBinary.h" />
<ClInclude Include="include\nx\KernelCapability.h" /> <ClInclude Include="include\nx\KernelCapability.h" />
<ClInclude Include="include\nx\KernelVersionEntry.h" /> <ClInclude Include="include\nx\KernelVersionEntry.h" />
@ -75,6 +77,8 @@
<ClCompile Include="source\FacHeader.cpp" /> <ClCompile Include="source\FacHeader.cpp" />
<ClCompile Include="source\HandleTableSizeEntry.cpp" /> <ClCompile Include="source\HandleTableSizeEntry.cpp" />
<ClCompile Include="source\HandleTableSizeHandler.cpp" /> <ClCompile Include="source\HandleTableSizeHandler.cpp" />
<ClCompile Include="source\HierarchicalIntegrityHeader.cpp" />
<ClCompile Include="source\HierarchicalSha256Header.cpp" />
<ClCompile Include="source\InteruptEntry.cpp" /> <ClCompile Include="source\InteruptEntry.cpp" />
<ClCompile Include="source\InteruptHandler.cpp" /> <ClCompile Include="source\InteruptHandler.cpp" />
<ClCompile Include="source\KcBinary.cpp" /> <ClCompile Include="source\KcBinary.cpp" />

View file

@ -123,9 +123,6 @@
<ClInclude Include="include\nx\AesKeygen.h"> <ClInclude Include="include\nx\AesKeygen.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="include\nx\ivfc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\nx\NcaUtils.h"> <ClInclude Include="include\nx\NcaUtils.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -150,6 +147,15 @@
<ClInclude Include="include\nx\cnmt.h"> <ClInclude Include="include\nx\cnmt.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="include\nx\hierarchicalintegrity.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\nx\HierarchicalSha256Header.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\nx\HierarchicalIntergrityHeader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="source\AciBinary.cpp"> <ClCompile Include="source\AciBinary.cpp">
@ -254,6 +260,12 @@
<ClCompile Include="source\ContentMetaBinary.cpp"> <ClCompile Include="source\ContentMetaBinary.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="source\HierarchicalIntegrityHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="source\HierarchicalSha256Header.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="makefile" /> <None Include="makefile" />

View file

@ -219,20 +219,33 @@ void NcaProcess::generatePartitionConfiguration()
// determine the data offset & size // determine the data offset & size
if (mPartitions[partition.index].hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) 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_offset = mPartitions[partition.index].hierarchicalsha256_header.layer[1].offset.get();
mPartitions[partition.index].data_size = mPartitions[partition.index].hierarchicalsha256_header.hash_target.size.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) 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) 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++)
{ {
mPartitions[partition.index].data_offset = mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].logical_offset.get(); size_t index = nx::hierarchicalintegrity::kMaxLayerNum - 1 - j;
mPartitions[partition.index].data_size = mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].hash_data_size.get(); 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; break;
} }
} }
*/
} }
else if (mPartitions[partition.index].hash_type == nx::nca::HASH_NONE) 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) if (fs_header.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY)
{ {
nx::sHierarchicalIntegrityHeader& hash_hdr = fs_header.hierarchicalintergrity_header;
printf(" HierarchicalIntegrity Header:\n"); printf(" HierarchicalIntegrity Header:\n");
printf(" Id: 0x%x\n", fs_header.ivfc_header.id.get()); printf(" TypeId: 0x%x\n", hash_hdr.type_id.get());
printf(" MasterHashSize: 0x%x\n", fs_header.ivfc_header.master_hash_size.get()); printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get());
printf(" LevelNum: %d\n", fs_header.ivfc_header.level_num.get()); printf(" LayerNum: %d\n", hash_hdr.layer_num.get());
for (size_t i = 0; i < fs_header.ivfc_header.level_num.get(); i++) for (size_t i = 0; i < hash_hdr.layer_num.get(); i++)
{ {
printf(" Level %d:\n", i); printf(" Layer %d:\n", i);
printf(" LogicalOffset: 0x%" PRIx64 "\n", fs_header.ivfc_header.level_header[i].logical_offset.get()); printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.layer[i].offset.get());
printf(" HashDataSize: 0x%" PRIx64 "\n", fs_header.ivfc_header.level_header[i].hash_data_size.get()); printf(" Size: 0x%" PRIx64 "\n", hash_hdr.layer[i].size.get());
printf(" BlockSize: 0x%" PRIx32 "\n", fs_header.ivfc_header.level_header[i].block_size.get()); printf(" BlockSize: 0x%" PRIx32 "\n", hash_hdr.layer[i].block_size.get());
} }
printf(" Master Hash: "); for (size_t j = 0; j < hash_hdr.master_hash_size.get() / sizeof(crypto::sha::sSha256Hash); j++)
fnd::SimpleTextOutput::hexDump(fs_header.ivfc_header.master_hash.bytes, 0x20); {
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; nx::sHierarchicalSha256Header& hash_hdr = fs_header.hierarchicalsha256_header;
printf(" HierarchicalSha256 Header:\n"); printf(" HierarchicalSha256 Header:\n");
printf(" Master Hash: "); 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(" HashBlockSize: 0x%x\n", hash_hdr.hash_block_size.get());
printf(" HashLevelNum: 0x%x\n", hash_hdr.hash_level_num.get()); printf(" LayerNum: %d\n", hash_hdr.layer_num.get());
printf(" HashDataOffset: 0x%" PRIx64 "\n", hash_hdr.hash_data.offset.get()); for (size_t i = 0; i < hash_hdr.layer_num.get(); i++)
printf(" HashDataSize: 0x%" PRIx64 "\n", hash_hdr.hash_data.size.get()); {
printf(" HashTargetOffset: 0x%" PRIx64 "\n", hash_hdr.hash_target.offset.get()); printf(" Layer %d:\n", i);
printf(" HashTargetSize: 0x%" PRIx64 "\n", hash_hdr.hash_target.size.get()); printf(" Offset: 0x%" PRIx64 "\n", hash_hdr.layer[i].offset.get());
printf(" Size: 0x%" PRIx64 "\n", hash_hdr.layer[i].size.get());
}
} }
else else
{ {

View file

@ -70,7 +70,7 @@ private:
union { union {
byte_t hash_superblock[nx::nca::kFsHeaderHashSuperblockLen]; byte_t hash_superblock[nx::nca::kFsHeaderHashSuperblockLen];
nx::sHierarchicalSha256Header hierarchicalsha256_header; nx::sHierarchicalSha256Header hierarchicalsha256_header;
nx::sIvfcHeader ivfc_header; nx::sHierarchicalIntegrityHeader hierarchicalintergrity_header;
}; };
} mPartitions[nx::nca::kPartitionNum]; } mPartitions[nx::nca::kPartitionNum];