Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ctrtool/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ shared_lib: $(SRC_OBJ) create_binary_dir
# Build Program
program: $(SRC_OBJ) create_binary_dir
@echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME)
@$(CXX) $(ARCHFLAGS) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)"
@$(CXX) $(LDFLAGS) $(ARCHFLAGS) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)"

# Build Test Program
test_program: $(TESTSRC_OBJ) $(SRC_OBJ) create_binary_dir
Expand Down
23 changes: 22 additions & 1 deletion ctrtool/src/CciProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ ctrtool::CciProcess::CciProcess() :
mValidCryptoType(ValidState::Unchecked),
mDecryptedTitleKey(),
mNcchProcess(),
mFsReader()
mFsReader(),
mDecryptNcch(false)
{
memset(&mHeader, 0, sizeof(mHeader));
}
Expand Down Expand Up @@ -384,6 +385,21 @@ void ctrtool::CciProcess::extractFs()

// begin export
mFsReader->openFile(*itr, tc::io::FileMode::Open, tc::io::FileAccess::Read, in_stream);
// decrypt ncch
if (mDecryptNcch)
{
if (mVerbose)
{
fmt::print(stderr, "[{} LOG] Decrypting NCCH partition before saving {}...\n", mModuleLabel, out_path.to_string());
}

NcchProcess ncchProcess;
ncchProcess.setInputStream(in_stream);
ncchProcess.setVerboseMode(mVerbose);
ncchProcess.setKeyBag(mKeyBag);
ncchProcess.decryptNcchStream(in_stream);
}

local_fs.openFile(out_path, tc::io::FileMode::OpenOrCreate, tc::io::FileAccess::Write, out_stream);

in_stream->seek(0, tc::io::SeekOrigin::Begin);
Expand Down Expand Up @@ -586,4 +602,9 @@ std::string ctrtool::CciProcess::getCryptoTypeString(byte_t crypto_type)
std::string ctrtool::CciProcess::getTitleVersionString(uint16_t version)
{
return fmt::format("{major:d}.{minor:d}.{build:d}", fmt::arg("major", (uint32_t)((version >> 10) & 0x3F)), fmt::arg("minor", (uint32_t)((version >> 4) & 0x3F)), fmt::arg("build", (uint32_t)(version & 0xF)));
}

void ctrtool::CciProcess::setDecryptNcch(bool decryptNcch)
{
mDecryptNcch = decryptNcch;
}
4 changes: 3 additions & 1 deletion ctrtool/src/CciProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ class CciProcess
void setVerifyMode(bool verify);
void setExtractPath(const tc::io::Path& extract_path);
void setContentIndex(size_t index);

// ncch settings passed on
void setRawMode(bool raw);
void setPlainMode(bool plain);
void setShowSyscallName(bool show_name);
void setNcchRegionProcessOutputMode(NcchProcess::NcchRegion region, bool show_info, bool show_fs, const tc::Optional<tc::io::Path>& bin_extract_path, const tc::Optional<tc::io::Path>& fs_extract_path);
void setDecryptNcch(bool decryptNcch);

void process();
private:
Expand All @@ -38,6 +39,7 @@ class CciProcess
bool mVerify;
tc::Optional<tc::io::Path> mExtractPath;
size_t mContentIndex;
bool mDecryptNcch;

int64_t mBlockSize;
int64_t mUsedImageSize;
Expand Down
19 changes: 19 additions & 0 deletions ctrtool/src/CiaProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,20 @@ void ctrtool::CiaProcess::extractCia()
{
fmt::print(stderr, "[{} LOG] Saving content {:04x} to {}...\n", mModuleLabel, itr->second.cindex, out_path.to_string());
}

if (mDecryptNcch)
{
if (mVerbose)
{
fmt::print(stderr, "[{} LOG] Decrypting NCCH partition before saving {}...\n", mModuleLabel, out_path.to_string());
}

NcchProcess ncchProcess;
ncchProcess.setInputStream(in_stream);
ncchProcess.setVerboseMode(mVerbose);
ncchProcess.setKeyBag(mKeyBag);
ncchProcess.decryptNcchStream(in_stream);
}

writeStreamToFile(in_stream, out_path, cache);
}
Expand Down Expand Up @@ -955,4 +969,9 @@ std::string ctrtool::CiaProcess::getCertificatePublicKeyTypeString(brd::es::ESCe
std::string ctrtool::CiaProcess::getTitleVersionString(uint16_t version)
{
return fmt::format("{major:d}.{minor:d}.{build:d}", fmt::arg("major", (uint32_t)((version >> 10) & 0x3F)), fmt::arg("minor", (uint32_t)((version >> 4) & 0x3F)), fmt::arg("build", (uint32_t)(version & 0xF)));
}

void ctrtool::CiaProcess::setDecryptNcch(bool decryptNcch)
{
mDecryptNcch = decryptNcch;
}
2 changes: 2 additions & 0 deletions ctrtool/src/CiaProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class CiaProcess
void setPlainMode(bool plain);
void setShowSyscallName(bool show_name);
void setNcchRegionProcessOutputMode(NcchProcess::NcchRegion region, bool show_info, bool show_fs, const tc::Optional<tc::io::Path>& bin_extract_path, const tc::Optional<tc::io::Path>& fs_extract_path);
void setDecryptNcch(bool decryptNcch);

void process();
private:
Expand All @@ -53,6 +54,7 @@ class CiaProcess
tc::Optional<tc::io::Path> mContentExtractPath;
tc::Optional<tc::io::Path> mFooterExtractPath;
size_t mContentIndex;
bool mDecryptNcch;

// process variables
ntd::n3ds::CiaHeader mHeader;
Expand Down
40 changes: 40 additions & 0 deletions ctrtool/src/NcchProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1010,3 +1010,43 @@ void ctrtool::NcchProcess::getAesCounter(byte_t* counter, byte_t ncch_region)
tmp->begin_offset.wrap(mRegionInfo[ncch_region].offset);
}
}

void ctrtool::NcchProcess::decryptNcchStream(std::shared_ptr<tc::io::IStream>& outStream)
{
importHeader();
determineRegionLayout();
determineRegionEncryption();

// merge mInputStream with decrypted NcchRegion_ExHeader, NcchRegion_ExeFs, NcchRegion_RomFs
std::vector<std::shared_ptr<tc::io::IStream>> streamSlices;
size_t inputStreamOffset = 0;
for (size_t i = 0; i < NcchRegionNum; i++)
{
if (i == NcchRegion_PlainRegion || i == NcchRegion_Logo) continue;

if (mRegionInfo[i].size)
{
streamSlices.push_back(std::make_shared<tc::io::SubStream>(tc::io::SubStream(mInputStream, inputStreamOffset, mRegionInfo[i].offset - inputStreamOffset)));

// update ncchflag[7] to 0x4 in NCCH header
// TODO: find a way to compute correct RSA-2048 signature in NCCH header
if (i == NcchRegion_Header)
{
size_t ncchflagOffset = 0x188;

streamSlices.push_back(std::make_shared<tc::io::SubStream>(tc::io::SubStream(mRegionInfo[i].ready_stream, 0, ncchflagOffset + 7)));
streamSlices.push_back(std::make_shared<tc::io::MemoryStream>(tc::io::MemoryStream(tc::ByteData({ 0x4 }))));
streamSlices.push_back(std::make_shared<tc::io::SubStream>(tc::io::SubStream(mRegionInfo[i].ready_stream, ncchflagOffset + 8, mRegionInfo[i].size - (ncchflagOffset + 8))));
}
else
{
streamSlices.push_back(mRegionInfo[i].ready_stream);
}

inputStreamOffset = mRegionInfo[i].offset + mRegionInfo[i].size;
}
}
streamSlices.push_back(std::make_shared<tc::io::SubStream>(tc::io::SubStream(mInputStream, inputStreamOffset, mInputStream->length() - inputStreamOffset)));

outStream = std::make_shared<tc::io::ConcatenatedStream>(tc::io::ConcatenatedStream(streamSlices));
}
3 changes: 3 additions & 0 deletions ctrtool/src/NcchProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class NcchProcess
void setRegionProcessOutputMode(NcchRegion region, bool show_info, bool show_fs, const tc::Optional<tc::io::Path>& bin_extract_path, const tc::Optional<tc::io::Path>& fs_extract_path);

void process();

// decrypt NCCH stream
void decryptNcchStream(std::shared_ptr<tc::io::IStream>& outStream);
private:
std::string mModuleLabel;

Expand Down
3 changes: 3 additions & 0 deletions ctrtool/src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ void ctrtool::SettingsInitializer::parse_args(const std::vector<std::string>& ar
// rom options
opts.registerOptionHandler(std::shared_ptr<SingleParamSizetOptionHandler>(new SingleParamSizetOptionHandler(rom.content_process_index, {"-n", "--ncch", "--cidx"})));
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(rom.content_extract_path, {"--contents"})));
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(rom.decrypt_ncch, { "--decrypt" })));


// ncch options
Expand Down Expand Up @@ -631,6 +632,7 @@ void ctrtool::SettingsInitializer::usage_text()
"CCI options:\n"
" -n, --ncch=index Specify NCCH partition index.\n"
" --contents=dir Specify Contents directory path.\n"
" --decrypt Decrypt NCCH partition.\n"
//" --initdata=file Specify Initial Data file path.\n"
"CIA options:\n"
" -n, --ncch=index Specify NCCH partition index.\n"
Expand All @@ -639,6 +641,7 @@ void ctrtool::SettingsInitializer::usage_text()
" --tik=file Specify Ticket file path.\n"
" --tmd=file Specify TMD file path.\n"
" --footer=file Specify Footer file path.\n"
" --decrypt Decrypt NCCH partition.\n"
"NCCH options:\n"
" --exheader=file Specify Extended Header file path.\n"
" --logo=file Specify Logo file path.\n"
Expand Down
2 changes: 2 additions & 0 deletions ctrtool/src/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct Settings
{
size_t content_process_index;
tc::Optional<tc::io::Path> content_extract_path;
bool decrypt_ncch;
} rom;

// CIA options
Expand Down Expand Up @@ -142,6 +143,7 @@ struct Settings

rom.content_process_index = 0;
rom.content_extract_path = tc::Optional<tc::io::Path>();
rom.decrypt_ncch = false;

cia.certs_path = tc::Optional<tc::io::Path>();
cia.tik_path = tc::Optional<tc::io::Path>();
Expand Down
2 changes: 2 additions & 0 deletions ctrtool/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
proc.setRawMode(set.opt.raw);
proc.setPlainMode(set.opt.plain);
proc.setShowSyscallName(set.exheader.show_syscalls_as_names);
proc.setDecryptNcch(set.rom.decrypt_ncch);
proc.setNcchRegionProcessOutputMode(ctrtool::NcchProcess::NcchRegion_Header, set.opt.info, false, tc::Optional<tc::io::Path>(), tc::Optional<tc::io::Path>());
proc.setNcchRegionProcessOutputMode(ctrtool::NcchProcess::NcchRegion_ExHeader, set.opt.info, false, set.ncch.exheader_path, tc::Optional<tc::io::Path>());
proc.setNcchRegionProcessOutputMode(ctrtool::NcchProcess::NcchRegion_PlainRegion, false, false, set.ncch.plainregion_path, tc::Optional<tc::io::Path>());
Expand Down Expand Up @@ -143,6 +144,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
proc.setRawMode(set.opt.raw);
proc.setPlainMode(set.opt.plain);
proc.setShowSyscallName(set.exheader.show_syscalls_as_names);
proc.setDecryptNcch(set.rom.decrypt_ncch);
proc.setNcchRegionProcessOutputMode(ctrtool::NcchProcess::NcchRegion_Header, set.opt.info, false, tc::Optional<tc::io::Path>(), tc::Optional<tc::io::Path>());
proc.setNcchRegionProcessOutputMode(ctrtool::NcchProcess::NcchRegion_ExHeader, set.opt.info, false, set.ncch.exheader_path, tc::Optional<tc::io::Path>());
proc.setNcchRegionProcessOutputMode(ctrtool::NcchProcess::NcchRegion_PlainRegion, false, false, set.ncch.plainregion_path, tc::Optional<tc::io::Path>());
Expand Down
2 changes: 1 addition & 1 deletion makerom/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ static_lib: $(SRC_OBJ) create_binary_dir
# Build Program
program: $(SRC_OBJ) create_binary_dir
@echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME)
@$(CXX) $(ARCHFLAGS) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)"
@$(CXX) $(LDFLAGS) $(ARCHFLAGS) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)"

# Build Test Program
test_program: $(TESTSRC_OBJ) $(SRC_OBJ) create_binary_dir
Expand Down