mirror of
https://github.com/jakcron/nstool
synced 2024-11-15 02:06:40 +00:00
Port NcaProcess to libtoolchain.
This commit is contained in:
parent
83e2403dbc
commit
f04c53f21e
4 changed files with 107 additions and 88 deletions
2
deps/libnintendo-hac
vendored
2
deps/libnintendo-hac
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 6fc9b94f377d41efceef9713215f5c7be9042d9d
|
||||
Subproject commit af437641b9d14381baf69c9399f4177cece7840c
|
|
@ -1,24 +1,17 @@
|
|||
#include "NcaProcess.h"
|
||||
|
||||
#include "PfsProcess.h"
|
||||
#include "RomfsProcess.h"
|
||||
#include "MetaProcess.h"
|
||||
|
||||
//#include <iostream>
|
||||
//#include <iomanip>
|
||||
//#include <sstream>
|
||||
|
||||
//#include <fnd/SimpleTextOutput.h>
|
||||
//#include <fnd/OffsetAdjustedIFile.h>
|
||||
//#include <fnd/AesCtrWrappedIFile.h>
|
||||
//#include <fnd/LayeredIntegrityWrappedIFile.h>
|
||||
//mak#include <memory>
|
||||
#include <tc/crypto/detail/BlockUtilImpl.h>
|
||||
|
||||
#include <nn/hac/ContentArchiveUtil.h>
|
||||
#include <nn/hac/AesKeygen.h>
|
||||
#include <nn/hac/HierarchicalSha256Header.h>
|
||||
#include <nn/hac/HierarchicalIntegrityHeader.h>
|
||||
#include <nn/hac/HierarchicalSha256Stream.h>
|
||||
#include <nn/hac/HierarchicalIntegrityStream.h>
|
||||
#include <nn/hac/PartitionFsMetaGenerator.h>
|
||||
#include <nn/hac/RomFsMetaGenerator.h>
|
||||
#include <nn/hac/CombinedFsMetaGenerator.h>
|
||||
|
||||
|
||||
nstool::NcaProcess::NcaProcess() :
|
||||
mModuleName("nstool::NcaProcess"),
|
||||
|
@ -138,15 +131,12 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
|
|||
|
||||
// process key area
|
||||
sKeys::sKeyAreaKey kak;
|
||||
//KeyBag::aes128_key_t key_area_enc_key;
|
||||
const KeyBag::aes128_key_t* key_area = (const KeyBag::aes128_key_t*) mHdr.getKeyArea();
|
||||
|
||||
for (size_t i = 0; i < nn::hac::nca::kKeyAreaKeyNum; i++)
|
||||
for (size_t i = 0; i < mHdr.getKeyArea().size(); i++)
|
||||
{
|
||||
if (key_area[i] != zero_aesctr_key)
|
||||
if (mHdr.getKeyArea()[i] != zero_aesctr_key)
|
||||
{
|
||||
kak.index = (byte_t)i;
|
||||
kak.enc = key_area[i];
|
||||
kak.enc = mHdr.getKeyArea()[i];
|
||||
kak.decrypted = false;
|
||||
// key[0-3]
|
||||
if (i < 4 && mKeyCfg.nca_key_area_encryption_key[keak_index].find(masterkey_rev) != mKeyCfg.nca_key_area_encryption_key[keak_index].end())
|
||||
|
@ -252,24 +242,16 @@ void nstool::NcaProcess::generatePartitionConfiguration()
|
|||
// setup AES-CTR
|
||||
nn::hac::ContentArchiveUtil::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.data());
|
||||
|
||||
// save partition config
|
||||
if (tc::is_uint64_t_too_large_for_int64_t(partition.offset))
|
||||
{
|
||||
throw tc::Exception(mModuleName, fmt::format("NCA FS Header [{:d}] Offset({:x}): Too large", partition.header_index, partition.offset));
|
||||
}
|
||||
if (tc::is_uint64_t_too_large_for_int64_t(partition.size))
|
||||
{
|
||||
throw tc::Exception(mModuleName, fmt::format("NCA FS Header [{:d}] Size({:x}): Too large", partition.header_index, partition.size));
|
||||
}
|
||||
|
||||
info.reader = nullptr;
|
||||
info.offset = int64_t(partition.offset);
|
||||
info.size = int64_t(partition.size);
|
||||
// save partition configinfo
|
||||
info.offset = partition.offset;
|
||||
info.size = partition.size;
|
||||
info.format_type = (nn::hac::nca::FormatType)fs_header.format_type;
|
||||
info.hash_type = (nn::hac::nca::HashType)fs_header.hash_type;
|
||||
info.enc_type = (nn::hac::nca::EncryptionType)fs_header.encryption_type;
|
||||
if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256)
|
||||
{
|
||||
info.hierarchicalsha256_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
|
||||
/*
|
||||
nn::hac::HierarchicalSha256Header hdr;
|
||||
|
||||
// import raw data
|
||||
|
@ -290,10 +272,13 @@ void nstool::NcaProcess::generatePartitionConfiguration()
|
|||
}
|
||||
}
|
||||
info.hashed_stream_info.master_hash_data = tc::ByteData(hdr.getMasterHash().data(), hdr.getMasterHash().size());
|
||||
info.hashed_stream_info.align_hash_layer_to_block = false;
|
||||
info.hashed_stream_info.align_partial_block_to_blocksize = false;
|
||||
*/
|
||||
}
|
||||
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
|
||||
{
|
||||
info.hierarchicalintegrity_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
|
||||
/*
|
||||
// info.hash_tree_meta.importData(fs_header.hash_info, nn::hac::nca::kHashInfoLen, LayeredIntegrityMetadata::HASH_TYPE_INTEGRITY);
|
||||
nn::hac::HierarchicalIntegrityHeader hdr;
|
||||
|
||||
|
@ -318,14 +303,13 @@ void nstool::NcaProcess::generatePartitionConfiguration()
|
|||
{
|
||||
((nn::hac::detail::sha256_hash_t*)info.hashed_stream_info.master_hash_data.data())[i] = hdr.getMasterHashList()[i];
|
||||
}
|
||||
info.hashed_stream_info.align_hash_layer_to_block = false;
|
||||
info.hashed_stream_info.align_partial_block_to_blocksize = false;
|
||||
*/
|
||||
}
|
||||
|
||||
// create reader
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// create reader based on encryption type0
|
||||
if (info.enc_type == nn::hac::nca::EncryptionType::None)
|
||||
{
|
||||
|
@ -350,13 +334,15 @@ void nstool::NcaProcess::generatePartitionConfiguration()
|
|||
}
|
||||
|
||||
// filter out unrecognised hash types, and hash based readers
|
||||
if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256 || info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
|
||||
{
|
||||
//info.reader = new fnd::LayeredIntegrityWrappedIFile(info.reader, info.layered_intergrity_metadata);
|
||||
info.reader = std::make_shared<nn::hac::HierarchicalValidatedStream>(nn::hac::HierarchicalValidatedStream(info.reader, info.hashed_stream_info));
|
||||
}
|
||||
else if (info.hash_type != nn::hac::nca::HashType::None)
|
||||
switch (info.hash_type)
|
||||
{
|
||||
case (nn::hac::nca::HashType::HierarchicalSha256):
|
||||
info.reader = std::make_shared<nn::hac::HierarchicalSha256Stream>(nn::hac::HierarchicalSha256Stream(info.reader, info.hierarchicalsha256_hdr));
|
||||
break;
|
||||
case (nn::hac::nca::HashType::HierarchicalIntegrity):
|
||||
info.reader = std::make_shared<nn::hac::HierarchicalIntegrityStream>(nn::hac::HierarchicalIntegrityStream(info.reader, info.hierarchicalintegrity_hdr));
|
||||
break;
|
||||
default:
|
||||
throw tc::Exception(mModuleName, fmt::format("HashType({:s}): UNKNOWN", nn::hac::ContentArchiveUtil::getHashTypeAsString(info.hash_type)));
|
||||
}
|
||||
|
||||
|
@ -499,49 +485,57 @@ void nstool::NcaProcess::displayHeader()
|
|||
if (info.enc_type == nn::hac::nca::EncryptionType::AesCtr)
|
||||
{
|
||||
nn::hac::detail::aes_iv_t aes_ctr;
|
||||
//fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
|
||||
memcpy(aes_ctr.data(), info.aes_ctr.data(), aes_ctr.size());
|
||||
tc::crypto::detail::incr_counter<16>(aes_ctr.data(), info.offset>>4);
|
||||
fmt::print(" AesCtr Counter:\n");
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(aes_ctr.data(), aes_ctr.size(), true, ":"));
|
||||
}
|
||||
if (info.hash_type == nn::hac::nca::HashType::HierarchicalIntegrity)
|
||||
{
|
||||
auto hash_hdr = info.hashed_stream_info;
|
||||
auto hash_hdr = info.hierarchicalintegrity_hdr;
|
||||
fmt::print(" HierarchicalIntegrity Header:\n");
|
||||
for (size_t j = 0; j < hash_hdr.hash_layer_info.size(); j++)
|
||||
for (size_t j = 0; j < hash_hdr.getLayerInfo().size(); j++)
|
||||
{
|
||||
if (j+1 == hash_hdr.getLayerInfo().size())
|
||||
{
|
||||
fmt::print(" Data Layer:\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::print(" Hash Layer {:d}:\n", j);
|
||||
fmt::print(" Offset: 0x{:x}\n", hash_hdr.hash_layer_info[j].offset);
|
||||
fmt::print(" Size: 0x{:x}\n", hash_hdr.hash_layer_info[j].size);
|
||||
fmt::print(" BlockSize: 0x{:x}\n", hash_hdr.hash_layer_info[j].block_size);
|
||||
}
|
||||
|
||||
fmt::print(" Data Layer:\n");
|
||||
fmt::print(" Offset: 0x{:x}\n", hash_hdr.data_layer_info.offset);
|
||||
fmt::print(" Size: 0x{:x}\n", hash_hdr.data_layer_info.size);
|
||||
fmt::print(" BlockSize: 0x{:x}\n", hash_hdr.data_layer_info.block_size);
|
||||
size_t master_hash_num = hash_hdr.master_hash_data.size() / sizeof(nn::hac::detail::sha256_hash_t);
|
||||
nn::hac::detail::sha256_hash_t* master_hash_table = (nn::hac::detail::sha256_hash_t*)hash_hdr.master_hash_data.data();
|
||||
for (size_t j = 0; j < master_hash_num; j++)
|
||||
fmt::print(" Offset: 0x{:x}\n", hash_hdr.getLayerInfo()[j].offset);
|
||||
fmt::print(" Size: 0x{:x}\n", hash_hdr.getLayerInfo()[j].size);
|
||||
fmt::print(" BlockSize: 0x{:x}\n", hash_hdr.getLayerInfo()[j].block_size);
|
||||
}
|
||||
for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++)
|
||||
{
|
||||
fmt::print(" Master Hash {:d}:\n", j);
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(master_hash_table[j].data(), 0x10, true, ":"));
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(master_hash_table[j].data()+0x10, 0x10, true, ":"));
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.getMasterHashList()[j].data(), 0x10, true, ":"));
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.getMasterHashList()[j].data()+0x10, 0x10, true, ":"));
|
||||
}
|
||||
}
|
||||
else if (info.hash_type == nn::hac::nca::HashType::HierarchicalSha256)
|
||||
{
|
||||
auto hash_hdr = info.hashed_stream_info;
|
||||
auto hash_hdr = info.hierarchicalsha256_hdr;
|
||||
fmt::print(" HierarchicalSha256 Header:\n");
|
||||
fmt::print(" Master Hash:\n");
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.master_hash_data.data(), 0x10, true, ":"));
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.master_hash_data.data()+0x10, 0x10, true, ":"));
|
||||
fmt::print(" HashBlockSize: 0x{:x}\n", hash_hdr.data_layer_info.block_size);
|
||||
fmt::print(" Hash Layer:\n");
|
||||
fmt::print(" Offset: 0x{:x}\n", hash_hdr.hash_layer_info[0].offset);
|
||||
fmt::print(" Size: 0x{:x}\n", hash_hdr.hash_layer_info[0].size);
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.getMasterHash().data(), 0x10, true, ":"));
|
||||
fmt::print(" {:s}\n", tc::cli::FormatUtil::formatBytesAsString(hash_hdr.getMasterHash().data()+0x10, 0x10, true, ":"));
|
||||
fmt::print(" HashBlockSize: 0x{:x}\n", hash_hdr.getHashBlockSize());
|
||||
for (size_t j = 0; j < hash_hdr.getLayerInfo().size(); j++)
|
||||
{
|
||||
if (j+1 == hash_hdr.getLayerInfo().size())
|
||||
{
|
||||
fmt::print(" Data Layer:\n");
|
||||
fmt::print(" Offset: 0x{:x}\n", hash_hdr.data_layer_info.offset);
|
||||
fmt::print(" Size: 0x{:x}\n", hash_hdr.data_layer_info.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::print(" Hash Layer {:d}:\n", j);
|
||||
}
|
||||
fmt::print(" Offset: 0x{:x}\n", hash_hdr.getLayerInfo()[j].offset);
|
||||
fmt::print(" Size: 0x{:x}\n", hash_hdr.getLayerInfo()[j].size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -550,6 +544,8 @@ void nstool::NcaProcess::displayHeader()
|
|||
|
||||
void nstool::NcaProcess::processPartitions()
|
||||
{
|
||||
std::vector<nn::hac::CombinedFsMetaGenerator::MountPointInfo> mount_points;
|
||||
|
||||
for (size_t i = 0; i < mHdr.getPartitionEntryList().size(); i++)
|
||||
{
|
||||
uint32_t index = mHdr.getPartitionEntryList()[i].header_index;
|
||||
|
@ -566,6 +562,21 @@ void nstool::NcaProcess::processPartitions()
|
|||
fmt::print("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string mount_point_name;
|
||||
/*
|
||||
if (mHdr.getContentType() == nn::hac::nca::ContentType::Program)
|
||||
{
|
||||
mount_point_name = nn::hac::ContentArchiveUtil::getProgramContentParititionIndexAsString((nn::hac::nca::ProgramContentPartitionIndex)index);
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
mount_point_name = fmt::format("{:d}", index);
|
||||
}
|
||||
|
||||
mount_points.push_back( { mount_point_name, partition.fs_meta } );
|
||||
|
||||
/*
|
||||
try {
|
||||
if (partition.format_type == nn::hac::nca::FormatType::PartitionFs)
|
||||
|
@ -611,11 +622,24 @@ void nstool::NcaProcess::processPartitions()
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
tc::io::VirtualFileSystem::FileSystemMeta fs_meta = nn::hac::CombinedFsMetaGenerator(mount_points);
|
||||
|
||||
std::shared_ptr<tc::io::IStorage> nca_fs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(fs_meta));
|
||||
|
||||
mFsProcess.setInputFileSystem(nca_fs);
|
||||
mFsProcess.setFsFormatName("ContentArchive");
|
||||
mFsProcess.setFsProperties({
|
||||
fmt::format("DirNum: {:d}", fs_meta.dir_entries.size()-1),
|
||||
fmt::format("FileNum: {:d}", fs_meta.file_entries.size()-1)
|
||||
});
|
||||
mFsProcess.setFsRootLabel(getContentTypeForMountStr(mHdr.getContentType()));
|
||||
mFsProcess.process();
|
||||
}
|
||||
|
||||
const char* nstool::NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const
|
||||
std::string nstool::NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const
|
||||
{
|
||||
const char* str = nullptr;
|
||||
std::string str;
|
||||
|
||||
switch (cont_type)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#include "FsProcess.h"
|
||||
|
||||
#include <nn/hac/ContentArchiveHeader.h>
|
||||
#include <nn/hac/HierarchicalValidatedStream.h>
|
||||
#include <nn/hac/HierarchicalIntegrityHeader.h>
|
||||
#include <nn/hac/HierarchicalSha256Header.h>
|
||||
|
||||
namespace nstool {
|
||||
|
||||
|
@ -98,14 +99,17 @@ private:
|
|||
nn::hac::nca::FormatType format_type;
|
||||
nn::hac::nca::HashType hash_type;
|
||||
nn::hac::nca::EncryptionType enc_type;
|
||||
nn::hac::HierarchicalValidatedStream::StreamInfo hashed_stream_info;
|
||||
//fnd::LayeredIntegrityMetadata layered_intergrity_metadata;
|
||||
|
||||
// hash meta data
|
||||
nn::hac::HierarchicalIntegrityHeader hierarchicalintegrity_hdr;
|
||||
nn::hac::HierarchicalSha256Header hierarchicalsha256_hdr;
|
||||
|
||||
// crypto metadata
|
||||
nn::hac::detail::aes_iv_t aes_ctr;
|
||||
};
|
||||
|
||||
std::array<sPartitionInfo, nn::hac::nca::kPartitionNum> mPartitions;
|
||||
|
||||
|
||||
void importHeader();
|
||||
void generateNcaBodyEncryptionKeys();
|
||||
void generatePartitionConfiguration();
|
||||
|
@ -113,7 +117,7 @@ private:
|
|||
void displayHeader();
|
||||
void processPartitions();
|
||||
|
||||
const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const;
|
||||
std::string getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const;
|
||||
};
|
||||
|
||||
}
|
13
src/main.cpp
13
src/main.cpp
|
@ -79,17 +79,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
obj.setVerifyMode(set.opt.verify);
|
||||
|
||||
/*
|
||||
if (set.nca.part0_extract_path.isSet())
|
||||
obj.setPartition0ExtractPath(set.nca.part0_extract_path.get());
|
||||
if (set.nca.part1_extract_path.isSet())
|
||||
obj.setPartition1ExtractPath(set.nca.part1_extract_path.get());
|
||||
if (set.nca.part2_extract_path.isSet())
|
||||
obj.setPartition2ExtractPath(set.nca.part2_extract_path.get());
|
||||
if (set.nca.part3_extract_path.isSet())
|
||||
obj.setPartition3ExtractPath(set.nca.part3_extract_path.get());
|
||||
obj.setListFs(set.fs.show_fs_tree);
|
||||
*/
|
||||
obj.setShowFsTree(set.fs.show_fs_tree);
|
||||
obj.setExtractJobs(set.fs.extract_jobs);
|
||||
|
||||
obj.process();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue