From a62a983399146f3419043184dacbb11745af2d07 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 11 Aug 2018 21:14:33 +0800 Subject: [PATCH 01/50] [nstool] CnmtProcess refactor string resources. --- programs/nstool/source/CnmtProcess.cpp | 228 ++++++++++++++++--------- programs/nstool/source/CnmtProcess.h | 6 + 2 files changed, 152 insertions(+), 82 deletions(-) diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index 1606a9d..aa7f497 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -2,64 +2,59 @@ #include "OffsetAdjustedIFile.h" #include "CnmtProcess.h" -const std::string kContentTypeStr[7] = +CnmtProcess::CnmtProcess() : + mFile(nullptr), + mOwnIFile(false), + mCliOutputMode(_BIT(OUTPUT_BASIC)), + mVerify(false) { - "Meta", - "Program", - "Data", - "Control", - "HtmlDocument", - "LegalInformation", - "DeltaFragment" -}; +} -const std::string kContentMetaTypeStr[2][0x80] = +CnmtProcess::~CnmtProcess() { + if (mOwnIFile) { - "", - "SystemProgram", - "SystemData", - "SystemUpdate", - "BootImagePackage", - "BootImagePackageSafe" - }, - { - "Application", - "Patch", - "AddOnContent", - "Delta" + delete mFile; } -}; - -const std::string kUpdateTypeStr[3] = -{ - "ApplyAsDelta", - "Overwrite", - "Create" -}; - -const std::string kContentMetaAttrStr[3] = -{ - "IncludesExFatDriver", - "Rebootless" -}; - - -std::string kUnknownStr = "Unknown"; - -inline const char* getBoolStr(bool isTrue) -{ - return isTrue? "TRUE" : "FALSE"; } -inline const char* getContentTypeStr(byte_t i) +void CnmtProcess::process() { - return i < 7 ? kContentTypeStr[i].c_str() : kUnknownStr.c_str(); + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); + + mCnmt.fromBytes(scratch.data(), scratch.size()); + + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + displayCmnt(); } -inline const char* getContentMetaTypeStr(byte_t i) +void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) { - return (i < 0x80) ? kContentMetaTypeStr[0][i].c_str() : kContentMetaTypeStr[1][i - 0x80].c_str(); + mFile = file; + mOwnIFile = ownIFile; +} + +void CnmtProcess::setCliOutputMode(CliOutputMode type) +{ + mCliOutputMode = type; +} + +void CnmtProcess::setVerifyMode(bool verify) +{ + mVerify = verify; +} + +const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const +{ + return mCnmt; } void CnmtProcess::displayCmnt() @@ -141,57 +136,126 @@ void CnmtProcess::displayCmnt() #undef _SPLIT_VER } -CnmtProcess::CnmtProcess() : - mFile(nullptr), - mOwnIFile(false), - mCliOutputMode(_BIT(OUTPUT_BASIC)), - mVerify(false) +const char* CnmtProcess::getBoolStr(bool state) const { + return state? "TRUE" : "FALSE"; } -CnmtProcess::~CnmtProcess() +const char* CnmtProcess::getContentTypeStr(byte_t type) const { - if (mOwnIFile) - { - delete mFile; - } -} + const char* str = nullptr; -void CnmtProcess::process() -{ - fnd::Vec scratch; - - if (mFile == nullptr) + switch (type) { - throw fnd::Exception(kModuleName, "No file reader set."); + case (nn::hac::cnmt::TYPE_META): + str = "Meta"; + break; + case (nn::hac::cnmt::TYPE_PROGRAM): + str = "Program"; + break; + case (nn::hac::cnmt::TYPE_DATA): + str = "Data"; + break; + case (nn::hac::cnmt::TYPE_CONTROL): + str = "Control"; + break; + case (nn::hac::cnmt::TYPE_HTML_DOCUMENT): + str = "HtmlDocument"; + break; + case (nn::hac::cnmt::TYPE_LEGAL_INFORMATION): + str = "LegalInformation"; + break; + case (nn::hac::cnmt::TYPE_DELTA_FRAGMENT): + str = "DeltaFragment"; + break; + default: + str = "Unknown"; + break; } - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mCnmt.fromBytes(scratch.data(), scratch.size()); - - if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - displayCmnt(); + return str; } -void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) +const char* CnmtProcess::getContentMetaTypeStr(byte_t type) const { - mFile = file; - mOwnIFile = ownIFile; + const char* str = nullptr; + + switch (type) + { + case (nn::hac::cnmt::METATYPE_SYSTEM_PROGRAM): + str = "SystemProgram"; + break; + case (nn::hac::cnmt::METATYPE_SYSTEM_DATA): + str = "SystemData"; + break; + case (nn::hac::cnmt::METATYPE_SYSTEM_UPDATE): + str = "SystemUpdate"; + break; + case (nn::hac::cnmt::METATYPE_BOOT_IMAGE_PACKAGE): + str = "BootImagePackage"; + break; + case (nn::hac::cnmt::METATYPE_BOOT_IMAGE_PACKAGE_SAFE): + str = "BootImagePackageSafe"; + break; + case (nn::hac::cnmt::METATYPE_APPLICATION): + str = "Application"; + break; + case (nn::hac::cnmt::METATYPE_PATCH): + str = "Patch"; + break; + case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT): + str = "AddOnContent"; + break; + case (nn::hac::cnmt::METATYPE_DELTA): + str = "Delta"; + break; + default: + str = "Unknown"; + break; + } + + return str; } -void CnmtProcess::setCliOutputMode(CliOutputMode type) +const char* CnmtProcess::getUpdateTypeStr(byte_t type) const { - mCliOutputMode = type; + const char* str = nullptr; + + switch (type) + { + case (nn::hac::cnmt::UPDATETYPE_APPLY_AS_DELTA): + str = "ApplyAsDelta"; + break; + case (nn::hac::cnmt::UPDATETYPE_OVERWRITE): + str = "Overwrite"; + break; + case (nn::hac::cnmt::UPDATETYPE_CREATE): + str = "Create"; + break; + default: + str = "Unknown"; + break; + } + + return str; } -void CnmtProcess::setVerifyMode(bool verify) +const char* CnmtProcess::getContentMetaAttrStr(byte_t type) const { - mVerify = verify; -} + const char* str = nullptr; -const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const -{ - return mCnmt; + switch (type) + { + case (nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER): + str = "IncludesExFatDriver"; + break; + case (nn::hac::cnmt::ATTRIBUTE_REBOOTLESS): + str = "Rebootless"; + break; + default: + str = "Unknown"; + break; + } + + return str; } diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index 1f4ca52..cd320e3 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -31,4 +31,10 @@ private: nn::hac::ContentMetaBinary mCnmt; void displayCmnt(); + + const char* getBoolStr(bool state) const; + const char* getContentTypeStr(byte_t type) const; + const char* getContentMetaTypeStr(byte_t type) const; + const char* getUpdateTypeStr(byte_t type) const; + const char* getContentMetaAttrStr(byte_t type) const; }; \ No newline at end of file From 9b6438790528ebe068010290e6ced1fd28795189 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:22:07 +0800 Subject: [PATCH 02/50] [nstool] Cleaned up AssetProcess string output. --- programs/nstool/source/AssetProcess.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/programs/nstool/source/AssetProcess.cpp b/programs/nstool/source/AssetProcess.cpp index ef48adf..7dd8726 100644 --- a/programs/nstool/source/AssetProcess.cpp +++ b/programs/nstool/source/AssetProcess.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include "AssetProcess.h" #include "OffsetAdjustedIFile.h" @@ -141,16 +143,16 @@ void AssetProcess::displayHeader() { if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf("[ASET Header]\n"); - printf(" Icon:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getIconInfo().offset); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getIconInfo().size); - printf(" NACP:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getNacpInfo().offset); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getNacpInfo().size); - printf(" RomFS:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().offset); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().size); + std::cout << "[ASET Header]" << std::endl; + std::cout << " Icon:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getIconInfo().offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getIconInfo().size << std::endl; + std::cout << " NACP:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getNacpInfo().offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getNacpInfo().size << std::endl; + std::cout << " RomFS:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRomfsInfo().offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRomfsInfo().size << std::endl; } } From 08612d487e1aa8ae6d35c16fc8749241ea050008 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:22:29 +0800 Subject: [PATCH 03/50] [nstool] Cleaned up CnmtProcess string output. --- programs/nstool/source/CnmtProcess.cpp | 89 +++++++++++++------------- programs/nstool/source/CnmtProcess.h | 8 +-- 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index aa7f497..7e39b7a 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "OffsetAdjustedIFile.h" #include "CnmtProcess.h" @@ -59,38 +61,37 @@ const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const void CnmtProcess::displayCmnt() { -#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) +#define _SPLIT_VER(ver) (uint32_t)((ver>>26) & 0x3f) << "." << (uint32_t)((ver>>20) & 0x3f) << "." << (uint32_t)((ver>>16) & 0xf) << "." << (uint32_t)(ver & 0xffff) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - printf("[ContentMeta]\n"); - printf(" TitleId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getTitleId()); - printf(" Version: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getTitleVersion(), _SPLIT_VER(mCnmt.getTitleVersion())); - printf(" Type: %s (%d)\n", getContentMetaTypeStr(mCnmt.getType()), mCnmt.getType()); - printf(" Attributes: %x\n", mCnmt.getAttributes()); - printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER))); - printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS))); - printf(" RequiredDownloadSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getRequiredDownloadSystemVersion(), _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion())); + std::cout << "[ContentMeta]" << std::endl; + std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << std::endl; + std::cout << " Version: v" << std::dec << mCnmt.getTitleVersion() << " (" << _SPLIT_VER(mCnmt.getTitleVersion()) << ")"<< std::endl; + std::cout << " Type: " << getContentMetaTypeStr(mCnmt.getType()) << " (" << std::dec << mCnmt.getType() << ")" << std::endl; + std::cout << " Attributes: " << std::hex << mCnmt.getAttributes() << std::endl; + std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl; + std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl; + std::cout << " RequiredDownloadSystemVersion: v" << mCnmt.getRequiredDownloadSystemVersion() << " (" << _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()) << ")"<< std::endl; switch(mCnmt.getType()) { case (nn::hac::cnmt::METATYPE_APPLICATION): - printf(" ApplicationExtendedHeader:\n"); - printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getApplicationMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().required_system_version)); - printf(" PatchId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getApplicationMetaExtendedHeader().patch_id); + std::cout << " ApplicationExtendedHeader:" << std::endl; + std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getApplicationMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " PatchId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getApplicationMetaExtendedHeader().patch_id << std::endl; break; case (nn::hac::cnmt::METATYPE_PATCH): - printf(" PatchMetaExtendedHeader:\n"); - printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d))\n", (uint32_t)mCnmt.getPatchMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().required_system_version)); - printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getPatchMetaExtendedHeader().application_id); + std::cout << " PatchMetaExtendedHeader:" << std::endl; + std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getPatchMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getPatchMetaExtendedHeader().application_id << std::endl; break; case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT): - printf(" AddOnContentMetaExtendedHeader:\n"); - printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getAddOnContentMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_system_version)); - printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getAddOnContentMetaExtendedHeader().application_id); + std::cout << " AddOnContentMetaExtendedHeader:" << std::endl; + std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getAddOnContentMetaExtendedHeader().application_id << std::endl; break; case (nn::hac::cnmt::METATYPE_DELTA): - printf(" DeltaMetaExtendedHeader:\n"); - printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getDeltaMetaExtendedHeader().application_id); + std::cout << " DeltaMetaExtendedHeader:" << std::endl; + std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getDeltaMetaExtendedHeader().application_id << std::endl; break; default: break; @@ -101,38 +102,38 @@ void CnmtProcess::displayCmnt() for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++) { const nn::hac::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i]; - printf(" %d\n", (int)i); - printf(" Type: %s (%d)\n", getContentTypeStr(info.type), info.type); - printf(" Id: "); + std::cout << " " << std::dec << i << std::endl; + std::cout << " Type: " << getContentTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl; + std::cout << " Id: "; _HEXDUMP_L(info.nca_id, nn::hac::cnmt::kContentIdLen); - printf("\n"); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); - printf(" Hash: "); + std::cout << std::endl; + std::cout << " Size: 0x" << std::hex << info.size << std::endl; + std::cout << " Hash: "; _HEXDUMP_L(info.hash.bytes, sizeof(info.hash)); - printf("\n"); + std::cout << std::endl; } } if (mCnmt.getContentMetaInfo().size() > 0) { - printf(" ContentMetaInfo:\n"); + std::cout << " ContentMetaInfo:" << std::endl; for (size_t i = 0; i < mCnmt.getContentMetaInfo().size(); i++) { const nn::hac::ContentMetaBinary::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i]; - printf(" %d\n", (int)i); - printf(" Id: 0x%016" PRIx64 "\n", (uint64_t)info.id); - printf(" Version: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)info.version, _SPLIT_VER(info.version)); - printf(" Type: %s (%d)\n", getContentMetaTypeStr(info.type), info.type); - printf(" Attributes: %x\n", mCnmt.getAttributes()); - printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER))); - printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS))); + std::cout << " " << std::dec << i << std::endl; + std::cout << " Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << info.id << std::endl; + std::cout << " Version: v" << std::dec << info.version << " (" << _SPLIT_VER(info.version) << ")"<< std::endl; + std::cout << " Type: " << getContentMetaTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl; + std::cout << " Attributes: " << std::hex << info.attributes << std::endl; + std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl; + std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl; } } - printf(" Digest: "); + + std::cout << " Digest: "; _HEXDUMP_L(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen); - printf("\n"); + std::cout << std::endl; #undef _HEXDUMP_L -#undef _HEXDUMP_U #undef _SPLIT_VER } @@ -141,7 +142,7 @@ const char* CnmtProcess::getBoolStr(bool state) const return state? "TRUE" : "FALSE"; } -const char* CnmtProcess::getContentTypeStr(byte_t type) const +const char* CnmtProcess::getContentTypeStr(nn::hac::cnmt::ContentType type) const { const char* str = nullptr; @@ -176,7 +177,7 @@ const char* CnmtProcess::getContentTypeStr(byte_t type) const return str; } -const char* CnmtProcess::getContentMetaTypeStr(byte_t type) const +const char* CnmtProcess::getContentMetaTypeStr(nn::hac::cnmt::ContentMetaType type) const { const char* str = nullptr; @@ -217,7 +218,7 @@ const char* CnmtProcess::getContentMetaTypeStr(byte_t type) const return str; } -const char* CnmtProcess::getUpdateTypeStr(byte_t type) const +const char* CnmtProcess::getUpdateTypeStr(nn::hac::cnmt::UpdateType type) const { const char* str = nullptr; @@ -240,11 +241,11 @@ const char* CnmtProcess::getUpdateTypeStr(byte_t type) const return str; } -const char* CnmtProcess::getContentMetaAttrStr(byte_t type) const +const char* CnmtProcess::getContentMetaAttrStr(nn::hac::cnmt::ContentMetaAttribute attr) const { const char* str = nullptr; - switch (type) + switch (attr) { case (nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER): str = "IncludesExFatDriver"; diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index cd320e3..7e2f113 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -33,8 +33,8 @@ private: void displayCmnt(); const char* getBoolStr(bool state) const; - const char* getContentTypeStr(byte_t type) const; - const char* getContentMetaTypeStr(byte_t type) const; - const char* getUpdateTypeStr(byte_t type) const; - const char* getContentMetaAttrStr(byte_t type) const; + const char* getContentTypeStr(nn::hac::cnmt::ContentType type) const; + const char* getContentMetaTypeStr(nn::hac::cnmt::ContentMetaType type) const; + const char* getUpdateTypeStr(nn::hac::cnmt::UpdateType type) const; + const char* getContentMetaAttrStr(nn::hac::cnmt::ContentMetaAttribute attr) const; }; \ No newline at end of file From a6b6aec978510faa5b9cb61c76ae8c58c2bf3a96 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:22:53 +0800 Subject: [PATCH 04/50] [nstool] Cleaned up EsTikProcess string output. --- programs/nstool/source/EsTikProcess.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp index cec162a..a16c0f4 100644 --- a/programs/nstool/source/EsTikProcess.cpp +++ b/programs/nstool/source/EsTikProcess.cpp @@ -106,9 +106,7 @@ void EsTikProcess::verifyTicket() void EsTikProcess::displayTicket() { -#define _SPLIT_VER(ver) ( (ver>>10) & 0x3f), ( (ver>>4) & 0x3f), ( (ver>>0) & 0xf) -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) +#define _SPLIT_VER(ver) (uint32_t)((ver>>10) & 0x3f) << "." << (uint32_t)((ver>>4) & 0x3f) << "." << (uint32_t)((ver>>0) & 0xf) const nn::es::TicketBody_V2& body = mTik.getBody(); @@ -127,10 +125,10 @@ void EsTikProcess::displayTicket() size_t size = body.getTitleKeyEncType() == nn::es::ticket::RSA2048 ? fnd::rsa::kRsa2048Size : fnd::aes::kAes128KeySize; fnd::SimpleTextOutput::hexDump(body.getEncTitleKey(), size, 0x10, 6); - printf(" Version: v%d.%d.%d", _SPLIT_VER(body.getTicketVersion())); + std::cout << " Version: v" << _SPLIT_VER(body.getTicketVersion()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" (%d)", body.getTicketVersion()); - printf("\n"); + std::cout << " (" << (uint32_t)body.getTicketVersion() << ")"; + std::cout << std::endl; std::cout << " License Type: " << getLicenseTypeStr(body.getLicenseType()) << std::endl; @@ -163,9 +161,6 @@ void EsTikProcess::displayTicket() std::cout << " SectionNum: 0x" << std::hex << body.getSectionNum() << std::endl; std::cout << " SectionEntrySize: 0x" << std::hex << body.getSectionEntrySize() << std::endl; - -#undef _HEXDUMP_L -#undef _HEXDUMP_U #undef _SPLIT_VER } From 4eec7f30ff1bb74765d7a5ae2ab854d82126140f Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:23:17 +0800 Subject: [PATCH 05/50] [nstool] Improved NacpProcess str resource management. --- programs/nstool/source/NacpProcess.cpp | 876 +++++++++++++------------ programs/nstool/source/NacpProcess.h | 19 + 2 files changed, 475 insertions(+), 420 deletions(-) diff --git a/programs/nstool/source/NacpProcess.cpp b/programs/nstool/source/NacpProcess.cpp index 52cb2f8..aa3f83c 100644 --- a/programs/nstool/source/NacpProcess.cpp +++ b/programs/nstool/source/NacpProcess.cpp @@ -3,426 +3,6 @@ #include "OffsetAdjustedIFile.h" #include "NacpProcess.h" -const char* getLanguageStr(nn::hac::nacp::Language var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::LANG_AmericanEnglish): - str = "AmericanEnglish"; - break; - case (nn::hac::nacp::LANG_BritishEnglish): - str = "BritishEnglish"; - break; - case (nn::hac::nacp::LANG_Japanese): - str = "Japanese"; - break; - case (nn::hac::nacp::LANG_French): - str = "French"; - break; - case (nn::hac::nacp::LANG_German): - str = "German"; - break; - case (nn::hac::nacp::LANG_LatinAmericanSpanish): - str = "LatinAmericanSpanish"; - break; - case (nn::hac::nacp::LANG_Spanish): - str = "Spanish"; - break; - case (nn::hac::nacp::LANG_Italian): - str = "Italian"; - break; - case (nn::hac::nacp::LANG_Dutch): - str = "Dutch"; - break; - case (nn::hac::nacp::LANG_CanadianFrench): - str = "CanadianFrench"; - break; - case (nn::hac::nacp::LANG_Portuguese): - str = "Portuguese"; - break; - case (nn::hac::nacp::LANG_Russian): - str = "Russian"; - break; - case (nn::hac::nacp::LANG_Korean): - str = "Korean"; - break; - case (nn::hac::nacp::LANG_TraditionalChinese): - str = "TraditionalChinese"; - break; - case (nn::hac::nacp::LANG_SimplifiedChinese): - str = "SimplifiedChinese"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::USER_None): - str = "None"; - break; - case (nn::hac::nacp::USER_Required): - str = "Required"; - break; - case (nn::hac::nacp::USER_RequiredWithNetworkServiceAccountAvailable): - str = "RequiredWithNetworkServiceAccountAvailable"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::TOUCH_None): - str = "None"; - break; - case (nn::hac::nacp::TOUCH_Supported): - str = "Supported"; - break; - case (nn::hac::nacp::TOUCH_Required): - str = "Required"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::AOC_AllOnLaunch): - str = "AllOnLaunch"; - break; - case (nn::hac::nacp::AOC_OnDemand): - str = "OnDemand"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::ATTR_None): - str = "None"; - break; - case (nn::hac::nacp::ATTR_Demo): - str = "Demo"; - break; - case (nn::hac::nacp::ATTR_RetailInteractiveDisplay): - str = "RetailInteractiveDisplay"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::PC_None): - str = "None"; - break; - case (nn::hac::nacp::PC_FreeCommunication): - str = "FreeCommunication"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::SCRN_Allow): - str = "Allow"; - break; - case (nn::hac::nacp::SCRN_Deny): - str = "Deny"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::VCAP_Disable): - str = "Disable"; - break; - case (nn::hac::nacp::VCAP_Manual): - str = "Manual"; - break; - case (nn::hac::nacp::VCAP_Enable): - str = "Enable"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::DLOSS_None): - str = "None"; - break; - case (nn::hac::nacp::DLOSS_Required): - str = "Required"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::PLP_All): - str = "All"; - break; - case (nn::hac::nacp::PLP_LogOnly): - str = "LogOnly"; - break; - case (nn::hac::nacp::PLP_None): - str = "None"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getOrganisationStr(nn::hac::nacp::Organisation var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::ORGN_CERO): - str = "CERO"; - break; - case (nn::hac::nacp::ORGN_GRACGCRB): - str = "GRACGCRB"; - break; - case (nn::hac::nacp::ORGN_GSRMR): - str = "GSRMR"; - break; - case (nn::hac::nacp::ORGN_ESRB): - str = "ESRB"; - break; - case (nn::hac::nacp::ORGN_ClassInd): - str = "ClassInd"; - break; - case (nn::hac::nacp::ORGN_USK): - str = "USK"; - break; - case (nn::hac::nacp::ORGN_PEGI): - str = "PEGI"; - break; - case (nn::hac::nacp::ORGN_PEGIPortugal): - str = "PEGIPortugal"; - break; - case (nn::hac::nacp::ORGN_PEGIBBFC): - str = "PEGIBBFC"; - break; - case (nn::hac::nacp::ORGN_Russian): - str = "Russian"; - break; - case (nn::hac::nacp::ORGN_ACB): - str = "ACB"; - break; - case (nn::hac::nacp::ORGN_OFLC): - str = "OFLC"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getLogoTypeStr(nn::hac::nacp::LogoType var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::LOGO_LicensedByNintendo): - str = "LicensedByNintendo"; - break; - case (nn::hac::nacp::LOGO_DistributedByNintendo): - str = "DistributedByNintendo"; - break; - case (nn::hac::nacp::LOGO_Nintendo): - str = "Nintendo"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::LHND_Auto): - str = "Auto"; - break; - case (nn::hac::nacp::LHND_None): - str = "None"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::RTAOC_Deny): - str = "Deny"; - break; - case (nn::hac::nacp::RTAOC_AllowAppend): - str = "AllowAppend"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::CREP_Deny): - str = "Deny"; - break; - case (nn::hac::nacp::CREP_Allow): - str = "Allow"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getHdcpStr(nn::hac::nacp::Hdcp var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::HDCP_None): - str = "None"; - break; - case (nn::hac::nacp::HDCP_Required): - str = "Required"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::PLQC_None): - str = "None"; - break; - case (nn::hac::nacp::PLQC_Whitelist): - str = "Whitelist"; - break; - case (nn::hac::nacp::PLQC_All): - str = "All"; - break; - default: - str = "Unknown"; - } - return str; -} - -const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var) -{ - const char* str = nullptr; - switch(var) - { - case (nn::hac::nacp::REPF_None): - str = "None"; - break; - case (nn::hac::nacp::REPF_SuppressGameCardAccess): - str = "SuppressGameCardAccess"; - break; - default: - str = "Unknown"; - } - return str; -} - -std::string getSaveDataSizeStr(int64_t size) -{ - static const int64_t kKiloByte = 1024; - static const int64_t kMegaByte = 1024 * 1024; - - std::stringstream sstr; - - - if (size < kKiloByte) - { - sstr << size << " B"; - } - else if (size < kMegaByte) - { - sstr << (size/kKiloByte) << " KB"; - } - else - { - sstr << (size/kMegaByte) << " MB"; - } - - return sstr.str(); -} - NacpProcess::NacpProcess() : mFile(nullptr), mOwnIFile(false), @@ -598,3 +178,459 @@ void NacpProcess::displayNacp() printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId()); } } + +const char* NacpProcess::getLanguageStr(nn::hac::nacp::Language var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::LANG_AmericanEnglish): + str = "AmericanEnglish"; + break; + case (nn::hac::nacp::LANG_BritishEnglish): + str = "BritishEnglish"; + break; + case (nn::hac::nacp::LANG_Japanese): + str = "Japanese"; + break; + case (nn::hac::nacp::LANG_French): + str = "French"; + break; + case (nn::hac::nacp::LANG_German): + str = "German"; + break; + case (nn::hac::nacp::LANG_LatinAmericanSpanish): + str = "LatinAmericanSpanish"; + break; + case (nn::hac::nacp::LANG_Spanish): + str = "Spanish"; + break; + case (nn::hac::nacp::LANG_Italian): + str = "Italian"; + break; + case (nn::hac::nacp::LANG_Dutch): + str = "Dutch"; + break; + case (nn::hac::nacp::LANG_CanadianFrench): + str = "CanadianFrench"; + break; + case (nn::hac::nacp::LANG_Portuguese): + str = "Portuguese"; + break; + case (nn::hac::nacp::LANG_Russian): + str = "Russian"; + break; + case (nn::hac::nacp::LANG_Korean): + str = "Korean"; + break; + case (nn::hac::nacp::LANG_TraditionalChinese): + str = "TraditionalChinese"; + break; + case (nn::hac::nacp::LANG_SimplifiedChinese): + str = "SimplifiedChinese"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::USER_None): + str = "None"; + break; + case (nn::hac::nacp::USER_Required): + str = "Required"; + break; + case (nn::hac::nacp::USER_RequiredWithNetworkServiceAccountAvailable): + str = "RequiredWithNetworkServiceAccountAvailable"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::TOUCH_None): + str = "None"; + break; + case (nn::hac::nacp::TOUCH_Supported): + str = "Supported"; + break; + case (nn::hac::nacp::TOUCH_Required): + str = "Required"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::AOC_AllOnLaunch): + str = "AllOnLaunch"; + break; + case (nn::hac::nacp::AOC_OnDemand): + str = "OnDemand"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::ATTR_None): + str = "None"; + break; + case (nn::hac::nacp::ATTR_Demo): + str = "Demo"; + break; + case (nn::hac::nacp::ATTR_RetailInteractiveDisplay): + str = "RetailInteractiveDisplay"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::PC_None): + str = "None"; + break; + case (nn::hac::nacp::PC_FreeCommunication): + str = "FreeCommunication"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::SCRN_Allow): + str = "Allow"; + break; + case (nn::hac::nacp::SCRN_Deny): + str = "Deny"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::VCAP_Disable): + str = "Disable"; + break; + case (nn::hac::nacp::VCAP_Manual): + str = "Manual"; + break; + case (nn::hac::nacp::VCAP_Enable): + str = "Enable"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::DLOSS_None): + str = "None"; + break; + case (nn::hac::nacp::DLOSS_Required): + str = "Required"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::PLP_All): + str = "All"; + break; + case (nn::hac::nacp::PLP_LogOnly): + str = "LogOnly"; + break; + case (nn::hac::nacp::PLP_None): + str = "None"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getOrganisationStr(nn::hac::nacp::Organisation var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::ORGN_CERO): + str = "CERO"; + break; + case (nn::hac::nacp::ORGN_GRACGCRB): + str = "GRACGCRB"; + break; + case (nn::hac::nacp::ORGN_GSRMR): + str = "GSRMR"; + break; + case (nn::hac::nacp::ORGN_ESRB): + str = "ESRB"; + break; + case (nn::hac::nacp::ORGN_ClassInd): + str = "ClassInd"; + break; + case (nn::hac::nacp::ORGN_USK): + str = "USK"; + break; + case (nn::hac::nacp::ORGN_PEGI): + str = "PEGI"; + break; + case (nn::hac::nacp::ORGN_PEGIPortugal): + str = "PEGIPortugal"; + break; + case (nn::hac::nacp::ORGN_PEGIBBFC): + str = "PEGIBBFC"; + break; + case (nn::hac::nacp::ORGN_Russian): + str = "Russian"; + break; + case (nn::hac::nacp::ORGN_ACB): + str = "ACB"; + break; + case (nn::hac::nacp::ORGN_OFLC): + str = "OFLC"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getLogoTypeStr(nn::hac::nacp::LogoType var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::LOGO_LicensedByNintendo): + str = "LicensedByNintendo"; + break; + case (nn::hac::nacp::LOGO_DistributedByNintendo): + str = "DistributedByNintendo"; + break; + case (nn::hac::nacp::LOGO_Nintendo): + str = "Nintendo"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::LHND_Auto): + str = "Auto"; + break; + case (nn::hac::nacp::LHND_None): + str = "None"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::RTAOC_Deny): + str = "Deny"; + break; + case (nn::hac::nacp::RTAOC_AllowAppend): + str = "AllowAppend"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::CREP_Deny): + str = "Deny"; + break; + case (nn::hac::nacp::CREP_Allow): + str = "Allow"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getHdcpStr(nn::hac::nacp::Hdcp var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::HDCP_None): + str = "None"; + break; + case (nn::hac::nacp::HDCP_Required): + str = "Required"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::PLQC_None): + str = "None"; + break; + case (nn::hac::nacp::PLQC_Whitelist): + str = "Whitelist"; + break; + case (nn::hac::nacp::PLQC_All): + str = "All"; + break; + default: + str = "Unknown"; + } + + return str; +} + +const char* NacpProcess::getRepairFlagStr(nn::hac::nacp::RepairFlag var) const +{ + const char* str = nullptr; + + switch(var) + { + case (nn::hac::nacp::REPF_None): + str = "None"; + break; + case (nn::hac::nacp::REPF_SuppressGameCardAccess): + str = "SuppressGameCardAccess"; + break; + default: + str = "Unknown"; + } + + return str; +} + +std::string NacpProcess::getSaveDataSizeStr(int64_t size) const +{ + static const int64_t kKiloByte = 1024; + static const int64_t kMegaByte = 1024 * 1024; + + std::stringstream sstr; + + + if (size < kKiloByte) + { + sstr << size << " B"; + } + else if (size < kMegaByte) + { + sstr << (size/kKiloByte) << " KB"; + } + else + { + sstr << (size/kMegaByte) << " MB"; + } + + return sstr.str(); +} \ No newline at end of file diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h index 7511d79..ec844be 100644 --- a/programs/nstool/source/NacpProcess.h +++ b/programs/nstool/source/NacpProcess.h @@ -31,4 +31,23 @@ private: nn::hac::ApplicationControlPropertyBinary mNacp; void displayNacp(); + const char* getLanguageStr(nn::hac::nacp::Language var) const; + const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const; + const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const; + const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const; + const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const; + const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const; + const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const; + const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const; + const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const; + const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const; + const char* getOrganisationStr(nn::hac::nacp::Organisation var) const; + const char* getLogoTypeStr(nn::hac::nacp::LogoType var) const; + const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const; + const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const; + const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const; + const char* getHdcpStr(nn::hac::nacp::Hdcp var) const; + const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const; + const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var) const; + std::string getSaveDataSizeStr(int64_t size) const; }; \ No newline at end of file From 20285b3303972e045300d612c60771ffa41977e0 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:23:39 +0800 Subject: [PATCH 06/50] [nstool] Improved NcaProcess str resource management. --- programs/nstool/source/NcaProcess.cpp | 435 +++++++++++++------------- programs/nstool/source/NcaProcess.h | 10 + 2 files changed, 236 insertions(+), 209 deletions(-) diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index bfc9f3f..1e71c85 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -11,215 +11,6 @@ #include "AesCtrWrappedIFile.h" #include "HashTreeWrappedIFile.h" -const char* getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) -{ - const char* str; - switch (format_ver) - { - case (nn::hac::NcaHeader::NCA2_FORMAT): - str = "NCA2"; - break; - case (nn::hac::NcaHeader::NCA3_FORMAT): - str = "NCA3"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -const char* getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) -{ - const char* str; - switch (dist_type) - { - case (nn::hac::nca::DIST_DOWNLOAD): - str = "Download"; - break; - case (nn::hac::nca::DIST_GAME_CARD): - str = "Game Card"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - - - const char* getContentTypeStr(nn::hac::nca::ContentType cont_type) -{ - const char* str; - switch (cont_type) - { - case (nn::hac::nca::TYPE_PROGRAM): - str = "Program"; - break; - case (nn::hac::nca::TYPE_META): - str = "Meta"; - break; - case (nn::hac::nca::TYPE_CONTROL): - str = "Control"; - break; - case (nn::hac::nca::TYPE_MANUAL): - str = "Manual"; - break; - case (nn::hac::nca::TYPE_DATA): - str = "Data"; - break; - case (nn::hac::nca::TYPE_PUBLIC_DATA): - str = "PublicData"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -const char* getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) -{ - const char* str; - switch (enc_type) - { - case (nn::hac::nca::CRYPT_AUTO): - str = "Auto"; - break; - case (nn::hac::nca::CRYPT_NONE): - str = "None"; - break; - case (nn::hac::nca::CRYPT_AESXTS): - str = "AesXts"; - break; - case (nn::hac::nca::CRYPT_AESCTR): - str = "AesCtr"; - break; - case (nn::hac::nca::CRYPT_AESCTREX): - str = "AesCtrEx"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getHashTypeStr(nn::hac::nca::HashType hash_type) -{ - const char* str; - switch (hash_type) - { - case (nn::hac::nca::HASH_AUTO): - str = "Auto"; - break; - case (nn::hac::nca::HASH_NONE): - str = "None"; - break; - case (nn::hac::nca::HASH_HIERARCHICAL_SHA256): - str = "HierarchicalSha256"; - break; - case (nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY): - str = "HierarchicalIntegrity"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getFormatTypeStr(nn::hac::nca::FormatType format_type) -{ - const char* str; - switch (format_type) - { - case (nn::hac::nca::FORMAT_ROMFS): - str = "RomFs"; - break; - case (nn::hac::nca::FORMAT_PFS0): - str = "PartitionFs"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) -{ - const char* str; - switch (keak_index) - { - case (nn::hac::nca::KAEK_IDX_APPLICATION): - str = "Application"; - break; - case (nn::hac::nca::KAEK_IDX_OCEAN): - str = "Ocean"; - break; - case (nn::hac::nca::KAEK_IDX_SYSTEM): - str = "System"; - break; - default: - str = "Unknown"; - break; - } - return str; -} - -inline const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) -{ - const char* str; - switch (cont_type) - { - case (nn::hac::nca::TYPE_PROGRAM): - str = "program"; - break; - case (nn::hac::nca::TYPE_META): - str = "meta"; - break; - case (nn::hac::nca::TYPE_CONTROL): - str = "control"; - break; - case (nn::hac::nca::TYPE_MANUAL): - str = "manual"; - break; - case (nn::hac::nca::TYPE_DATA): - str = "data"; - break; - case (nn::hac::nca::TYPE_PUBLIC_DATA): - str = "publicData"; - break; - default: - str = ""; - break; - } - return str; -} - -const char* getProgramPartitionNameStr(size_t i) -{ - const char* str; - switch (i) - { - case (nn::hac::nca::PARTITION_CODE): - str = "code"; - break; - case (nn::hac::nca::PARTITION_DATA): - str = "data"; - break; - case (nn::hac::nca::PARTITION_LOGO): - str = "logo"; - break; - default: - str = ""; - break; - } - return str; -} - - NcaProcess::NcaProcess() : mFile(nullptr), mOwnIFile(false), @@ -806,3 +597,229 @@ void NcaProcess::processPartitions() } } } + +const char* NcaProcess::getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) const +{ + const char* str = nullptr; + + switch (format_ver) + { + case (nn::hac::NcaHeader::NCA2_FORMAT): + str = "NCA2"; + break; + case (nn::hac::NcaHeader::NCA3_FORMAT): + str = "NCA3"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) const +{ + const char* str = nullptr; + + switch (dist_type) + { + case (nn::hac::nca::DIST_DOWNLOAD): + str = "Download"; + break; + case (nn::hac::nca::DIST_GAME_CARD): + str = "Game Card"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + + +const char* NcaProcess::getContentTypeStr(nn::hac::nca::ContentType cont_type) const +{ + const char* str = nullptr; + + switch (cont_type) + { + case (nn::hac::nca::TYPE_PROGRAM): + str = "Program"; + break; + case (nn::hac::nca::TYPE_META): + str = "Meta"; + break; + case (nn::hac::nca::TYPE_CONTROL): + str = "Control"; + break; + case (nn::hac::nca::TYPE_MANUAL): + str = "Manual"; + break; + case (nn::hac::nca::TYPE_DATA): + str = "Data"; + break; + case (nn::hac::nca::TYPE_PUBLIC_DATA): + str = "PublicData"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) const +{ + const char* str = nullptr; + + switch (enc_type) + { + case (nn::hac::nca::CRYPT_AUTO): + str = "Auto"; + break; + case (nn::hac::nca::CRYPT_NONE): + str = "None"; + break; + case (nn::hac::nca::CRYPT_AESXTS): + str = "AesXts"; + break; + case (nn::hac::nca::CRYPT_AESCTR): + str = "AesCtr"; + break; + case (nn::hac::nca::CRYPT_AESCTREX): + str = "AesCtrEx"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getHashTypeStr(nn::hac::nca::HashType hash_type) const +{ + const char* str = nullptr; + + switch (hash_type) + { + case (nn::hac::nca::HASH_AUTO): + str = "Auto"; + break; + case (nn::hac::nca::HASH_NONE): + str = "None"; + break; + case (nn::hac::nca::HASH_HIERARCHICAL_SHA256): + str = "HierarchicalSha256"; + break; + case (nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY): + str = "HierarchicalIntegrity"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getFormatTypeStr(nn::hac::nca::FormatType format_type) const +{ + const char* str = nullptr; + + switch (format_type) + { + case (nn::hac::nca::FORMAT_ROMFS): + str = "RomFs"; + break; + case (nn::hac::nca::FORMAT_PFS0): + str = "PartitionFs"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) const +{ + const char* str = nullptr; + + switch (keak_index) + { + case (nn::hac::nca::KAEK_IDX_APPLICATION): + str = "Application"; + break; + case (nn::hac::nca::KAEK_IDX_OCEAN): + str = "Ocean"; + break; + case (nn::hac::nca::KAEK_IDX_SYSTEM): + str = "System"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const +{ + const char* str = nullptr; + + switch (cont_type) + { + case (nn::hac::nca::TYPE_PROGRAM): + str = "program"; + break; + case (nn::hac::nca::TYPE_META): + str = "meta"; + break; + case (nn::hac::nca::TYPE_CONTROL): + str = "control"; + break; + case (nn::hac::nca::TYPE_MANUAL): + str = "manual"; + break; + case (nn::hac::nca::TYPE_DATA): + str = "data"; + break; + case (nn::hac::nca::TYPE_PUBLIC_DATA): + str = "publicData"; + break; + default: + str = ""; + break; + } + + return str; +} + +const char* NcaProcess::getProgramPartitionNameStr(size_t i) const +{ + const char* str = nullptr; + + switch (i) + { + case (nn::hac::nca::PARTITION_CODE): + str = "code"; + break; + case (nn::hac::nca::PARTITION_DATA): + str = "data"; + break; + case (nn::hac::nca::PARTITION_LOGO): + str = "logo"; + break; + default: + str = ""; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index e21ded8..49c6d57 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -110,4 +110,14 @@ private: void validateNcaSignatures(); void displayHeader(); void processPartitions(); + + const char* getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) const; + const char* getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) const; + const char* getContentTypeStr(nn::hac::nca::ContentType cont_type) const; + const char* getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) const; + const char* getHashTypeStr(nn::hac::nca::HashType hash_type) const; + const char* getFormatTypeStr(nn::hac::nca::FormatType format_type) const; + const char* getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) const; + const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const; + const char* getProgramPartitionNameStr(size_t i) const; }; \ No newline at end of file From 7a0c22666c0787f4f675c4dbe9400ed5a1775a74 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:23:57 +0800 Subject: [PATCH 07/50] [nstool] Cleaned up some formatting in XciProcess --- programs/nstool/source/XciProcess.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index 230b1b9..41dcf19 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -120,7 +120,7 @@ void XciProcess::displayHeader() } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Enc Header AES-IV:\n"); + printf(" Extended Header AES-IV:\n"); fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4); } printf(" SelSec: 0x%x\n", mHdr.getSelSec()); @@ -240,7 +240,8 @@ void XciProcess::processPartitionPfs() const char* XciProcess::getRomSizeStr(byte_t rom_size) const { - const char* str = "unknown"; + const char* str = nullptr; + switch (rom_size) { case (nn::hac::xci::ROM_SIZE_1GB): @@ -261,13 +262,18 @@ const char* XciProcess::getRomSizeStr(byte_t rom_size) const case (nn::hac::xci::ROM_SIZE_32GB): str = "32GB"; break; + default: + str = "Unknown"; + break; } + return str; } const char* XciProcess::getHeaderFlagStr(byte_t flag) const { - const char* str = "unknown"; + const char* str = nullptr; + switch (flag) { case (nn::hac::xci::FLAG_AUTOBOOT): @@ -279,14 +285,19 @@ const char* XciProcess::getHeaderFlagStr(byte_t flag) const case (nn::hac::xci::FLAG_REPAIR_TOOL): str = "RepairTool"; break; + default: + str = "Unknown"; + break; } + return str; } const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const { - const char* str = "unknown"; + const char* str = nullptr; + switch (acc_ctrl_1) { case (nn::hac::xci::CLOCK_RATE_25): @@ -295,7 +306,10 @@ const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const case (nn::hac::xci::CLOCK_RATE_50): str = "50 MHz"; break; - + default: + str = "Unknown"; + break; } + return str; } From 3ad02fb5ccb6a9636b1c28e447b09af852f1f97a Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 12 Aug 2018 13:24:34 +0800 Subject: [PATCH 08/50] [nstool] Cleaned up NpdmProcess string resource management --- programs/nstool/source/NpdmProcess.cpp | 905 +++++++++++++++++-------- programs/nstool/source/NpdmProcess.h | 10 + 2 files changed, 648 insertions(+), 267 deletions(-) diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index 6a7f977..f0ab4eb 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -85,257 +85,6 @@ const nn::hac::NpdmBinary& NpdmProcess::getNpdmBinary() const return mNpdm; } -const std::string kInstructionType[2] = { "32Bit", "64Bit" }; -const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" }; -const std::string kAcidFlag[32] = -{ - "Production", - "UnqualifiedApproval", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown" -}; -const std::string kMiscFlag[15] = { "EnableDebug", "ForceDebug", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7", "bit8", "bit9", "bit10", "bit11", "bit12", "bit13", "bit14"}; -const std::string kFsaFlag[64] = -{ - "ApplicationInfo", - "BootModeControl", - "Calibration", - "SystemSaveData", - "GameCard", - "SaveDataBackUp", - "SaveDataManagement", - "BisAllRaw", - "GameCardRaw", - "GameCardPrivate", - "SetTime", - "ContentManager", - "ImageManager", - "CreateSaveData", - "SystemSaveDataManagement", - "BisFileSystem", - "SystemUpdate", - "SaveDataMeta", - "DeviceSaveData", - "SettingsControl", - "Bit20", - "Bit21", - "Bit22", - "Bit23", - "Bit24", - "Bit25", - "Bit26", - "Bit27", - "Bit28", - "Bit29", - "Bit30", - "Bit31", - "Bit32", - "Bit33", - "Bit34", - "Bit35", - "Bit36", - "Bit37", - "Bit38", - "Bit39", - "Bit40", - "Bit41", - "Bit42", - "Bit43", - "Bit44", - "Bit45", - "Bit46", - "Bit47", - "Bit48", - "Bit49", - "Bit50", - "Bit51", - "Bit52", - "Bit53", - "Bit54", - "Bit55", - "Bit56", - "Bit57", - "Bit58", - "Bit59", - "Bit60", - "Bit61", - "Debug", - "FullPermission" -}; - -const std::string kSaveDataOwnerAccessMode[4] = -{ - "IllegalAccessCondition", - "Read", - "Write", - "ReadWrite" -}; - -const std::string kSysCall[0x80] = -{ - "svc00", - "SetHeapSize", - "SetMemoryPermission", - "SetMemoryAttribute", - "MapMemory", - "UnmapMemory", - "QueryMemory", - "ExitProcess", - "CreateThread", - "StartThread", - "ExitThread", - "SleepThread", - "GetThreadPriority", - "SetThreadPriority", - "GetThreadCoreMask", - "SetThreadCoreMask", - "GetCurrentProcessorNumber", - "SignalEvent", - "ClearEvent", - "MapSharedMemory", - "UnmapSharedMemory", - "CreateTransferMemory", - "CloseHandle", - "ResetSignal", - "WaitSynchronization", - "CancelSynchronization", - "ArbitrateLock", - "ArbitrateUnlock", - "WaitProcessWideKeyAtomic", - "SignalProcessWideKey", - "GetSystemTick", - "ConnectToNamedPort", - "SendSyncRequestLight", - "SendSyncRequest", - "SendSyncRequestWithUserBuffer", - "SendAsyncRequestWithUserBuffer", - "GetProcessId", - "GetThreadId", - "Break", - "OutputDebugString", - "ReturnFromException", - "GetInfo", - "FlushEntireDataCache", - "FlushDataCache", - "MapPhysicalMemory", - "UnmapPhysicalMemory", - "svc2E", - "GetLastThreadInfo", - "GetResourceLimitLimitValue", - "GetResourceLimitCurrentValue", - "SetThreadActivity", - "GetThreadContext3", - "svc34", - "svc35", - "svc36", - "svc37", - "svc38", - "svc39", - "svc3A", - "svc3B", - "DumpInfo", - "svc3D", - "svc3E", - "svc3F", - "CreateSession", - "AcceptSession", - "ReplyAndReceiveLight", - "ReplyAndReceive", - "ReplyAndReceiveWithUserBuffer", - "CreateEvent", - "svc46", - "svc47", - "svc48", - "svc49", - "svc4A", - "svc4B", - "svc4C", - "SleepSystem", - "ReadWriteRegister", - "SetProcessActivity", - "CreateSharedMemory", - "MapTransferMemory", - "UnmapTransferMemory", - "CreateInterruptEvent", - "QueryPhysicalAddress", - "QueryIoMapping", - "CreateDeviceAddressSpace", - "AttachDeviceAddressSpace", - "DetachDeviceAddressSpace", - "MapDeviceAddressSpaceByForce", - "MapDeviceAddressSpaceAligned", - "MapDeviceAddressSpace", - "UnmapDeviceAddressSpace", - "InvalidateProcessDataCache", - "StoreProcessDataCache", - "FlushProcessDataCache", - "DebugActiveProcess", - "BreakDebugProcess", - "TerminateDebugProcess", - "GetDebugEvent", - "ContinueDebugEvent", - "GetProcessList", - "GetThreadList", - "GetDebugThreadContext", - "SetDebugThreadContext", - "QueryDebugProcessMemory", - "ReadDebugProcessMemory", - "WriteDebugProcessMemory", - "SetHardwareBreakPoint", - "GetDebugThreadParam", - "svc6E", - "svc6F", - "CreatePort", - "ManageNamedPort", - "ConnectToPort", - "SetProcessMemoryPermission", - "MapProcessMemory", - "UnmapProcessMemory", - "QueryProcessMemory", - "MapProcessCodeMemory", - "UnmapProcessCodeMemory", - "CreateProcess", - "StartProcess", - "TerminateProcess", - "GetProcessInfo", - "CreateResourceLimit", - "SetResourceLimitLimitValue", - "CallSecureMonitor" -}; - -const std::string kMemMapPerm[2] = { "RW", "RO" }; -const std::string kMemMapType[2] = { "Io", "Static" }; - -const std::string kAcidTarget[2] = { "Development", "Production" }; - void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid) { try { @@ -371,7 +120,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (fsaRightFound == false) { - printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFileSystemAccessControl().getFsaRightsList()[i]].c_str()); + printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i])); } } @@ -403,7 +152,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 "(%d) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type); + printf("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (%016" PRIx64 "(%d) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type); } } @@ -453,7 +202,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]].c_str()); + printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i])); } } // check memory maps @@ -470,7 +219,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac { const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i]; - printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); + printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, getMemMapPermStr(map.perm), getMemMapTypeStr(map.type)); } } for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++) @@ -486,7 +235,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac { const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i]; - printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); + printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, getMemMapPermStr(map.perm), getMemMapTypeStr(map.type)); } } // check interupts @@ -533,7 +282,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]].c_str()); + printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i])); } } } @@ -542,8 +291,8 @@ void NpdmProcess::displayNpdmHeader(const nn::hac::NpdmBinary& hdr) { printf("[NPDM HEADER]\n"); printf(" Process Architecture Params:\n"); - printf(" Ins. Type: %s\n", kInstructionType[hdr.getInstructionType()].c_str()); - printf(" Addr Space: %s\n", kProcAddrSpace[hdr.getProcAddressSpaceType()].c_str()); + printf(" Ins. Type: %s\n", getInstructionTypeStr(hdr.getInstructionType())); + printf(" Addr Space: %s\n", getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType())); printf(" Main Thread Params:\n"); printf(" Priority: %d\n", hdr.getMainThreadPriority()); printf(" CpuId: %d\n", hdr.getMainThreadCpuId()); @@ -571,7 +320,7 @@ void NpdmProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDescBinary& printf(" Flags: \n"); for (size_t i = 0; i < acid.getFlagList().size(); i++) { - printf(" %s (%d)\n", kAcidFlag[acid.getFlagList()[i]].c_str(), acid.getFlagList()[i]); + printf(" %s (%d)\n", getAcidFlagStr(acid.getFlagList()[i]), acid.getFlagList()[i]); } } printf(" ProgramID Restriction\n"); @@ -593,7 +342,7 @@ void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) { printf("%s ", i != 0 ? "\n" : ""); } - printf("%s", kFsaFlag[fac.getFsaRightsList()[i]].c_str()); + printf("%s", getFsaRightStr(fac.getFsaRightsList()[i])); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) printf(" (bit %" PRId32 ")", fac.getFsaRightsList()[i]); printf("%s", fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack() ? ", " : "\n"); @@ -614,7 +363,7 @@ void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) printf(" Save Data Owner IDs:\n"); for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++) { - printf(" 0x%016" PRIx64 " (%s)\n", fac.getSaveDataOwnerIdList()[i].id, kSaveDataOwnerAccessMode[fac.getSaveDataOwnerIdList()[i].access_type].c_str()); + printf(" 0x%016" PRIx64 " (%s)\n", fac.getSaveDataOwnerIdList()[i].id, getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type)); } } @@ -647,6 +396,7 @@ void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) printf(" Min: %d\n", threadInfo.getMinCpuId()); printf(" Max: %d\n", threadInfo.getMaxCpuId()); } + if (kern.getSystemCalls().isSet()) { fnd::List syscalls = kern.getSystemCalls().getSystemCalls(); @@ -660,8 +410,8 @@ void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) lineLen = 0; printf("\n "); } - printf("%s%s", kSysCall[syscalls[i]].c_str(), syscalls[i] != syscalls.atBack() ? ", " : "\n"); - lineLen += kSysCall[syscalls[i]].length(); + printf("%s%s", getSystemCallStr(syscalls[i]), syscalls[i] != syscalls.atBack() ? ", " : "\n"); + lineLen += strlen(getSystemCallStr(syscalls[i])); } } if (kern.getMemoryMaps().isSet()) @@ -672,12 +422,12 @@ void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) printf(" MemoryMaps:\n"); for (size_t i = 0; i < maps.size(); i++) { - printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)maps[i].addr << 12, ((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1, kMemMapPerm[maps[i].perm].c_str(), kMemMapType[maps[i].type].c_str()); + printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)maps[i].addr << 12, ((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1, getMemMapPermStr(maps[i].perm), getMemMapTypeStr(maps[i].type)); } //printf(" IoMaps:\n"); for (size_t i = 0; i < ioMaps.size(); i++) { - printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)ioMaps[i].addr << 12, ((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1, kMemMapPerm[ioMaps[i].perm].c_str(), kMemMapType[ioMaps[i].type].c_str()); + printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)ioMaps[i].addr << 12, ((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1, getMemMapPermStr(ioMaps[i].perm), getMemMapTypeStr(ioMaps[i].type)); } } if (kern.getInterupts().isSet()) @@ -716,7 +466,628 @@ void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) { printf("%s ", i != 0 ? "\n" : ""); } - printf("%s%s", kMiscFlag[flagList[i]].c_str(), flagList[i] != flagList.atBack() ? ", " : "\n"); + printf("%s%s", getMiscFlagStr(flagList[i]), flagList[i] != flagList.atBack() ? ", " : "\n"); } } } + +const char* NpdmProcess::getInstructionTypeStr(nn::hac::npdm::InstructionType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::npdm::INSTR_32BIT): + str = "32Bit"; + break; + case (nn::hac::npdm::INSTR_64BIT): + str = "64Bit"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getProcAddressSpaceTypeStr(nn::hac::npdm::ProcAddrSpaceType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::npdm::ADDR_SPACE_64BIT): + str = "64Bit"; + break; + case (nn::hac::npdm::ADDR_SPACE_32BIT): + str = "32Bit"; + break; + case (nn::hac::npdm::ADDR_SPACE_32BIT_NO_RESERVED): + str = "32Bit no reserved"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getAcidFlagStr(nn::hac::aci::Flag flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::aci::FLAG_PRODUCTION): + str = "Production"; + break; + case (nn::hac::aci::FLAG_UNQUALIFIED_APPROVAL): + str = "UnqualifiedApproval"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::MiscFlagsHandler::FLAG_ENABLE_DEBUG): + str = "EnableDebug"; + break; + case (nn::hac::MiscFlagsHandler::FLAG_FORCE_DEBUG): + str = "ForceDebug"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getFsaRightStr(nn::hac::fac::FsAccessFlag flag) const +{ + const char* str = nullptr; + + switch(flag) + { + case (nn::hac::fac::FSA_APPLICATION_INFO): + str = "ApplicationInfo"; + break; + case (nn::hac::fac::FSA_BOOT_MODE_CONTROL): + str = "BootModeControl"; + break; + case (nn::hac::fac::FSA_CALIBRATION): + str = "Calibration"; + break; + case (nn::hac::fac::FSA_SYSTEM_SAVE_DATA): + str = "SystemSaveData"; + break; + case (nn::hac::fac::FSA_GAME_CARD): + str = "GameCard"; + break; + case (nn::hac::fac::FSA_SAVE_DATA_BACKUP): + str = "SaveDataBackUp"; + break; + case (nn::hac::fac::FSA_SAVE_DATA_MANAGEMENT): + str = "SaveDataManagement"; + break; + case (nn::hac::fac::FSA_BIS_ALL_RAW): + str = "BisAllRaw"; + break; + case (nn::hac::fac::FSA_GAME_CARD_RAW): + str = "GameCardRaw"; + break; + case (nn::hac::fac::FSA_GAME_CARD_PRIVATE): + str = "GameCardPrivate"; + break; + case (nn::hac::fac::FSA_SET_TIME): + str = "SetTime"; + break; + case (nn::hac::fac::FSA_CONTENT_MANAGER): + str = "ContentManager"; + break; + case (nn::hac::fac::FSA_IMAGE_MANAGER): + str = "ImageManager"; + break; + case (nn::hac::fac::FSA_CREATE_SAVE_DATA): + str = "CreateSaveData"; + break; + case (nn::hac::fac::FSA_SYSTEM_SAVE_DATA_MANAGEMENT): + str = "SystemSaveDataManagement"; + break; + case (nn::hac::fac::FSA_BIS_FILE_SYSTEM): + str = "BisFileSystem"; + break; + case (nn::hac::fac::FSA_SYSTEM_UPDATE): + str = "SystemUpdate"; + break; + case (nn::hac::fac::FSA_SAVE_DATA_META): + str = "SaveDataMeta"; + break; + case (nn::hac::fac::FSA_DEVICE_SAVE_CONTROL): + str = "DeviceSaveData"; + break; + case (nn::hac::fac::FSA_SETTINGS_CONTROL): + str = "SettingsControl"; + break; + case (nn::hac::fac::FSA_DEBUG): + str = "Debug"; + break; + case (nn::hac::fac::FSA_FULL_PERMISSION): + str = "FullPermission"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getSaveDataOwnerAccessModeStr(nn::hac::fac::SaveDataOwnerIdAccessType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::fac::SDO_READ): + str = "Read"; + break; + case (nn::hac::fac::SDO_WRITE): + str = "Write"; + break; + case (nn::hac::fac::SDO_READWRITE): + str = "ReadWrite"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getSystemCallStr(byte_t syscall_id) const +{ + const char* str = nullptr; + + switch(syscall_id) + { + case (0x01): + str = "SetHeapSize"; + break; + case (0x02): + str = "SetMemoryPermission"; + break; + case (0x03): + str = "SetMemoryAttribute"; + break; + case (0x04): + str = "MapMemory"; + break; + case (0x05): + str = "UnmapMemory"; + break; + case (0x06): + str = "QueryMemory"; + break; + case (0x07): + str = "ExitProcess"; + break; + case (0x08): + str = "CreateThread"; + break; + case (0x09): + str = "StartThread"; + break; + case (0x0a): + str = "ExitThread"; + break; + case (0x0b): + str = "SleepThread"; + break; + case (0x0c): + str = "GetThreadPriority"; + break; + case (0x0d): + str = "SetThreadPriority"; + break; + case (0x0e): + str = "GetThreadCoreMask"; + break; + case (0x0f): + str = "SetThreadCoreMask"; + break; + case (0x10): + str = "GetCurrentProcessorNumber"; + break; + case (0x11): + str = "SignalEvent"; + break; + case (0x12): + str = "ClearEvent"; + break; + case (0x13): + str = "MapSharedMemory"; + break; + case (0x14): + str = "UnmapSharedMemory"; + break; + case (0x15): + str = "CreateTransferMemory"; + break; + case (0x16): + str = "CloseHandle"; + break; + case (0x17): + str = "ResetSignal"; + break; + case (0x18): + str = "WaitSynchronization"; + break; + case (0x19): + str = "CancelSynchronization"; + break; + case (0x1a): + str = "ArbitrateLock"; + break; + case (0x1b): + str = "ArbitrateUnlock"; + break; + case (0x1c): + str = "WaitProcessWideKeyAtomic"; + break; + case (0x1d): + str = "SignalProcessWideKey"; + break; + case (0x1e): + str = "GetSystemTick"; + break; + case (0x1f): + str = "ConnectToNamedPort"; + break; + case (0x20): + str = "SendSyncRequestLight"; + break; + case (0x21): + str = "SendSyncRequest"; + break; + case (0x22): + str = "SendSyncRequestWithUserBuffer"; + break; + case (0x23): + str = "SendAsyncRequestWithUserBuffer"; + break; + case (0x24): + str = "GetProcessId"; + break; + case (0x25): + str = "GetThreadId"; + break; + case (0x26): + str = "Break"; + break; + case (0x27): + str = "OutputDebugString"; + break; + case (0x28): + str = "ReturnFromException"; + break; + case (0x29): + str = "GetInfo"; + break; + case (0x2a): + str = "FlushEntireDataCache"; + break; + case (0x2b): + str = "FlushDataCache"; + break; + case (0x2c): + str = "MapPhysicalMemory"; + break; + case (0x2d): + str = "UnmapPhysicalMemory"; + break; + case (0x2e): + str = "GetFutureThreadInfo"; + break; + case (0x2f): + str = "GetLastThreadInfo"; + break; + case (0x30): + str = "GetResourceLimitLimitValue"; + break; + case (0x31): + str = "GetResourceLimitCurrentValue"; + break; + case (0x32): + str = "SetThreadActivity"; + break; + case (0x33): + str = "GetThreadContext3"; + break; + case (0x34): + str = "WaitForAddress"; + break; + case (0x35): + str = "SignalToAddress"; + break; + case (0x36): + str = "svc36"; + break; + case (0x37): + str = "svc37"; + break; + case (0x38): + str = "svc38"; + break; + case (0x39): + str = "svc39"; + break; + case (0x3a): + str = "svc3A"; + break; + case (0x3b): + str = "svc3B"; + break; + case (0x3c): + str = "DumpInfo"; + break; + case (0x3d): + str = "DumpInfoNew"; + break; + case (0x3e): + str = "svc3E"; + break; + case (0x3f): + str = "svc3F"; + break; + case (0x40): + str = "CreateSession"; + break; + case (0x41): + str = "AcceptSession"; + break; + case (0x42): + str = "ReplyAndReceiveLight"; + break; + case (0x43): + str = "ReplyAndReceive"; + break; + case (0x44): + str = "ReplyAndReceiveWithUserBuffer"; + break; + case (0x45): + str = "CreateEvent"; + break; + case (0x46): + str = "svc46"; + break; + case (0x47): + str = "svc47"; + break; + case (0x48): + str = "MapPhysicalMemoryUnsafe"; + break; + case (0x49): + str = "UnmapPhysicalMemoryUnsafe"; + break; + case (0x4a): + str = "SetUnsafeLimit"; + break; + case (0x4b): + str = "CreateCodeMemory"; + break; + case (0x4c): + str = "ControlCodeMemory"; + break; + case (0x4d): + str = "SleepSystem"; + break; + case (0x4e): + str = "ReadWriteRegister"; + break; + case (0x4f): + str = "SetProcessActivity"; + break; + case (0x50): + str = "CreateSharedMemory"; + break; + case (0x51): + str = "MapTransferMemory"; + break; + case (0x52): + str = "UnmapTransferMemory"; + break; + case (0x53): + str = "CreateInterruptEvent"; + break; + case (0x54): + str = "QueryPhysicalAddress"; + break; + case (0x55): + str = "QueryIoMapping"; + break; + case (0x56): + str = "CreateDeviceAddressSpace"; + break; + case (0x57): + str = "AttachDeviceAddressSpace"; + break; + case (0x58): + str = "DetachDeviceAddressSpace"; + break; + case (0x59): + str = "MapDeviceAddressSpaceByForce"; + break; + case (0x5a): + str = "MapDeviceAddressSpaceAligned"; + break; + case (0x5b): + str = "MapDeviceAddressSpace"; + break; + case (0x5c): + str = "UnmapDeviceAddressSpace"; + break; + case (0x5d): + str = "InvalidateProcessDataCache"; + break; + case (0x5e): + str = "StoreProcessDataCache"; + break; + case (0x5f): + str = "FlushProcessDataCache"; + break; + case (0x60): + str = "DebugActiveProcess"; + break; + case (0x61): + str = "BreakDebugProcess"; + break; + case (0x62): + str = "TerminateDebugProcess"; + break; + case (0x63): + str = "GetDebugEvent"; + break; + case (0x64): + str = "ContinueDebugEvent"; + break; + case (0x65): + str = "GetProcessList"; + break; + case (0x66): + str = "GetThreadList"; + break; + case (0x67): + str = "GetDebugThreadContext"; + break; + case (0x68): + str = "SetDebugThreadContext"; + break; + case (0x69): + str = "QueryDebugProcessMemory"; + break; + case (0x6a): + str = "ReadDebugProcessMemory"; + break; + case (0x6b): + str = "WriteDebugProcessMemory"; + break; + case (0x6c): + str = "SetHardwareBreakPoint"; + break; + case (0x6d): + str = "GetDebugThreadParam"; + break; + case (0x6e): + str = "svc6E"; + break; + case (0x6f): + str = "GetSystemInfo"; + break; + case (0x70): + str = "CreatePort"; + break; + case (0x71): + str = "ManageNamedPort"; + break; + case (0x72): + str = "ConnectToPort"; + break; + case (0x73): + str = "SetProcessMemoryPermission"; + break; + case (0x74): + str = "MapProcessMemory"; + break; + case (0x75): + str = "UnmapProcessMemory"; + break; + case (0x76): + str = "QueryProcessMemory"; + break; + case (0x77): + str = "MapProcessCodeMemory"; + break; + case (0x78): + str = "UnmapProcessCodeMemory"; + break; + case (0x79): + str = "CreateProcess"; + break; + case (0x7a): + str = "StartProcess"; + break; + case (0x7b): + str = "TerminateProcess"; + break; + case (0x7c): + str = "GetProcessInfo"; + break; + case (0x7d): + str = "CreateResourceLimit"; + break; + case (0x7e): + str = "SetResourceLimitLimitValue"; + break; + case (0x7f): + str = "CallSecureMonitor"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::MemoryMappingHandler::MEM_RW): + str = "RW"; + break; + case (nn::hac::MemoryMappingHandler::MEM_RO): + str = "RO"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} + +const char* NpdmProcess::getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const +{ + const char* str = nullptr; + + switch(type) + { + case (nn::hac::MemoryMappingHandler::MAP_IO): + str = "Io"; + break; + case (nn::hac::MemoryMappingHandler::MAP_STATIC): + str = "Static"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index 6ed8959..9e4fc24 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -41,4 +41,14 @@ private: void displayFac(const nn::hac::FileSystemAccessControlBinary& fac); void displaySac(const nn::hac::ServiceAccessControlBinary& sac); void displayKernelCap(const nn::hac::KernelCapabilityBinary& kern); + + const char* getInstructionTypeStr(nn::hac::npdm::InstructionType type) const; + const char* getProcAddressSpaceTypeStr(nn::hac::npdm::ProcAddrSpaceType type) const; + const char* getAcidFlagStr(nn::hac::aci::Flag flag) const; + const char* getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const; + const char* getFsaRightStr(nn::hac::fac::FsAccessFlag flag) const; + const char* getSaveDataOwnerAccessModeStr(nn::hac::fac::SaveDataOwnerIdAccessType type) const; + const char* getSystemCallStr(byte_t syscall_id) const; + const char* getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const; + const char* getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const; }; \ No newline at end of file From 70cea402e56c84c4ea198c73f86a1eb286becc3d Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 14 Aug 2018 01:14:21 +0800 Subject: [PATCH 09/50] [nstool] Migrated printf to std::cout --- programs/nstool/source/AssetProcess.cpp | 15 +- programs/nstool/source/CnmtProcess.cpp | 37 ++-- programs/nstool/source/CnmtProcess.h | 3 +- programs/nstool/source/EsTikProcess.cpp | 5 +- programs/nstool/source/NacpProcess.cpp | 159 +++++++------- programs/nstool/source/NacpProcess.h | 1 + programs/nstool/source/NcaProcess.cpp | 184 ++++++++-------- programs/nstool/source/NcaProcess.h | 1 + programs/nstool/source/NpdmProcess.cpp | 210 +++++++++++-------- programs/nstool/source/NpdmProcess.h | 2 + programs/nstool/source/NroProcess.cpp | 69 +++--- programs/nstool/source/NsoProcess.cpp | 101 ++++----- programs/nstool/source/PfsProcess.cpp | 105 ++++++---- programs/nstool/source/PfsProcess.h | 3 + programs/nstool/source/PkiCertProcess.cpp | 22 +- programs/nstool/source/PkiValidator.cpp | 2 +- programs/nstool/source/RoMetadataProcess.cpp | 33 +-- programs/nstool/source/RomfsProcess.cpp | 41 ++-- programs/nstool/source/XciProcess.cpp | 141 +++++++------ programs/nstool/source/XciProcess.h | 1 + 20 files changed, 613 insertions(+), 522 deletions(-) diff --git a/programs/nstool/source/AssetProcess.cpp b/programs/nstool/source/AssetProcess.cpp index 7dd8726..0128ee1 100644 --- a/programs/nstool/source/AssetProcess.cpp +++ b/programs/nstool/source/AssetProcess.cpp @@ -1,7 +1,7 @@ -#include -#include #include #include +#include +#include #include "AssetProcess.h" #include "OffsetAdjustedIFile.h" @@ -25,11 +25,6 @@ AssetProcess::~AssetProcess() void AssetProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayHeader(); @@ -76,6 +71,12 @@ void AssetProcess::setRomfsExtractPath(const std::string& path) void AssetProcess::importHeader() { fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + if (mFile->size() < sizeof(nn::hac::sAssetHeader)) { throw fnd::Exception(kModuleName, "Corrupt ASET: file too small"); diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index 7e39b7a..1a8bc0a 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include #include "OffsetAdjustedIFile.h" #include "CnmtProcess.h" @@ -22,20 +22,10 @@ CnmtProcess::~CnmtProcess() void CnmtProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mCnmt.fromBytes(scratch.data(), scratch.size()); + importCnmt(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - displayCmnt(); + displayCnmt(); } void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) @@ -59,7 +49,22 @@ const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const return mCnmt; } -void CnmtProcess::displayCmnt() +void CnmtProcess::importCnmt() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); + + mCnmt.fromBytes(scratch.data(), scratch.size()); +} + +void CnmtProcess::displayCnmt() { #define _SPLIT_VER(ver) (uint32_t)((ver>>26) & 0x3f) << "." << (uint32_t)((ver>>20) & 0x3f) << "." << (uint32_t)((ver>>16) & 0xf) << "." << (uint32_t)(ver & 0xffff) #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) @@ -68,7 +73,7 @@ void CnmtProcess::displayCmnt() std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << std::endl; std::cout << " Version: v" << std::dec << mCnmt.getTitleVersion() << " (" << _SPLIT_VER(mCnmt.getTitleVersion()) << ")"<< std::endl; std::cout << " Type: " << getContentMetaTypeStr(mCnmt.getType()) << " (" << std::dec << mCnmt.getType() << ")" << std::endl; - std::cout << " Attributes: " << std::hex << mCnmt.getAttributes() << std::endl; + std::cout << " Attributes: 0x" << std::hex << (uint32_t)mCnmt.getAttributes() << std::endl; std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl; std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl; std::cout << " RequiredDownloadSystemVersion: v" << mCnmt.getRequiredDownloadSystemVersion() << " (" << _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()) << ")"<< std::endl; @@ -123,7 +128,7 @@ void CnmtProcess::displayCmnt() std::cout << " Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << info.id << std::endl; std::cout << " Version: v" << std::dec << info.version << " (" << _SPLIT_VER(info.version) << ")"<< std::endl; std::cout << " Type: " << getContentMetaTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl; - std::cout << " Attributes: " << std::hex << info.attributes << std::endl; + std::cout << " Attributes: 0x" << std::hex << (uint32_t)info.attributes << std::endl; std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl; std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl; } diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index 7e2f113..83535ba 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -30,7 +30,8 @@ private: nn::hac::ContentMetaBinary mCnmt; - void displayCmnt(); + void importCnmt(); + void displayCnmt(); const char* getBoolStr(bool state) const; const char* getContentTypeStr(nn::hac::cnmt::ContentType type) const; diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp index a16c0f4..5a3801a 100644 --- a/programs/nstool/source/EsTikProcess.cpp +++ b/programs/nstool/source/EsTikProcess.cpp @@ -1,6 +1,5 @@ #include #include - #include #include #include "OffsetAdjustedIFile.h" @@ -64,12 +63,14 @@ void EsTikProcess::setVerifyMode(bool verify) void EsTikProcess::importTicket() { + fnd::Vec scratch; + + if (mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - fnd::Vec scratch; scratch.alloc(mFile->size()); mFile->read(scratch.data(), 0, scratch.size()); mTik.fromBytes(scratch.data(), scratch.size()); diff --git a/programs/nstool/source/NacpProcess.cpp b/programs/nstool/source/NacpProcess.cpp index aa3f83c..fb6d5bf 100644 --- a/programs/nstool/source/NacpProcess.cpp +++ b/programs/nstool/source/NacpProcess.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include "OffsetAdjustedIFile.h" #include "NacpProcess.h" @@ -21,17 +23,7 @@ NacpProcess::~NacpProcess() void NacpProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mNacp.fromBytes(scratch.data(), scratch.size()); + importNacp(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayNacp(); @@ -58,124 +50,139 @@ const nn::hac::ApplicationControlPropertyBinary& NacpProcess::getApplicationCont return mNacp; } +void NacpProcess::importNacp() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); + + mNacp.fromBytes(scratch.data(), scratch.size()); +} + void NacpProcess::displayNacp() { - printf("[ApplicationControlProperty]\n"); - printf(" Menu Description:\n"); - printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str()); + std::cout << "[ApplicationControlProperty]" << std::endl; + std::cout << " Menu Description:" << std::endl; + std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl; if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" ISBN: %s\n", mNacp.getIsbn().c_str()); + std::cout << " ISBN: " << mNacp.getIsbn() << std::endl; for (size_t i = 0; i < mNacp.getTitle().size(); i++) { - printf(" %s Title:\n", getLanguageStr(mNacp.getTitle()[i].language)); - printf(" Name: %s\n", mNacp.getTitle()[i].name.c_str()); - printf(" Publisher: %s\n", mNacp.getTitle()[i].publisher.c_str()); + std::cout << " " << getLanguageStr(mNacp.getTitle()[i].language) << " Title:" << std::endl; + std::cout << " Name: " << mNacp.getTitle()[i].name << std::endl; + std::cout << " Publisher: " << mNacp.getTitle()[i].publisher << std::endl; } - printf(" Logo:\n"); - printf(" Type: %s\n", getLogoTypeStr(mNacp.getLogoType())); - printf(" Handling: %s\n", getLogoHandlingStr(mNacp.getLogoHandling())); - printf(" AddOnContent:\n"); - printf(" BaseId: 0x%016" PRIx64 "\n", mNacp.getAocBaseId()); - printf(" RegistrationType: %s\n", getAocRegistrationTypeStr(mNacp.getAocRegistrationType())); - printf(" RuntimeInstallMode: %s\n", getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode())); - printf(" Play Log:\n"); - printf(" PlayLogPolicy: %s\n", getPlayLogPolicyStr(mNacp.getPlayLogPolicy())); - printf(" PlayLogQueryCapability: %s\n", getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability())); + std::cout << " Logo:" << std::endl; + std::cout << " Type: " << getLogoTypeStr(mNacp.getLogoType()) << std::endl; + std::cout << " Handling: " << getLogoHandlingStr(mNacp.getLogoHandling()) << std::endl; + std::cout << " AddOnContent:" << std::endl; + std::cout << " BaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAocBaseId() << std::endl; + std::cout << " RegistrationType: " << getAocRegistrationTypeStr(mNacp.getAocRegistrationType()) << std::endl; + std::cout << " RuntimeInstallMode: " << getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode()) << std::endl; + std::cout << " Play Log:" << std::endl; + std::cout << " PlayLogPolicy: " << getPlayLogPolicyStr(mNacp.getPlayLogPolicy()) << std::endl; + std::cout << " PlayLogQueryCapability: " << getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability()) << std::endl; if (mNacp.getPlayLogQueryableApplicationId().size() > 0) { - printf(" PlayLogQueryableApplicationId:\n"); + std::cout << " PlayLogQueryableApplicationId:" << std::endl; for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++) { - printf(" 0x%016" PRIx64 "\n", mNacp.getPlayLogQueryableApplicationId()[i]); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPlayLogQueryableApplicationId()[i] << std::endl; } } - printf(" Parental Controls:\n"); - printf(" ParentalControlFlag: %s\n", getParentalControlFlagStr(mNacp.getParentalControlFlag())); + std::cout << " Parental Controls:" << std::endl; + std::cout << " ParentalControlFlag: " << getParentalControlFlagStr(mNacp.getParentalControlFlag()) << std::endl; for (size_t i = 0; i < mNacp.getRatingAge().size(); i++) { - printf(" Age Restriction:\n"); - printf(" Agency: %s\n", getOrganisationStr(mNacp.getRatingAge()[i].organisation)); - printf(" Age: %d\n", mNacp.getRatingAge()[i].age); + std::cout << " Age Restriction:" << std::endl; + std::cout << " Agency: " << getOrganisationStr(mNacp.getRatingAge()[i].organisation) << std::endl; + std::cout << " Age: " << std::dec << (uint32_t)mNacp.getRatingAge()[i].age << std::endl; } if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" BCAT:\n"); - printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str()); - printf(" DeliveryCacheStorageSize: 0x%016" PRIx64 "\n", mNacp.getBcatDeliveryCacheStorageSize()); + std::cout << " BCAT:" << std::endl; + std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl; + std::cout << " DeliveryCacheStorageSize: 0x" << std::hex << mNacp.getBcatDeliveryCacheStorageSize() << std::endl; } if (mNacp.getLocalCommunicationId().size() > 0) { - printf(" Local Area Communication:\n"); - printf(" LocalCommunicationId:\n"); + std::cout << " Local Area Communication:" << std::endl; + std::cout << " LocalCommunicationId:" << std::endl; for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++) { - printf(" 0x%016" PRIx64 "\n", mNacp.getLocalCommunicationId()[i]); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getLocalCommunicationId()[i] << std::endl; } } - printf(" SaveData:\n"); - printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId()); + std::cout << " SaveData:" << std::endl; + std::cout << " SaveDatawOwnerId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSaveDatawOwnerId() << std::endl; if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" UserAccountSaveData:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str()); + std::cout << " UserAccountSaveData:" << std::endl; + std::cout << " Size: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl; } if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" DeviceSaveData:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str()); + std::cout << " DeviceSaveData:" << std::endl; + std::cout << " Size: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size) << std::endl; } if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" UserAccountSaveDataMax:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str()); + std::cout << " UserAccountSaveDataMax:" << std::endl; + std::cout << " Size: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl; } if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" DeviceSaveDataMax:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str()); + std::cout << " DeviceSaveDataMax:" << std::endl; + std::cout << " Size: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size) << std::endl; } if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str()); + std::cout << " TemporaryStorageSize: " << getSaveDataSizeStr(mNacp.getTemporaryStorageSize()) << std::endl; } if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" CacheStorage:\n"); - printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str()); - printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size).c_str()); - printf(" MaxDataAndJournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()).c_str()); - printf(" StorageIndexMax: 0x%" PRIx16 "\n", mNacp.getCacheStorageIndexMax()); + std::cout << " CacheStorage:" << std::endl; + std::cout << " Size: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().size) << std::endl; + std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size) << std::endl; + std::cout << " MaxDataAndJournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl; + std::cout << " StorageIndexMax: 0x" << std::hex << mNacp.getCacheStorageIndexMax() << std::endl; } - printf(" Other Flags:\n"); - printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount())); + std::cout << " Other Flags:" << std::endl; + std::cout << " StartupUserAccount: " << getStartupUserAccountStr(mNacp.getStartupUserAccount()) << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode())); + std::cout << " TouchScreenUsageMode: " << getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode()) << std::endl; } - printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag())); - printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode())); - printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp())); - printf(" ScreenshotMode: %s\n", getScreenshotModeStr(mNacp.getScreenshotMode())); - printf(" VideoCaptureMode: %s\n", getVideoCaptureModeStr(mNacp.getVideoCaptureMode())); - printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation())); - printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag())); - printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex()); + std::cout << " AttributeFlag: " << getAttributeFlagStr(mNacp.getAttributeFlag()) << std::endl; + std::cout << " CrashReportMode: " << getCrashReportModeStr(mNacp.getCrashReportMode()) << std::endl; + std::cout << " HDCP: " << getHdcpStr(mNacp.getHdcp()) << std::endl; + std::cout << " ScreenshotMode: " << getScreenshotModeStr(mNacp.getScreenshotMode()) << std::endl; + std::cout << " VideoCaptureMode: " << getVideoCaptureModeStr(mNacp.getVideoCaptureMode()) << std::endl; + std::cout << " DataLossConfirmation: " << getDataLossConfirmationStr(mNacp.getDataLossConfirmation()) << std::endl; + std::cout << " RepairFlag: " << getRepairFlagStr(mNacp.getRepairFlag()) << std::endl; + std::cout << " ProgramIndex: 0x" << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mNacp.getProgramIndex() << std::endl; if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str()); + std::cout << " ApplicationErrorCodeCategory: " << mNacp.getApplicationErrorCodeCategory() << std::endl; } if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Other Ids:\n"); + std::cout << " Other Ids:" << std::endl; if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId()); + std::cout << " SeedForPsuedoDeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSeedForPsuedoDeviceId() << std::endl; if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId()); + std::cout << " PresenceGroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPresenceGroupId() << std::endl; } } diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h index ec844be..8d6eb6e 100644 --- a/programs/nstool/source/NacpProcess.h +++ b/programs/nstool/source/NacpProcess.h @@ -30,6 +30,7 @@ private: nn::hac::ApplicationControlPropertyBinary mNacp; + void importNacp(); void displayNacp(); const char* getLanguageStr(nn::hac::nacp::Language var) const; const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const; diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 1e71c85..1c98593 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -44,22 +45,8 @@ NcaProcess::~NcaProcess() void NcaProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - // read header block - mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); - - // decrypt header block - nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); - - // generate header hash - fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes); - - // proccess main header - mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader)); + // import header + importHeader(); // determine keys generateNcaBodyEncryptionKeys(); @@ -129,6 +116,26 @@ void NcaProcess::setListFs(bool list_fs) mListFs = list_fs; } +void NcaProcess::importHeader() +{ + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + // read header block + mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); + + // decrypt header block + nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); + + // generate header hash + fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes); + + // proccess main header + mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader)); +} + void NcaProcess::generateNcaBodyEncryptionKeys() { // create zeros key @@ -231,17 +238,17 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { if (mBodyKeys.aes_ctr.isSet) { - printf("[NCA Body Key]\n"); - printf(" AES-CTR Key: "); + std::cout << "[NCA Body Key]" << std::endl; + std::cout << " AES-CTR Key: "; fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); } if (mBodyKeys.aes_xts.isSet) { - printf("[NCA Body Key]\n"); - printf(" AES-XTS Key0: "); + std::cout << "[NCA Body Key]" << std::endl; + std::cout << " AES-XTS Key0: "; fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var)); - printf(" AES-XTS Key1: "); + std::cout << " AES-XTS Key1: "; fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var)); } } @@ -363,7 +370,7 @@ void NcaProcess::validateNcaSignatures() // validate signature[0] if (fnd::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0) { - printf("[WARNING] NCA Header Main Signature: FAIL \n"); + std::cout << "[WARNING] NCA Header Main Signature: FAIL" << std::endl; } // validate signature[1] @@ -390,93 +397,90 @@ void NcaProcess::validateNcaSignatures() if (fnd::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeaderSignature2Key(), fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0) { - printf("[WARNING] NCA Header ACID Signature: FAIL \n"); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL" << std::endl; } } else { - printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str()); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL (\"" << kNpdmExefsPath << "\" not present in ExeFs)" << std::endl; } } else { - printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n"); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)" << std::endl; } } else { - printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n"); + std::cout << "[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)" << std::endl; } } } void NcaProcess::displayHeader() { -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - - printf("[NCA Header]\n"); - printf(" Format Type: %s\n", getFormatVersionStr(mHdr.getFormatVersion())); - printf(" Dist. Type: %s\n", getDistributionTypeStr(mHdr.getDistributionType())); - printf(" Content Type: %s\n", getContentTypeStr(mHdr.getContentType())); - printf(" Key Generation: %d\n", mHdr.getKeyGeneration()); - printf(" Kaek Index: %s (%d)\n", getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()), mHdr.getKaekIndex()); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getContentSize()); - printf(" ProgID: 0x%016" PRIx64 "\n", mHdr.getProgramId()); - printf(" Content Index: %" PRIu32 "\n", mHdr.getContentIndex()); -#define _SPLIT_VER(ver) ( (ver>>24) & 0xff), ( (ver>>16) & 0xff), ( (ver>>8) & 0xff) - printf(" SdkAddon Ver.: v%" PRIu32 " (%d.%d.%d)\n", mHdr.getSdkAddonVersion(), _SPLIT_VER(mHdr.getSdkAddonVersion())); + std::cout << "[NCA Header]" << std::endl; + std::cout << " Format Type: " << getFormatVersionStr(mHdr.getFormatVersion()) << std::endl; + std::cout << " Dist. Type: " << getDistributionTypeStr(mHdr.getDistributionType()) << std::endl; + std::cout << " Content Type: " << getContentTypeStr(mHdr.getContentType()) << std::endl; + std::cout << " Key Generation: " << std::dec << (uint32_t)mHdr.getKeyGeneration() << std::endl; + std::cout << " Kaek Index: " << getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()) << " (" << std::dec << (uint32_t)mHdr.getKaekIndex() << ")" << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getContentSize() << std::endl; + std::cout << " ProgID: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getProgramId() << std::endl; + std::cout << " Content Index: " << std::dec << mHdr.getContentIndex() << std::endl; +#define _SPLIT_VER(ver) std::dec << (uint32_t)((ver>>24) & 0xff) << "." << (uint32_t)((ver>>16) & 0xff) << "." << (uint32_t)((ver>>8) & 0xff) + std::cout << " SdkAddon Ver.: v" << std::dec << mHdr.getSdkAddonVersion() << " (" << _SPLIT_VER(mHdr.getSdkAddonVersion()) << ")" << std::endl; #undef _SPLIT_VER if (mHdr.hasRightsId()) { - printf(" RightsId: "); + std::cout << " RightsId: "; fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen); } - +#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0) if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { - printf(" Key Area: \n"); - printf(" <--------------------------------------------------------------------------->\n"); - printf(" | IDX | ENCRYPTED KEY | DECRYPTED KEY |\n"); - printf(" |-----|----------------------------------|----------------------------------|\n"); + std::cout << " Key Area:" << std::endl; + std::cout << " <--------------------------------------------------------------------------->" << std::endl; + std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl; + std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl; for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++) { - printf(" | %3d | ", mBodyKeys.keak_list[i].index); + std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mBodyKeys.keak_list[i].index << " | "; _HEXDUMP_L(mBodyKeys.keak_list[i].enc.key, 16); - //for (size_t j = 0; j < 16; j++) printf("%02x", mBodyKeys.keak_list[i].enc.key[j]); - printf(" | "); + std::cout << " | "; if (mBodyKeys.keak_list[i].decrypted) _HEXDUMP_L(mBodyKeys.keak_list[i].dec.key, 16); else - printf(" "); + std::cout << " "; - printf(" |\n"); + std::cout << " |" << std::endl; } - printf(" <--------------------------------------------------------------------------->\n"); + std::cout << " <--------------------------------------------------------------------------->" << std::endl; } +#undef _HEXDUMP_L if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" Partitions:\n"); + std::cout << " Partitions:" << std::endl; for (size_t i = 0; i < mHdr.getPartitions().size(); i++) { size_t index = mHdr.getPartitions()[i].index; sPartitionInfo& info = mPartitions[index]; - printf(" %d:\n", (int)index); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); - printf(" Format Type: %s\n", getFormatTypeStr(info.format_type)); - printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type)); - printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type)); + std::cout << " " << std::dec << index << ":" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)info.offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)info.size << std::endl; + std::cout << " Format Type: " << getFormatTypeStr(info.format_type) << std::endl; + std::cout << " Hash Type: " << getHashTypeStr(info.hash_type) << std::endl; + std::cout << " Enc. Type: " << getEncryptionTypeStr(info.enc_type) << std::endl; if (info.enc_type == nn::hac::nca::CRYPT_AESCTR) { - printf(" AES-CTR: "); + std::cout << " AES-CTR: "; fnd::aes::sAesIvCtr ctr; fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(fnd::aes::sAesIvCtr)); @@ -484,53 +488,41 @@ void NcaProcess::displayHeader() if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY) { HashTreeMeta& hash_hdr = info.hash_tree_meta; - printf(" HierarchicalIntegrity Header:\n"); - //printf(" TypeId: 0x%x\n", hash_hdr.type_id.get()); - //printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get()); - //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size()); + std::cout << " HierarchicalIntegrity Header:" << std::endl; for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++) { - printf(" Hash Layer %d:\n", (int)j); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size); - printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size); + std::cout << " Hash Layer " << std::dec << j << ":" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].size << std::endl; + std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size << std::endl; } - printf(" Data Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); - printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); + std::cout << " Data Layer:" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl; + std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++) { - printf(" Master Hash %d: ", (int)j); + std::cout << " Master Hash " << std::dec << j << ": "; fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash)); } } else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256) { HashTreeMeta& hash_hdr = info.hash_tree_meta; - printf(" HierarchicalSha256 Header:\n"); - printf(" Master Hash: "); + std::cout << " HierarchicalSha256 Header:" << std::endl; + std::cout << " Master Hash: "; fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash)); - printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); - //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size()); - printf(" Hash Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size); - printf(" Data Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); + std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; + std::cout << " Hash Layer:" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].size << std::endl; + std::cout << " Data Layer:" << std::endl; + std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl; + std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl; } - //else - //{ - // printf(" Hash Superblock:\n"); - // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen); - //} } } - -#undef _HEXDUMP_U -#undef _HEXDUMP_L } @@ -544,12 +536,12 @@ void NcaProcess::processPartitions() // if the reader is null, skip if (partition.reader == nullptr) { - printf("[WARNING] NCA Partition %d not readable.", (int)index); + std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable."; if (partition.fail_reason.empty() == false) { - printf(" (%s)", partition.fail_reason.c_str()); + std::cout << " (" << partition.fail_reason << ")"; } - printf("\n"); + std::cout << std::endl; continue; } @@ -570,9 +562,7 @@ void NcaProcess::processPartitions() if (mPartitionPath[index].doExtract) pfs.setExtractPath(mPartitionPath[index].path); - //printf("pfs.process(%lx)\n",partition.data_offset); pfs.process(); - //printf("pfs.process() end\n"); } else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS) { @@ -591,9 +581,7 @@ void NcaProcess::processPartitions() if (mPartitionPath[index].doExtract) romfs.setExtractPath(mPartitionPath[index].path); - //printf("romfs.process(%lx)\n", partition.data_offset); romfs.process(); - //printf("romfs.process() end\n"); } } } diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index 49c6d57..a9b0806 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -105,6 +105,7 @@ private: fnd::aes::sAesIvCtr aes_ctr; } mPartitions[nn::hac::nca::kPartitionNum]; + void importHeader(); void generateNcaBodyEncryptionKeys(); void generatePartitionConfiguration(); void validateNcaSignatures(); diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index f0ab4eb..b9f5fe6 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include "NpdmProcess.h" NpdmProcess::NpdmProcess() : @@ -19,17 +21,7 @@ NpdmProcess::~NpdmProcess() void NpdmProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); - - mNpdm.fromBytes(scratch.data(), scratch.size()); + importNpdm(); if (mVerify) { @@ -85,13 +77,28 @@ const nn::hac::NpdmBinary& NpdmProcess::getNpdmBinary() const return mNpdm; } +void NpdmProcess::importNpdm() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mFile->size()); + mFile->read(scratch.data(), 0, scratch.size()); + + mNpdm.fromBytes(scratch.data(), scratch.size()); +} + void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid) { try { acid.validateSignature(mKeyset->acid_sign_key); } catch (...) { - printf("[WARNING] ACID Signature: FAIL\n"); + std::cout << "[WARNING] ACID Signature: FAIL" << std::endl; } } @@ -101,11 +108,11 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac // check Program ID if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min) { - printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); + std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl; } else if (acid.getProgramIdRestrict().max > 0 && aci.getProgramId() > acid.getProgramIdRestrict().max) { - printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); + std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl; } for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++) @@ -120,7 +127,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (fsaRightFound == false) { - printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i])); + std::cout << "[WARNING] ACI/FAC FsaRights: FAIL (" << getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i]) << " not permitted)" << std::endl; } } @@ -136,7 +143,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 " not permitted)\n", aci.getFileSystemAccessControl().getContentOwnerIdList()[i]); + std::cout << "[WARNING] ACI/FAC ContentOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getContentOwnerIdList()[i] << " not permitted)" << std::endl; } } @@ -152,7 +159,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (%016" PRIx64 "(%d) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type); + std::cout << "[WARNING] ACI/FAC SaveDataOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id << "(" << std::dec << (uint32_t)aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type << ") not permitted)" << std::endl; } } @@ -168,7 +175,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getServiceAccessControl().getServiceList()[i].getName().c_str(), aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : ""); + std::cout << "[WARNING] ACI/SAC ServiceList: FAIL (" << aci.getServiceAccessControl().getServiceList()[i].getName() << (aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : "") << " not permitted)" << std::endl; } } @@ -176,19 +183,19 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac // check thread info if (aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() != acid.getKernelCapabilities().getThreadInfo().getMaxCpuId()) { - printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxCpuId()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() << " not permitted)" << std::endl; } if (aci.getKernelCapabilities().getThreadInfo().getMinCpuId() != acid.getKernelCapabilities().getThreadInfo().getMinCpuId()) { - printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinCpuId()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinCpuId() << " not permitted)" << std::endl; } if (aci.getKernelCapabilities().getThreadInfo().getMaxPriority() != acid.getKernelCapabilities().getThreadInfo().getMaxPriority()) { - printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxPriority()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxPriority() << " not permitted)" << std::endl; } if (aci.getKernelCapabilities().getThreadInfo().getMinPriority() != acid.getKernelCapabilities().getThreadInfo().getMinPriority()) { - printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinPriority()); + std::cout << "[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinPriority() << " not permitted)" << std::endl; } // check system calls for (size_t i = 0; i < aci.getKernelCapabilities().getSystemCalls().getSystemCalls().size(); i++) @@ -202,7 +209,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i])); + std::cout << "[WARNING] ACI/KC SystemCallList: FAIL (" << getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]) << " not permitted)" << std::endl; } } // check memory maps @@ -219,7 +226,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac { const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i]; - printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, getMemMapPermStr(map.perm), getMemMapTypeStr(map.type)); + std::cout << "[WARNING] ACI/KC MemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl; } } for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++) @@ -235,7 +242,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac { const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i]; - printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, getMemMapPermStr(map.perm), getMemMapTypeStr(map.type)); + std::cout << "[WARNING] ACI/KC IoMemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl; } } // check interupts @@ -250,25 +257,25 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKernelCapabilities().getInterupts().getInteruptList()[i]); + std::cout << "[WARNING] ACI/KC InteruptsList: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getInterupts().getInteruptList()[i] << " not permitted)" << std::endl; } } // check misc params if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType()) { - printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType()); + std::cout << "[WARNING] ACI/KC ProgramType: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType() << " not permitted)" << std::endl; } // check kernel version uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor(); uint32_t acidKernelVersion = (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMinor(); if (aciKernelVersion < acidKernelVersion) { - printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKernelCapabilities().getKernelVersion().getVerMajor(), aci.getKernelCapabilities().getKernelVersion().getVerMinor()); + std::cout << "[WARNING] ACI/KC RequiredKernelVersion: FAIL (" << std::dec << aci.getKernelCapabilities().getKernelVersion().getVerMajor() << "." << aci.getKernelCapabilities().getKernelVersion().getVerMinor() << " not permitted)" << std::endl; } // check handle table size if (aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() > acid.getKernelCapabilities().getHandleTableSize().getHandleTableSize()) { - printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize()); + std::cout << "[WARNING] ACI/KC HandleTableSize: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() << " too large)" << std::endl; } // check misc flags for (size_t i = 0; i < aci.getKernelCapabilities().getMiscFlags().getFlagList().size(); i++) @@ -282,88 +289,92 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac if (rightFound == false) { - printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i])); + std::cout << "[WARNING] ACI/KC MiscFlag: FAIL (" << getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]) << " not permitted)" << std::endl; } } } void NpdmProcess::displayNpdmHeader(const nn::hac::NpdmBinary& hdr) { - printf("[NPDM HEADER]\n"); - printf(" Process Architecture Params:\n"); - printf(" Ins. Type: %s\n", getInstructionTypeStr(hdr.getInstructionType())); - printf(" Addr Space: %s\n", getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType())); - printf(" Main Thread Params:\n"); - printf(" Priority: %d\n", hdr.getMainThreadPriority()); - printf(" CpuId: %d\n", hdr.getMainThreadCpuId()); - printf(" StackSize: 0x%x\n", hdr.getMainThreadStackSize()); - printf(" TitleInfo:\n"); - printf(" Version: v%" PRIu32 "\n", hdr.getVersion()); - printf(" Name: %s\n", hdr.getName().c_str()); + std::cout << "[NPDM HEADER]" << std::endl; + std::cout << " Process Architecture Params:" << std::endl; + std::cout << " Ins. Type: " << getInstructionTypeStr(hdr.getInstructionType()) << std::endl; + std::cout << " Addr Space: " << getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType()) << std::endl; + std::cout << " Main Thread Params:" << std::endl; + std::cout << " Priority: " << std::dec << (uint32_t)hdr.getMainThreadPriority() << std::endl; + std::cout << " CpuId: " << std::dec << (uint32_t)hdr.getMainThreadCpuId() << std::endl; + std::cout << " StackSize: 0x" << std::hex << hdr.getMainThreadStackSize() << std::endl; + std::cout << " TitleInfo:" << std::endl; + std::cout << " Version: v" << std::dec << hdr.getVersion() << std::endl; + std::cout << " Name: " << hdr.getName() << std::endl; if (hdr.getProductCode().length()) { - printf(" ProductCode: %s\n", hdr.getProductCode().c_str()); + std::cout << " ProductCode: " << hdr.getProductCode() << std::endl; } } void NpdmProcess::displayAciHdr(const nn::hac::AccessControlInfoBinary& aci) { - printf("[Access Control Info]\n"); - printf(" ProgramID: 0x%016" PRIx64 "\n", aci.getProgramId()); + std::cout << "[Access Control Info]" << std::endl; + std::cout << " ProgramID: 0x" << std::hex << std::setw(16) << std::setfill('0') << aci.getProgramId() << std::endl; } void NpdmProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDescBinary& acid) { - printf("[Access Control Info Desc]\n"); + std::cout << "[Access Control Info Desc]" << std::endl; if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Flags: \n"); + std::cout << " Flags: " << std::endl; for (size_t i = 0; i < acid.getFlagList().size(); i++) { - printf(" %s (%d)\n", getAcidFlagStr(acid.getFlagList()[i]), acid.getFlagList()[i]); + std::cout << " " << getAcidFlagStr(acid.getFlagList()[i]) << " (" << std::dec << (uint32_t)acid.getFlagList()[i] << ")" << std::endl; } } - printf(" ProgramID Restriction\n"); - printf(" Min: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().min); - printf(" Max: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().max); + std::cout << " ProgramID Restriction" << std::endl; + std::cout << " Min: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().min << std::endl; + std::cout << " Max: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().max << std::endl; } void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) { - printf("[FS Access Control]\n"); - printf(" Format Version: %d\n", fac.getFormatVersion()); + std::cout << "[FS Access Control]" << std::endl; + std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << std::endl; if (fac.getFsaRightsList().size()) { - printf(" FS Rights:\n"); + std::cout << " FS Rights:" << std::endl; for (size_t i = 0; i < fac.getFsaRightsList().size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("%s", getFsaRightStr(fac.getFsaRightsList()[i])); + std::cout << getFsaRightStr(fac.getFsaRightsList()[i]); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" (bit %" PRId32 ")", fac.getFsaRightsList()[i]); - printf("%s", fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack() ? ", " : "\n"); + std::cout << " (bit " << std::dec << (uint32_t)fac.getFsaRightsList()[i] << ")"; + if (fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack()) + std::cout << ", "; + std::cout << std::endl; } } if (fac.getContentOwnerIdList().size()) { - printf(" Content Owner IDs:\n"); + std::cout << " Content Owner IDs:" << std::endl; for (size_t i = 0; i < fac.getContentOwnerIdList().size(); i++) { - printf(" 0x%016" PRIx64 "\n", fac.getContentOwnerIdList()[i]); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getContentOwnerIdList()[i] << std::endl; } } if (fac.getSaveDataOwnerIdList().size()) { - printf(" Save Data Owner IDs:\n"); + std::cout << " Save Data Owner IDs:" << std::endl; for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++) { - printf(" 0x%016" PRIx64 " (%s)\n", fac.getSaveDataOwnerIdList()[i].id, getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type)); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getSaveDataOwnerIdList()[i].id << " (" << getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type) << ")" << std::endl; } } @@ -371,102 +382,123 @@ void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac) void NpdmProcess::displaySac(const nn::hac::ServiceAccessControlBinary& sac) { - printf("[Service Access Control]\n"); - printf(" Service List:\n"); + std::cout << "[Service Access Control]" << std::endl; + std::cout << " Service List:" << std::endl; for (size_t i = 0; i < sac.getServiceList().size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("%s%s%s", sac.getServiceList()[i].getName().c_str(), sac.getServiceList()[i].isServer() ? "(isSrv)" : "", sac.getServiceList()[i] != sac.getServiceList().atBack() ? ", " : "\n"); + std::cout << sac.getServiceList()[i].getName(); + if (sac.getServiceList()[i].isServer()) + std::cout << "(isSrv)"; + if (sac.getServiceList()[i] != sac.getServiceList().atBack()) + std::cout << ", "; } + std::cout << std::endl; } void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern) { - printf("[Kernel Capabilities]\n"); + std::cout << "[Kernel Capabilities]" << std::endl; if (kern.getThreadInfo().isSet()) { nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo(); - printf(" Thread Priority:\n"); - printf(" Min: %d\n", threadInfo.getMinPriority()); - printf(" Max: %d\n", threadInfo.getMaxPriority()); - printf(" CpuId:\n"); - printf(" Min: %d\n", threadInfo.getMinCpuId()); - printf(" Max: %d\n", threadInfo.getMaxCpuId()); + std::cout << " Thread Priority:" << std::endl; + std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinPriority() << std::endl; + std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxPriority() << std::endl; + std::cout << " CpuId:" << std::endl; + std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinCpuId() << std::endl; + std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxCpuId() << std::endl; } if (kern.getSystemCalls().isSet()) { fnd::List syscalls = kern.getSystemCalls().getSystemCalls(); - printf(" SystemCalls:"); - printf("\n "); + std::cout << " SystemCalls:" << std::endl; + std::cout << " "; size_t lineLen = 0; for (size_t i = 0; i < syscalls.size(); i++) { if (lineLen > 60) { lineLen = 0; - printf("\n "); + std::cout << std::endl; + std::cout << " "; } - printf("%s%s", getSystemCallStr(syscalls[i]), syscalls[i] != syscalls.atBack() ? ", " : "\n"); + std::cout << getSystemCallStr(syscalls[i]); + if (syscalls[i] != syscalls.atBack()) + std::cout << ", "; lineLen += strlen(getSystemCallStr(syscalls[i])); } + std::cout << std::endl; } if (kern.getMemoryMaps().isSet()) { fnd::List maps = kern.getMemoryMaps().getMemoryMaps(); fnd::List ioMaps = kern.getMemoryMaps().getIoMemoryMaps(); - printf(" MemoryMaps:\n"); + std::cout << " MemoryMaps:" << std::endl; for (size_t i = 0; i < maps.size(); i++) { - printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)maps[i].addr << 12, ((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1, getMemMapPermStr(maps[i].perm), getMemMapTypeStr(maps[i].type)); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(maps[i].perm) << ") (type=" << getMemMapTypeStr(maps[i].type) << ") not permitted)" << std::endl; } - //printf(" IoMaps:\n"); + //std::cout << " IoMaps:" << std::endl; for (size_t i = 0; i < ioMaps.size(); i++) { - printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)ioMaps[i].addr << 12, ((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1, getMemMapPermStr(ioMaps[i].perm), getMemMapTypeStr(ioMaps[i].type)); + std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(ioMaps[i].perm) << ") (type=" << getMemMapTypeStr(ioMaps[i].type) << ") not permitted)" << std::endl; } } if (kern.getInterupts().isSet()) { fnd::List interupts = kern.getInterupts().getInteruptList(); - printf(" Interupts Flags:\n"); + std::cout << " Interupts Flags:" << std::endl; for (uint32_t i = 0; i < interupts.size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("0x%x%s", interupts[i], interupts[i] != interupts.atBack() ? ", " : "\n"); + std::cout << "0x" << std::hex << (uint32_t)interupts[i]; + if (interupts[i] != interupts.atBack()) + std::cout << ", "; + std::cout << std::endl; } } if (kern.getMiscParams().isSet()) { - printf(" ProgramType: %d\n", kern.getMiscParams().getProgramType()); + std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl; } if (kern.getKernelVersion().isSet()) { - printf(" Kernel Version: %d.%d\n", kern.getKernelVersion().getVerMajor(), kern.getKernelVersion().getVerMinor()); + std::cout << " Kernel Version: " << std::dec << (uint32_t)kern.getKernelVersion().getVerMajor() << "." << (uint32_t)kern.getKernelVersion().getVerMinor() << std::endl; } if (kern.getHandleTableSize().isSet()) { - printf(" Handle Table Size: 0x%x\n", kern.getHandleTableSize().getHandleTableSize()); + std::cout << " Handle Table Size: 0x" << std::hex << kern.getHandleTableSize().getHandleTableSize() << std::endl; } if (kern.getMiscFlags().isSet()) { fnd::List flagList = kern.getMiscFlags().getFlagList(); - printf(" Misc Flags:\n"); + std::cout << " Misc Flags:" << std::endl; for (uint32_t i = 0; i < flagList.size(); i++) { if (i % 10 == 0) { - printf("%s ", i != 0 ? "\n" : ""); + if (i != 0) + std::cout << std::endl; + std::cout << " "; } - printf("%s%s", getMiscFlagStr(flagList[i]), flagList[i] != flagList.atBack() ? ", " : "\n"); + std::cout << getMiscFlagStr(flagList[i]); + if (flagList[i] != flagList.atBack()) + std::cout << ", "; + std::cout << std::endl; } } } diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index 9e4fc24..d476493 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -32,6 +32,8 @@ private: nn::hac::NpdmBinary mNpdm; + void importNpdm(); + void validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid); void validateAciFromAcid(const nn::hac::AccessControlInfoBinary& aci, const nn::hac::AccessControlInfoDescBinary& acid); diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp index 3beb776..e9c73b3 100644 --- a/programs/nstool/source/NroProcess.cpp +++ b/programs/nstool/source/NroProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -23,11 +25,6 @@ NroProcess::~NroProcess() void NroProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importHeader(); importCodeSegments(); @@ -99,6 +96,12 @@ const RoMetadataProcess& NroProcess::getRoMetadataProcess() const void NroProcess::importHeader() { fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + if (mFile->size() < sizeof(nn::hac::sNroHeader)) { throw fnd::Exception(kModuleName, "Corrupt NRO: file too small"); @@ -134,39 +137,39 @@ void NroProcess::importCodeSegments() void NroProcess::displayHeader() { -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - printf("[NRO Header]\n"); - printf(" RoCrt: "); +#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0) + std::cout << "[NRO Header]" << std::endl; + std::cout << " RoCrt: "; _HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize); - printf("\n"); - printf(" ModuleId: "); + std::cout << std::endl; + std::cout << " ModuleId: "; _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize); - printf("\n"); - printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize()); - printf(" Program Sections:\n"); - printf(" .text:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size); - printf(" .ro:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size); + std::cout << std::endl; + std::cout << " NroSize: 0x" << std::hex << mHdr.getNroSize() << std::endl; + std::cout << " Program Sections:" << std::endl; + std::cout << " .text:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getTextInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getTextInfo().size << std::endl; + std::cout << " .ro:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoInfo().size << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" .api_info:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); - printf(" .dynstr:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); - printf(" .dynsym:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); + std::cout << " .api_info:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl; + std::cout << " .dynstr:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynStrInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl; + std::cout << " .dynsym:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynSymInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl; } - printf(" .data:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size); - printf(" .bss:\n"); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize()); + std::cout << " .data:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getDataInfo().memory_offset << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getDataInfo().size << std::endl; + std::cout << " .bss:" << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl; #undef _HEXDUMP_L } diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index 3113be5..9f40548 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -22,11 +24,6 @@ NsoProcess::~NsoProcess() void NsoProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importHeader(); importCodeSegments(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) @@ -74,6 +71,12 @@ const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const void NsoProcess::importHeader() { fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + if (mFile->size() < sizeof(nn::hac::sNsoHeader)) { throw fnd::Exception(kModuleName, "Corrupt NSO: file too small"); @@ -172,71 +175,71 @@ void NsoProcess::importCodeSegments() void NsoProcess::displayNsoHeader() { -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) +#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0) - printf("[NSO Header]\n"); - printf(" ModuleId: "); + std::cout << "[NSO Header]" << std::endl; + std::cout << " ModuleId: "; _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize); - printf("\n"); + std::cout << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" Program Segments:\n"); - printf(" .module_name:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset); - printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size); - printf(" .text:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .ro:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .data:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + std::cout << " Program Segments:" << std::endl; + std::cout << " .module_name:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getModuleNameInfo().offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getModuleNameInfo().size << std::endl; + std::cout << " .text:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.size << (mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + std::cout << " .ro:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.size << (mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; + std::cout << " .data:" << std::endl; + std::cout << " FileOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.offset << std::endl; + std::cout << " FileSize: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.size << (mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl; } - printf(" Program Sections:\n"); - printf(" .text:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size); + std::cout << " Program Sections:" << std::endl; + std::cout << " .text:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl; if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash: "); + std::cout << " Hash: "; _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32); - printf("\n"); + std::cout << std::endl; } - printf(" .ro:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size); + std::cout << " .ro:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl; if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash: "); + std::cout << " Hash: "; _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32); - printf("\n"); + std::cout << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" .api_info:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); - printf(" .dynstr:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); - printf(" .dynsym:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); + std::cout << " .api_info:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl; + std::cout << " .dynstr:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynStrInfo().offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl; + std::cout << " .dynsym:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynSymInfo().offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl; } - printf(" .data:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size); + std::cout << " .data:" << std::endl; + std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl; if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash: "); + std::cout << " Hash: "; _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32); - printf("\n"); + std::cout << std::endl; } - printf(" .bss:\n"); - printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize()); + std::cout << " .bss:" << std::endl; + std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl; #undef _HEXDUMP_L } diff --git a/programs/nstool/source/PfsProcess.cpp b/programs/nstool/source/PfsProcess.cpp index c44fca0..f878a4f 100644 --- a/programs/nstool/source/PfsProcess.cpp +++ b/programs/nstool/source/PfsProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include "PfsProcess.h" @@ -25,26 +27,7 @@ PfsProcess::~PfsProcess() void PfsProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - // open minimum header to get full header size - scratch.alloc(sizeof(nn::hac::sPfsHeader)); - mFile->read(scratch.data(), 0, scratch.size()); - if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) - { - throw fnd::Exception(kModuleName, "Corrupt Header"); - } - size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data())); - - // open minimum header to get full header size - scratch.alloc(pfsHeaderSize); - mFile->read(scratch.data(), 0, scratch.size()); - mPfs.fromBytes(scratch.data(), scratch.size()); + importHeader(); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) { @@ -95,32 +78,64 @@ const nn::hac::PfsHeader& PfsProcess::getPfsHeader() const return mPfs; } +void PfsProcess::importHeader() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + // open minimum header to get full header size + scratch.alloc(sizeof(nn::hac::sPfsHeader)); + mFile->read(scratch.data(), 0, scratch.size()); + if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) + { + throw fnd::Exception(kModuleName, "Corrupt Header"); + } + size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data())); + + // open minimum header to get full header size + scratch.alloc(pfsHeaderSize); + mFile->read(scratch.data(), 0, scratch.size()); + mPfs.fromBytes(scratch.data(), scratch.size()); +} + void PfsProcess::displayHeader() { - printf("[PartitionFS]\n"); - printf(" Type: %s\n", mPfs.getFsType() == mPfs.TYPE_PFS0? "PFS0" : "HFS0"); - printf(" FileNum: %" PRId64 "\n", (uint64_t)mPfs.getFileList().size()); - if (mMountName.empty() == false) - printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : ""); + std::cout << "[PartitionFS]" << std::endl; + std::cout << " Type: " << getFsTypeStr(mPfs.getFsType()) << std::endl; + std::cout << " FileNum: " << std::dec << mPfs.getFileList().size() << std::endl; + if (mMountName.empty() == false) + { + std::cout << " MountPoint: " << mMountName; + if (mMountName.at(mMountName.length()-1) != '/') + std::cout << "/"; + std::cout << std::endl; + } } void PfsProcess::displayFs() { for (size_t i = 0; i < mPfs.getFileList().size(); i++) { - printf(" %s", mPfs.getFileList()[i].name.c_str()); + const nn::hac::PfsHeader::sFile& file = mPfs.getFileList()[i]; + std::cout << " " << file.name; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - if (mPfs.getFsType() == mPfs.TYPE_PFS0) - printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size); - else - printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ", hash_protected_size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size, (uint64_t)mPfs.getFileList()[i].hash_protected_size); + switch (mPfs.getFsType()) + { + case (nn::hac::PfsHeader::TYPE_PFS0): + std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")"; + break; + case (nn::hac::PfsHeader::TYPE_HFS0): + std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ", hash_protected_size=0x" << file.hash_protected_size << ")"; + break; + } + } - else - { - printf("\n"); - } - + std::cout << std::endl; } } @@ -187,3 +202,23 @@ void PfsProcess::extractFs() outFile.close(); } } + +const char* PfsProcess::getFsTypeStr(nn::hac::PfsHeader::FsType type) const +{ + const char* str = nullptr; + + switch (type) + { + case (nn::hac::PfsHeader::TYPE_PFS0): + str = "PFS0"; + break; + case (nn::hac::PfsHeader::TYPE_HFS0): + str = "HFS0"; + break; + default: + str = "Unknown"; + break; + } + + return str; +} \ No newline at end of file diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h index 4b15c05..96c56aa 100644 --- a/programs/nstool/source/PfsProcess.h +++ b/programs/nstool/source/PfsProcess.h @@ -44,10 +44,13 @@ private: nn::hac::PfsHeader mPfs; + void importHeader(); void displayHeader(); void displayFs(); size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr); bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr); void validateHfs(); void extractFs(); + + const char* getFsTypeStr(nn::hac::PfsHeader::FsType type) const; }; \ No newline at end of file diff --git a/programs/nstool/source/PkiCertProcess.cpp b/programs/nstool/source/PkiCertProcess.cpp index db7c629..505c7a1 100644 --- a/programs/nstool/source/PkiCertProcess.cpp +++ b/programs/nstool/source/PkiCertProcess.cpp @@ -1,6 +1,5 @@ #include #include - #include #include #include "OffsetAdjustedIFile.h" @@ -25,12 +24,8 @@ PkiCertProcess::~PkiCertProcess() void PkiCertProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - importCerts(); + if (mVerify) validateCerts(); @@ -63,6 +58,11 @@ void PkiCertProcess::importCerts() { fnd::Vec scratch; + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + scratch.alloc(mFile->size()); mFile->read(scratch.data(), 0, scratch.size()); @@ -100,10 +100,6 @@ void PkiCertProcess::displayCerts() void PkiCertProcess::displayCert(const nn::pki::SignedData& cert) { -#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) -#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - std::cout << "[NNPKI Certificate]" << std::endl; std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType()); @@ -143,12 +139,6 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData #include #include #include +#include "PkiValidator.h" PkiValidator::PkiValidator() { diff --git a/programs/nstool/source/RoMetadataProcess.cpp b/programs/nstool/source/RoMetadataProcess.cpp index 3c44d2b..afbb982 100644 --- a/programs/nstool/source/RoMetadataProcess.cpp +++ b/programs/nstool/source/RoMetadataProcess.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include "RoMetadataProcess.h" @@ -23,12 +25,8 @@ RoMetadataProcess::RoMetadataProcess() : void RoMetadataProcess::process() { - if (mRoBlob.size() == 0) - { - throw fnd::Exception(kModuleName, "No ro binary set."); - } - importApiList(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayRoMetaData(); } @@ -101,6 +99,11 @@ const fnd::List& RoMetadataProcess::getSymbolList() void RoMetadataProcess::importApiList() { + if (mRoBlob.size() == 0) + { + throw fnd::Exception(kModuleName, "No ro binary set."); + } + if (mApiInfo.size > 0) { std::stringstream list_stream(std::string((char*)mRoBlob.data() + mApiInfo.offset, mApiInfo.size)); @@ -133,43 +136,43 @@ void RoMetadataProcess::displayRoMetaData() if (api_num > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { - printf("[SDK API List]\n"); + std::cout << "[SDK API List]" << std::endl; if (mSdkVerApiList.size() > 0) { - printf(" Sdk Revision: %s\n", mSdkVerApiList[0].getModuleName().c_str()); + std::cout << " Sdk Revision: " << mSdkVerApiList[0].getModuleName() << std::endl; } if (mPublicApiList.size() > 0) { - printf(" Public APIs:\n"); + std::cout << " Public APIs:" << std::endl; for (size_t i = 0; i < mPublicApiList.size(); i++) { - printf(" %s (vender: %s)\n", mPublicApiList[i].getModuleName().c_str(), mPublicApiList[i].getVenderName().c_str()); + std::cout << " " << mPublicApiList[i].getModuleName() << " (vender: " << mPublicApiList[i].getVenderName() << ")" << std::endl; } } if (mDebugApiList.size() > 0) { - printf(" Debug APIs:\n"); + std::cout << " Debug APIs:" << std::endl; for (size_t i = 0; i < mDebugApiList.size(); i++) { - printf(" %s (vender: %s)\n", mDebugApiList[i].getModuleName().c_str(), mDebugApiList[i].getVenderName().c_str()); + std::cout << " " << mDebugApiList[i].getModuleName() << " (vender: " << mDebugApiList[i].getVenderName() << ")" << std::endl; } } if (mPrivateApiList.size() > 0) { - printf(" Private APIs:\n"); + std::cout << " Private APIs:" << std::endl; for (size_t i = 0; i < mPrivateApiList.size(); i++) { - printf(" %s (vender: %s)\n", mPrivateApiList[i].getModuleName().c_str(), mPrivateApiList[i].getVenderName().c_str()); + std::cout << " " << mPrivateApiList[i].getModuleName() << " (vender: " << mPrivateApiList[i].getVenderName() << ")" << std::endl; } } } if (mSymbolList.getSymbolList().size() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { - printf("[Symbol List]\n"); + std::cout << "[Symbol List]" << std::endl; for (size_t i = 0; i < mSymbolList.getSymbolList().size(); i++) { const ElfSymbolParser::sElfSymbol& symbol = mSymbolList.getSymbolList()[i]; - printf(" %s [SHN=%s (%04x)][STT=%s][STB=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type), getSymbolBindingStr(symbol.symbol_binding)); + std::cout << " " << symbol.name << " [SHN=" << getSectionIndexStr(symbol.shn_index) << " (" << std::hex << std::setw(4) << std::setfill('0') << symbol.shn_index << ")][STT=" << getSymbolTypeStr(symbol.symbol_type) << "][STB=" << getSymbolBindingStr(symbol.symbol_binding) << "]" << std::endl; } } } diff --git a/programs/nstool/source/RomfsProcess.cpp b/programs/nstool/source/RomfsProcess.cpp index c2baf8c..cf68257 100644 --- a/programs/nstool/source/RomfsProcess.cpp +++ b/programs/nstool/source/RomfsProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -30,18 +32,15 @@ RomfsProcess::~RomfsProcess() void RomfsProcess::process() { - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - resolveRomfs(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) { displayHeader(); if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) displayFs(); } + if (mExtract) extractFs(); } @@ -87,19 +86,19 @@ void RomfsProcess::printTab(size_t tab) const { for (size_t i = 0; i < tab; i++) { - printf(" "); + std::cout << " "; } } void RomfsProcess::displayFile(const sFile& file, size_t tab) const { printTab(tab); - printf("%s", file.name.c_str()); + std::cout << file.name; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size); + std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")"; } - putchar('\n'); + std::cout << std::endl; } void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const @@ -107,7 +106,7 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const if (dir.name.empty() == false) { printTab(tab); - printf("%s\n", dir.name.c_str()); + std::cout << dir.name << std::endl; } for (size_t i = 0; i < dir.dir_list.size(); i++) @@ -122,11 +121,16 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const void RomfsProcess::displayHeader() { - printf("[RomFS]\n"); - printf(" DirNum: %" PRId64 "\n", (uint64_t)mDirNum); - printf(" FileNum: %" PRId64 "\n", (uint64_t)mFileNum); - if (mMountName.empty() == false) - printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : ""); + std::cout << "[RomFS]" << std::endl; + std::cout << " DirNum: " << std::dec << mDirNum << std::endl; + std::cout << " FileNum: " << std::dec << mFileNum << std::endl; + if (mMountName.empty() == false) + { + std::cout << " MountPoint: " << mMountName; + if (mMountName.at(mMountName.length()-1) != '/') + std::cout << "/"; + std::cout << std::endl; + } } void RomfsProcess::displayFs() @@ -156,7 +160,7 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) fnd::io::appendToPath(file_path, dir.file_list[i].name); if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) - printf("extract=[%s]\n", file_path.c_str()); + std::cout << "extract=[" << file_path << "]" << std::endl; outFile.open(file_path, outFile.Create); mFile->seek(dir.file_list[i].offset); @@ -254,6 +258,11 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) void RomfsProcess::resolveRomfs() { + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + // read header mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader)); diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index 41dcf19..b752787 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include "OffsetAdjustedIFile.h" @@ -25,28 +27,11 @@ XciProcess::~XciProcess() void XciProcess::process() { - fnd::Vec scratch; - - if (mFile == nullptr) - { - throw fnd::Exception(kModuleName, "No file reader set."); - } - - // read header page - mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage)); - - // allocate memory for and decrypt sXciHeader - scratch.alloc(sizeof(nn::hac::sXciHeader)); - nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), mKeyset->xci.header_key.key); + importHeader(); // validate header signature if (mVerify) - { validateXciSignature(); - } - - // deserialise header - mHdr.fromBytes(scratch.data(), scratch.size()); // display header if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) @@ -90,70 +75,90 @@ void XciProcess::setListFs(bool list_fs) mListFs = list_fs; } +void XciProcess::importHeader() +{ + fnd::Vec scratch; + + if (mFile == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + // read header page + mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage)); + + // allocate memory for and decrypt sXciHeader + scratch.alloc(sizeof(nn::hac::sXciHeader)); + nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), mKeyset->xci.header_key.key); + + // deserialise header + mHdr.fromBytes(scratch.data(), scratch.size()); +} + void XciProcess::displayHeader() { - printf("[XCI Header]\n"); - printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion()); - printf(" RomSize: %s", getRomSizeStr(mHdr.getRomSizeType())); + std::cout << "[XCI Header]" << std::endl; + std::cout << " CardHeaderVersion: " << std::dec << (uint32_t)mHdr.getCardHeaderVersion() << std::endl; + std::cout << " RomSize: " << getRomSizeStr(mHdr.getRomSizeType()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) - printf(" (0x%x)", mHdr.getRomSizeType()); - printf("\n"); - printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId()); - printf(" Flags: 0x%x\n", mHdr.getFlags()); + std::cout << " (0x" << std::hex << (uint32_t)mHdr.getRomSizeType() << ")"; + std::cout << std::endl; + std::cout << " PackageId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getPackageId() << std::endl; + std::cout << " Flags: 0x" << std::dec << (uint32_t)mHdr.getFlags() << std::endl; if (mHdr.getFlags() != 0) { for (uint32_t i = 0; i < 8; i++) { if (_HAS_BIT(mHdr.getFlags(), i)) { - printf(" %s\n", getHeaderFlagStr(i)); + std::cout << " " << getHeaderFlagStr(i) << std::endl; } } } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" InitialData:\n"); - printf(" KekIndex: %d\n", mHdr.getKekIndex()); - printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex()); - printf(" Hash:\n"); + std::cout << " InitialData:" << std::endl; + std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl; + std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl; + std::cout << " Hash:" << std::endl; fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes), 0x10, 6); } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Extended Header AES-IV:\n"); + std::cout << " Extended Header AES-IV:" << std::endl; fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4); } - printf(" SelSec: 0x%x\n", mHdr.getSelSec()); - printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key()); - printf(" SelKey: 0x%x\n", mHdr.getSelKey()); + std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl; + std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl; + std::cout << " SelKey: 0x" << std::hex << mHdr.getSelKey() << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage()); + std::cout << " RomAreaStartPage: 0x" << std::hex << mHdr.getRomAreaStartPage(); if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()) << ")"; + std::cout << std::endl; - printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage()); + std::cout << " BackupAreaStartPage: 0x" << std::hex << mHdr.getBackupAreaStartPage(); if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()) << ")"; + std::cout << std::endl; - printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage()); + std::cout << " ValidDataEndPage: 0x" << std::hex << mHdr.getValidDataEndPage(); if (mHdr.getValidDataEndPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage()) << ")"; + std::cout << std::endl; - printf(" LimArea: 0x%x", mHdr.getLimAreaPage()); + std::cout << " LimArea: 0x" << std::hex << mHdr.getLimAreaPage(); if (mHdr.getLimAreaPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage())); - printf("\n"); + std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage()) << ")"; + std::cout << std::endl; - printf(" PartitionFs Header:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress()); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize()); + std::cout << " PartitionFs Header:" << std::endl; + std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl; + std::cout << " Size: 0x" << std::hex << mHdr.getPartitionFsSize() << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf(" Hash:\n"); + std::cout << " Hash:" << std::endl; fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes), 0x10, 6); } } @@ -161,23 +166,23 @@ void XciProcess::displayHeader() if (mHdr.getFwVerMinor() != 0) { - printf("[XCI Extended Header]\n"); - printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor()); - printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1()); - printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1())); - printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead()); - printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead()); - printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite()); - printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite()); - printf(" FwMode: 0x%x\n", mHdr.getFwMode()); - printf(" Update Partition Info:\n"); -#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) - printf(" CUP Version: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion())); + std::cout << "[XCI Extended Header]" << std::endl; + std::cout << " FwVersion: v" << std::dec << mHdr.getFwVerMajor() << "." << mHdr.getFwVerMinor() << std::endl; + std::cout << " AccCtrl1: 0x" << std::hex << mHdr.getAccCtrl1() << std::endl; + std::cout << " CardClockRate: " << getCardClockRate(mHdr.getAccCtrl1()) << std::endl; + std::cout << " Wait1TimeRead: 0x" << std::hex << mHdr.getWait1TimeRead() << std::endl; + std::cout << " Wait2TimeRead: 0x" << std::hex << mHdr.getWait2TimeRead() << std::endl; + std::cout << " Wait1TimeWrite: 0x" << std::hex << mHdr.getWait1TimeWrite() << std::endl; + std::cout << " Wait2TimeWrite: 0x" << std::hex << mHdr.getWait2TimeWrite() << std::endl; + std::cout << " FwMode: 0x" << std::hex << mHdr.getFwMode() << std::endl; + std::cout << " Update Partition Info:" << std::endl; +#define _SPLIT_VER(ver) std::dec << ((ver>>26) & 0x3f) << "." << ((ver>>20) & 0x3f) << "." << ((ver>>16) & 0xf) << "." << (ver & 0xffff) + std::cout << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl; #undef _SPLIT_VER - printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId()); - printf(" Partition Hash: "); + std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl; + std::cout << " Partition Hash: "; fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8); - } + } } bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash) @@ -196,7 +201,7 @@ void XciProcess::validateXciSignature() fnd::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nn::hac::sXciHeader), calc_hash.bytes); if (fnd::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, fnd::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0) { - printf("[WARNING] XCI Header Signature: FAIL \n"); + std::cout << "[WARNING] XCI Header Signature: FAIL" << std::endl; } } @@ -204,7 +209,7 @@ void XciProcess::processRootPfs() { if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes) == false) { - printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n"); + std::cout << "[WARNING] XCI Root HFS0: FAIL (bad hash)" << std::endl; } mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE); mRootPfs.setListFs(mListFs); @@ -222,7 +227,7 @@ void XciProcess::processPartitionPfs() // this must be validated here because only the size of the root partiton header is known at verification time if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].hash_protected_size, rootPartitions[i].hash.bytes) == false) { - printf("[WARNING] XCI %s Partition HFS0: FAIL (bad hash)\n", rootPartitions[i].name.c_str()); + std::cout << "[WARNING] XCI " << rootPartitions[i].name << " Partition HFS0: FAIL (bad hash)" << std::endl; } PfsProcess tmp; diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index 32fc038..c3da185 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -62,6 +62,7 @@ private: PfsProcess mRootPfs; fnd::List mExtractInfo; + void importHeader(); void displayHeader(); bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash); void validateXciSignature(); From e7416b1c16641ba4b4d1ede26bd18b9a86cc632c Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 14 Aug 2018 15:23:02 +0800 Subject: [PATCH 10/50] [fnd] Add SimpleTextOutput::arrayToString() --- lib/libfnd/include/fnd/SimpleTextOutput.h | 2 ++ lib/libfnd/source/SimpleTextOutput.cpp | 40 ++++++++++++----------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/libfnd/include/fnd/SimpleTextOutput.h b/lib/libfnd/include/fnd/SimpleTextOutput.h index bbf8e73..ef0516f 100644 --- a/lib/libfnd/include/fnd/SimpleTextOutput.h +++ b/lib/libfnd/include/fnd/SimpleTextOutput.h @@ -1,4 +1,5 @@ #pragma once +#include #include namespace fnd @@ -10,6 +11,7 @@ namespace fnd static void hxdStyleDump(const byte_t* data, size_t len); static void hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len); static void hexDump(const byte_t* data, size_t len); + static std::string arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator); private: static const size_t kDefaultRowLen = 0x10; static const size_t kDefaultByteGroupingSize = 1; diff --git a/lib/libfnd/source/SimpleTextOutput.cpp b/lib/libfnd/source/SimpleTextOutput.cpp index 7dbc17d..c7f1582 100644 --- a/lib/libfnd/source/SimpleTextOutput.cpp +++ b/lib/libfnd/source/SimpleTextOutput.cpp @@ -1,5 +1,8 @@ -#include +#include +#include +#include #include +#include void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len, size_t row_len, size_t byte_grouping_size) { @@ -58,31 +61,30 @@ void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len) void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len) { - for (size_t i = 0; i < len; i++) + for (size_t i = 0; i < len; i += row_len) { - if ((i % row_len) == 0) - { - if (i > 0) - putchar('\n'); - for (size_t j = 0; j < indent_len; j++) - { - putchar(' '); - } - } - printf("%02X", data[i]); - if ((i+1) >= len) - { - putchar('\n'); - } - + for (size_t j = 0; j < indent_len; j++) + std::cout << " "; + std::cout << arrayToString(data+i, _MIN(len-i, row_len), true, "") << std::endl; } } void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len) { + std::cout << arrayToString(data, len, true, "") << std::endl; +} + +std::string fnd::SimpleTextOutput::arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator) +{ + std::stringstream ss; + + if (upper_case) + ss << std::uppercase; for (size_t i = 0; i < len; i++) { - printf("%02X", data[i]); + ss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)data[i]; + if (i+1 < len) + ss << separator; } - putchar('\n'); + return ss.str(); } \ No newline at end of file From bf5f90a4b8e6e0cada5b7a83946c5641e486049e Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 14 Aug 2018 15:24:10 +0800 Subject: [PATCH 11/50] [fnd::ecdsa] Fix bug in sEcdsa240Point::operator=(). --- lib/libfnd/include/fnd/ecdsa.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libfnd/include/fnd/ecdsa.h b/lib/libfnd/include/fnd/ecdsa.h index e06880e..04cfcff 100644 --- a/lib/libfnd/include/fnd/ecdsa.h +++ b/lib/libfnd/include/fnd/ecdsa.h @@ -21,8 +21,8 @@ namespace fnd void operator=(const sEcdsa240Point& other) { - memcpy(this->r, r, kEcdsa240Size); - memcpy(this->s, s, kEcdsa240Size); + memcpy(this->r, other.r, kEcdsa240Size); + memcpy(this->s, other.s, kEcdsa240Size); } bool operator==(const sEcdsa240Point& other) const From 456a821df4cd4a71e48c2e06729d271cd6729cfb Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 14 Aug 2018 15:24:43 +0800 Subject: [PATCH 12/50] [nstool] Fix typos. --- programs/nstool/source/PkiCertProcess.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/nstool/source/PkiCertProcess.cpp b/programs/nstool/source/PkiCertProcess.cpp index 505c7a1..bc71e09 100644 --- a/programs/nstool/source/PkiCertProcess.cpp +++ b/programs/nstool/source/PkiCertProcess.cpp @@ -104,7 +104,7 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData Date: Tue, 14 Aug 2018 15:25:33 +0800 Subject: [PATCH 13/50] [nstool] Replaced _HEXDUMP_L macro with a method from fnd. --- programs/nstool/source/CnmtProcess.cpp | 14 +++---------- programs/nstool/source/NcaProcess.cpp | 28 +++++++++----------------- programs/nstool/source/NroProcess.cpp | 11 ++-------- programs/nstool/source/NsoProcess.cpp | 19 ++++------------- programs/nstool/source/XciProcess.cpp | 11 +++++----- 5 files changed, 24 insertions(+), 59 deletions(-) diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index 1a8bc0a..f40caab 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -67,7 +67,6 @@ void CnmtProcess::importCnmt() void CnmtProcess::displayCnmt() { #define _SPLIT_VER(ver) (uint32_t)((ver>>26) & 0x3f) << "." << (uint32_t)((ver>>20) & 0x3f) << "." << (uint32_t)((ver>>16) & 0xf) << "." << (uint32_t)(ver & 0xffff) -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) std::cout << "[ContentMeta]" << std::endl; std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << std::endl; @@ -109,13 +108,9 @@ void CnmtProcess::displayCnmt() const nn::hac::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i]; std::cout << " " << std::dec << i << std::endl; std::cout << " Type: " << getContentTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl; - std::cout << " Id: "; - _HEXDUMP_L(info.nca_id, nn::hac::cnmt::kContentIdLen); - std::cout << std::endl; + std::cout << " Id: " << fnd::SimpleTextOutput::arrayToString(info.nca_id, nn::hac::cnmt::kContentIdLen, false, "") << std::endl; std::cout << " Size: 0x" << std::hex << info.size << std::endl; - std::cout << " Hash: "; - _HEXDUMP_L(info.hash.bytes, sizeof(info.hash)); - std::cout << std::endl; + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(info.hash.bytes, sizeof(info.hash), false, "") << std::endl; } } if (mCnmt.getContentMetaInfo().size() > 0) @@ -134,11 +129,8 @@ void CnmtProcess::displayCnmt() } } - std::cout << " Digest: "; - _HEXDUMP_L(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen); - std::cout << std::endl; + std::cout << " Digest: " << fnd::SimpleTextOutput::arrayToString(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen, false, "") << std::endl; -#undef _HEXDUMP_L #undef _SPLIT_VER } diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 1c98593..90de628 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -239,17 +239,14 @@ void NcaProcess::generateNcaBodyEncryptionKeys() if (mBodyKeys.aes_ctr.isSet) { std::cout << "[NCA Body Key]" << std::endl; - std::cout << " AES-CTR Key: "; - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); + std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; } if (mBodyKeys.aes_xts.isSet) { std::cout << "[NCA Body Key]" << std::endl; - std::cout << " AES-XTS Key0: "; - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var)); - std::cout << " AES-XTS Key1: "; - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var)); + std::cout << " AES-XTS Key0: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; + std::cout << " AES-XTS Key1: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; } } @@ -434,11 +431,9 @@ void NcaProcess::displayHeader() #undef _SPLIT_VER if (mHdr.hasRightsId()) { - std::cout << " RightsId: "; - fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen); + std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl; } -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0) if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { std::cout << " Key Area:" << std::endl; @@ -449,12 +444,11 @@ void NcaProcess::displayHeader() { std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mBodyKeys.keak_list[i].index << " | "; - _HEXDUMP_L(mBodyKeys.keak_list[i].enc.key, 16); + std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].enc.key, 16, false, "") << " | "; - std::cout << " | "; if (mBodyKeys.keak_list[i].decrypted) - _HEXDUMP_L(mBodyKeys.keak_list[i].dec.key, 16); + std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].dec.key, 16, false, ""); else std::cout << " "; @@ -462,7 +456,6 @@ void NcaProcess::displayHeader() } std::cout << " <--------------------------------------------------------------------------->" << std::endl; } -#undef _HEXDUMP_L if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { @@ -480,10 +473,9 @@ void NcaProcess::displayHeader() std::cout << " Enc. Type: " << getEncryptionTypeStr(info.enc_type) << std::endl; if (info.enc_type == nn::hac::nca::CRYPT_AESCTR) { - std::cout << " AES-CTR: "; fnd::aes::sAesIvCtr ctr; fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); - fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(fnd::aes::sAesIvCtr)); + std::cout << " AES-CTR: " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, "") << std::endl; } if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY) { @@ -503,16 +495,14 @@ void NcaProcess::displayHeader() std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++) { - std::cout << " Master Hash " << std::dec << j << ": "; - fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash)); + std::cout << " Master Hash " << std::dec << j << ": " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl; } } else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256) { HashTreeMeta& hash_hdr = info.hash_tree_meta; std::cout << " HierarchicalSha256 Header:" << std::endl; - std::cout << " Master Hash: "; - fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash)); + std::cout << " Master Hash: " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl; std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; std::cout << " Hash Layer:" << std::endl; std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl; diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp index e9c73b3..577cc95 100644 --- a/programs/nstool/source/NroProcess.cpp +++ b/programs/nstool/source/NroProcess.cpp @@ -137,14 +137,9 @@ void NroProcess::importCodeSegments() void NroProcess::displayHeader() { -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0) std::cout << "[NRO Header]" << std::endl; - std::cout << " RoCrt: "; - _HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize); - std::cout << std::endl; - std::cout << " ModuleId: "; - _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize); - std::cout << std::endl; + std::cout << " RoCrt: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize, false, "") << std::endl; + std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize, false, "") << std::endl; std::cout << " NroSize: 0x" << std::hex << mHdr.getNroSize() << std::endl; std::cout << " Program Sections:" << std::endl; std::cout << " .text:" << std::endl; @@ -170,8 +165,6 @@ void NroProcess::displayHeader() std::cout << " Size: 0x" << std::hex << mHdr.getDataInfo().size << std::endl; std::cout << " .bss:" << std::endl; std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl; - -#undef _HEXDUMP_L } void NroProcess::processRoMeta() diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index 9f40548..c99cd78 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -175,12 +175,8 @@ void NsoProcess::importCodeSegments() void NsoProcess::displayNsoHeader() { -#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) std::cout << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)var[a__a__A]; } while(0) - std::cout << "[NSO Header]" << std::endl; - std::cout << " ModuleId: "; - _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize); - std::cout << std::endl; + std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize, false, "") << std::endl; if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { std::cout << " Program Segments:" << std::endl; @@ -203,18 +199,14 @@ void NsoProcess::displayNsoHeader() std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl; if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - std::cout << " Hash: "; - _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32); - std::cout << std::endl; + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getTextSegmentInfo().hash.bytes, 32, false, "") << std::endl; } std::cout << " .ro:" << std::endl; std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl; if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - std::cout << " Hash: "; - _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32); - std::cout << std::endl; + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoSegmentInfo().hash.bytes, 32, false, "") << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { @@ -234,13 +226,10 @@ void NsoProcess::displayNsoHeader() std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl; if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - std::cout << " Hash: "; - _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32); - std::cout << std::endl; + std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getDataSegmentInfo().hash.bytes, 32, false, "") << std::endl; } std::cout << " .bss:" << std::endl; std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl; -#undef _HEXDUMP_L } void NsoProcess::processRoMeta() diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index b752787..b535204 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -121,12 +121,13 @@ void XciProcess::displayHeader() std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl; std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl; std::cout << " Hash:" << std::endl; - fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes), 0x10, 6); + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, "") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, "") << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { std::cout << " Extended Header AES-IV:" << std::endl; - fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4); + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, "") << std::endl; } std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl; std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl; @@ -159,7 +160,8 @@ void XciProcess::displayHeader() if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { std::cout << " Hash:" << std::endl; - fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes), 0x10, 6); + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, "") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, "") << std::endl; } } @@ -180,8 +182,7 @@ void XciProcess::displayHeader() std::cout << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl; #undef _SPLIT_VER std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl; - std::cout << " Partition Hash: "; - fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8); + std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, "") << std::endl; } } From 7afd6a582b9370c7c3ba278945de148d47ea9b52 Mon Sep 17 00:00:00 2001 From: jakcron Date: Wed, 15 Aug 2018 17:14:51 +0800 Subject: [PATCH 14/50] Bump patch version to 1 --- programs/nstool/source/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/nstool/source/version.h b/programs/nstool/source/version.h index d294cec..f2109d4 100644 --- a/programs/nstool/source/version.h +++ b/programs/nstool/source/version.h @@ -1,5 +1,5 @@ #pragma once #define VER_MAJOR 1 #define VER_MINOR 0 -#define VER_PATCH 0 +#define VER_PATCH 1 #define AUTHORS "jakcron" \ No newline at end of file From 9b759b8d35f570a098f2e97271c5c14bb94ff9d1 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 20 Aug 2018 19:23:55 +0800 Subject: [PATCH 15/50] [fnd::ecdsa] Fix bug in copy operator. --- lib/libfnd/include/fnd/ecdsa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libfnd/include/fnd/ecdsa.h b/lib/libfnd/include/fnd/ecdsa.h index 04cfcff..af38511 100644 --- a/lib/libfnd/include/fnd/ecdsa.h +++ b/lib/libfnd/include/fnd/ecdsa.h @@ -43,7 +43,7 @@ namespace fnd void operator=(const sEcdsa240PrivateKey& other) { - memcpy(this->k, k, kEcdsa240Size); + memcpy(this->k, other.k, kEcdsa240Size); } bool operator==(const sEcdsa240PrivateKey& other) const From 12ad762666944d609f47ad850326b55f700facf7 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 20 Aug 2018 19:24:23 +0800 Subject: [PATCH 16/50] [fnd::ecdsa] Add sEcdsa240Key/ --- lib/libfnd/include/fnd/ecdsa.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/libfnd/include/fnd/ecdsa.h b/lib/libfnd/include/fnd/ecdsa.h index af38511..aa9e48b 100644 --- a/lib/libfnd/include/fnd/ecdsa.h +++ b/lib/libfnd/include/fnd/ecdsa.h @@ -56,6 +56,28 @@ namespace fnd return !operator==(other); } }; + + struct sEcdsa240Key + { + sEcdsa240Point pub; + sEcdsa240PrivateKey pvt; + + void operator=(const sEcdsa240Key& other) + { + this->pub = other.pub; + this->pvt = other.pvt; + } + + bool operator==(const sEcdsa240Key& other) const + { + return this->pub == other.pub && this->pvt == other.pvt; + } + + bool operator!=(const sEcdsa240Key& other) const + { + return !operator==(other); + } + }; #pragma pack (pop) } } From c026aeee92987ce308956243efc4ccfc7336f7df Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 20 Aug 2018 19:25:10 +0800 Subject: [PATCH 17/50] [fnd] Add SImpleTextOutput::stringToArray() --- lib/libfnd/include/fnd/SimpleTextOutput.h | 3 +++ lib/libfnd/source/SimpleTextOutput.cpp | 27 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/libfnd/include/fnd/SimpleTextOutput.h b/lib/libfnd/include/fnd/SimpleTextOutput.h index ef0516f..15c3c8e 100644 --- a/lib/libfnd/include/fnd/SimpleTextOutput.h +++ b/lib/libfnd/include/fnd/SimpleTextOutput.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace fnd { @@ -12,6 +13,8 @@ namespace fnd static void hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len); static void hexDump(const byte_t* data, size_t len); static std::string arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator); + static void stringToArray(const std::string& str, fnd::Vec& array); + private: static const size_t kDefaultRowLen = 0x10; static const size_t kDefaultByteGroupingSize = 1; diff --git a/lib/libfnd/source/SimpleTextOutput.cpp b/lib/libfnd/source/SimpleTextOutput.cpp index c7f1582..1ee71ce 100644 --- a/lib/libfnd/source/SimpleTextOutput.cpp +++ b/lib/libfnd/source/SimpleTextOutput.cpp @@ -87,4 +87,31 @@ std::string fnd::SimpleTextOutput::arrayToString(const byte_t* data, size_t len, ss << separator; } return ss.str(); +} + +inline byte_t charToByte(char chr) +{ + if (chr >= 'a' && chr <= 'f') + return (chr - 'a') + 0xa; + else if (chr >= 'A' && chr <= 'F') + return (chr - 'A') + 0xa; + else if (chr >= '0' && chr <= '9') + return chr - '0'; + return 0; +} + +void fnd::SimpleTextOutput::stringToArray(const std::string& str, fnd::Vec& array) +{ + size_t size = str.size(); + if ((size % 2)) + { + return; + } + + array.alloc(size/2); + + for (size_t i = 0; i < array.size(); i++) + { + array[i] = (charToByte(str[i * 2]) << 4) | charToByte(str[(i * 2) + 1]); + } } \ No newline at end of file From d4435b7559719589c0cfdbe3d150c658a24a9dac Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 20 Aug 2018 19:26:03 +0800 Subject: [PATCH 18/50] [nstool] Add KeyConfiguration. --- programs/nstool/source/KeyConfiguration.cpp | 343 ++++++++++++++++++++ programs/nstool/source/KeyConfiguration.h | 206 ++++++++++++ 2 files changed, 549 insertions(+) create mode 100644 programs/nstool/source/KeyConfiguration.cpp create mode 100644 programs/nstool/source/KeyConfiguration.h diff --git a/programs/nstool/source/KeyConfiguration.cpp b/programs/nstool/source/KeyConfiguration.cpp new file mode 100644 index 0000000..0a4f7b1 --- /dev/null +++ b/programs/nstool/source/KeyConfiguration.cpp @@ -0,0 +1,343 @@ +#include "KeyConfiguration.h" +#include +#include +#include +#include + +KeyConfiguration::KeyConfiguration() +{ + clearGeneralKeyConfiguration(); + clearNcaExternalKeys(); +} + +void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) +{ + clearGeneralKeyConfiguration(); + + fnd::ResourceFileReader res; + try + { + res.processFile(path); + } + catch (const fnd::Exception&) + { + throw fnd::Exception(kModuleName, "Failed to open key file: " + path); + } + + // internally used sources + fnd::aes::sAes128Key master_key[kMasterKeyNum] = { kNullAesKey }; + fnd::aes::sAes128Key package2_key_source = kNullAesKey; + fnd::aes::sAes128Key ticket_titlekek_source = kNullAesKey; + fnd::aes::sAes128Key key_area_key_source[kNcaKeakNum] = { kNullAesKey, kNullAesKey, kNullAesKey }; + fnd::aes::sAes128Key aes_kek_generation_source = kNullAesKey; + fnd::aes::sAes128Key aes_key_generation_source = kNullAesKey; + fnd::aes::sAes128Key nca_header_kek_source = kNullAesKey; + fnd::aes::sAesXts128Key nca_header_key_source = kNullAesXtsKey; + fnd::rsa::sRsa4096Key pki_root_sign_key = kNullRsa4096Key; + +#define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2)) +#define _CONCAT_3_STRINGS(str1, str2, str3) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3) + + std::string key,val; + fnd::Vec dec_array; + +#define _SAVE_KEYDATA(key_name, array, len) \ + key = (key_name); \ + val = res[key]; \ + if (val.empty() == false) { \ + fnd::SimpleTextOutput::stringToArray(val, dec_array); \ + if (dec_array.size() != len) \ + throw fnd::Exception(kModuleName, "Key: \"" + key_name + "\" has incorrect length"); \ + memcpy(array, dec_array.data(), len); \ + } + + for (size_t nameidx = 0; nameidx < kNameVariantNum; nameidx++) + { + // import sources + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kKeyStr, kSourceStr), package2_key_source.key, 0x10); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[nameidx], kSourceStr), ticket_titlekek_source.key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kSourceStr), key_area_key_source[0].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kSourceStr), key_area_key_source[1].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kSourceStr), key_area_key_source[2].key, 0x10); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKekGenBase[nameidx], kSourceStr), aes_kek_generation_source.key, 0x10); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKeyGenBase[nameidx], kSourceStr), aes_key_generation_source.key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20); + + // Store Key Variants/Derivatives + for (size_t mkeyidx = 0; mkeyidx < kMasterKeyNum; mkeyidx++) + { + + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kMasterBase[nameidx], kKeyStr, kKeyIndex[mkeyidx]), master_key[mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg1Base[nameidx], kKeyStr, kKeyIndex[mkeyidx]), mPkg1Key[mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kKeyStr, kKeyIndex[mkeyidx]), mPkg2Key[mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[nameidx], kKeyIndex[mkeyidx]), mETicketCommonKey[mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[0][mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[1][mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[2][mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[0][mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[1][mkeyidx].key, 0x10); + _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[2][mkeyidx].key, 0x10); + } + + // store nca header key + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[nameidx], kKeyStr), mNcaHeaderKey.key[0], 0x20); + + // store xci header key + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kKeyStr), mXciHeaderKey.key, 0x10); + + // store rsa keys + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[nameidx], kRsaKeyPrivate), mNcaHeader0SignKey.priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[nameidx], kRsaKeyModulus), mNcaHeader0SignKey.modulus, fnd::rsa::kRsa2048Size); + + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyPrivate), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyModulus), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size); + + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyPrivate), mAcidSignKey.priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyModulus), mAcidSignKey.modulus, fnd::rsa::kRsa2048Size); + + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyPrivate), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyModulus), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size); + + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyPrivate), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size); + _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyModulus), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size); + } + +#undef _SAVE_KEYDATA +#undef _CONCAT_3_STRINGS +#undef _CONCAT_2_STRINGS + + // Derive keys + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (master_key[i] != kNullAesKey) + { + if (aes_kek_generation_source != kNullAesKey && aes_key_generation_source != kNullAesKey) + { + if (i == 0 && nca_header_kek_source != kNullAesKey && nca_header_key_source != kNullAesXtsKey) + { + if (mNcaHeaderKey == kNullAesXtsKey) + { + fnd::aes::sAes128Key nca_header_kek; + nn::hac::AesKeygen::generateKey(nca_header_kek.key, aes_kek_generation_source.key, nca_header_kek_source.key, aes_key_generation_source.key, master_key[i].key); + nn::hac::AesKeygen::generateKey(mNcaHeaderKey.key[0], nca_header_key_source.key[0], nca_header_kek.key); + nn::hac::AesKeygen::generateKey(mNcaHeaderKey.key[1], nca_header_key_source.key[1], nca_header_kek.key); + } + } + + for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++) + { + if (key_area_key_source[j] != kNullAesKey && mNcaKeyAreaEncryptionKey[j][i] == kNullAesKey) + { + nn::hac::AesKeygen::generateKey(mNcaKeyAreaEncryptionKey[j][i].key, aes_kek_generation_source.key, key_area_key_source[j].key, aes_key_generation_source.key, master_key[i].key); + } + } + } + + if (ticket_titlekek_source != kNullAesKey && mETicketCommonKey[i] == kNullAesKey) + { + nn::hac::AesKeygen::generateKey(mETicketCommonKey[i].key, ticket_titlekek_source.key, master_key[i].key); + } + if (package2_key_source != kNullAesKey && mPkg2Key[i] == kNullAesKey) + { + nn::hac::AesKeygen::generateKey(mPkg2Key[i].key, package2_key_source.key, master_key[i].key); + } + } + } + + // populate pki root keys + if (pki_root_sign_key != kNullRsa4096Key) + { + sPkiRootKey tmp; + + tmp.name = nn::pki::sign::kRootIssuerStr; + tmp.key_type = nn::pki::sign::SIGN_ALGO_RSA4096; + tmp.rsa4096_key = pki_root_sign_key; + + mPkiRootKeyList.addElement(tmp); + } +} + + +void KeyConfiguration::clearGeneralKeyConfiguration() +{ + mAcidSignKey = kNullRsa2048Key; + mPkg2SignKey = kNullRsa2048Key; + mNcaHeader0SignKey = kNullRsa2048Key; + mXciHeaderSignKey = kNullRsa2048Key; + mPkiRootKeyList.clear(); + + mNcaHeaderKey = kNullAesXtsKey; + mXciHeaderKey = kNullAesKey; + + for (size_t i = 0; i < kMasterKeyNum; i++) + { + mPkg1Key[i] = kNullAesKey; + mPkg2Key[i] = kNullAesKey; + mETicketCommonKey[i] = kNullAesKey; + for (size_t j = 0; j < kNcaKeakNum; j++) + { + mNcaKeyAreaEncryptionKey[j][i] = kNullAesKey; + mNcaKeyAreaEncryptionKey[j][i] = kNullAesKey; + } + } +} + +void KeyConfiguration::clearNcaExternalKeys() +{ + mNcaExternalContentKeyList.clear(); +} + +bool KeyConfiguration::getNcaHeaderKey(fnd::aes::sAesXts128Key& key) const +{ + return copyOutKeyResourceIfExists(mNcaHeaderKey, key, kNullAesXtsKey); +} + +bool KeyConfiguration::getNcaHeader0SignKey(fnd::rsa::sRsa2048Key& key) const +{ + return copyOutKeyResourceIfExists(mNcaHeader0SignKey, key, kNullRsa2048Key); +} + +bool KeyConfiguration::getAcidSignKey(fnd::rsa::sRsa2048Key& key) const +{ + return copyOutKeyResourceIfExists(mAcidSignKey, key, kNullRsa2048Key); +} + +bool KeyConfiguration::getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const +{ + if (keak_type >= kNcaKeakNum || masterkey_index >= kMasterKeyNum) + { + return false; + } + return copyOutKeyResourceIfExists(mNcaKeyAreaEncryptionKey[keak_type][masterkey_index], key, kNullAesKey); +} + +bool KeyConfiguration::getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const +{ + if (keak_type >= kNcaKeakNum || masterkey_index >= kMasterKeyNum) + { + return false; + } + return copyOutKeyResourceIfExists(mNcaKeyAreaEncryptionKeyHw[keak_type][masterkey_index], key, kNullAesKey); +} + +void KeyConfiguration::addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key) +{ + sNcaExternalContentKey tmp; + memcpy(tmp.rights_id.data, rights_id, nn::hac::nca::kRightsIdLen); + tmp.key = key; + + if (mNcaExternalContentKeyList.hasElement(tmp)) + return; + + mNcaExternalContentKeyList.addElement(tmp); +} + +bool KeyConfiguration::getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const +{ + sRightsId id; + bool res_exists = false; + + memcpy(id.data, rights_id, nn::hac::nca::kRightsIdLen); + for (size_t i = 0; i < mNcaExternalContentKeyList.size(); i++) + { + if (mNcaExternalContentKeyList[i].rights_id == id) + { + res_exists = true; + key = mNcaExternalContentKeyList[i].key; + break; + } + } + + return res_exists; +} + +bool KeyConfiguration::getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const +{ + if (masterkey_index >= kMasterKeyNum) + { + return false; + } + return copyOutKeyResourceIfExists(mPkg1Key[masterkey_index], key, kNullAesKey); +} + +bool KeyConfiguration::getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const +{ + if (masterkey_index >= kMasterKeyNum) + { + return false; + } + return copyOutKeyResourceIfExists(mPkg2Key[masterkey_index], key, kNullAesKey); +} + +bool KeyConfiguration::getPkg2SignKey(fnd::rsa::sRsa2048Key& key) const +{ + return copyOutKeyResourceIfExists(mPkg2SignKey, key, kNullRsa2048Key); +} + +bool KeyConfiguration::getXciHeaderSignKey(fnd::rsa::sRsa2048Key& key) const +{ + return copyOutKeyResourceIfExists(mXciHeaderSignKey, key, kNullRsa2048Key); +} + +bool KeyConfiguration::getXciHeaderKey(fnd::aes::sAes128Key& key) const +{ + return copyOutKeyResourceIfExists(mXciHeaderKey, key, kNullAesKey); +} + +bool KeyConfiguration::getETicketCommonKey(byte_t masterkey_index, fnd::aes::sAes128Key& key) const +{ + if (masterkey_index >= kMasterKeyNum) + { + return false; + } + return copyOutKeyResourceIfExists(mETicketCommonKey[masterkey_index], key, kNullAesKey); +} + +bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa4096Key& key) const +{ + bool res_exists = false; + for (size_t i = 0; i < mPkiRootKeyList.size(); i++) + { + if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_RSA4096) + { + res_exists = true; + key = mPkiRootKeyList[i].rsa4096_key; + break; + } + } + + return res_exists; +} + +bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa2048Key& key) const +{ + bool res_exists = false; + for (size_t i = 0; i < mPkiRootKeyList.size(); i++) + { + if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_RSA2048) + { + res_exists = true; + key = mPkiRootKeyList[i].rsa2048_key; + break; + } + } + + return res_exists; +} + +bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::ecdsa::sEcdsa240Key& key) const +{ + bool res_exists = false; + for (size_t i = 0; i < mPkiRootKeyList.size(); i++) + { + if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_ECDSA240) + { + res_exists = true; + key = mPkiRootKeyList[i].ecdsa240_key; + break; + } + } + + return res_exists; +} \ No newline at end of file diff --git a/programs/nstool/source/KeyConfiguration.h b/programs/nstool/source/KeyConfiguration.h new file mode 100644 index 0000000..f5197cb --- /dev/null +++ b/programs/nstool/source/KeyConfiguration.h @@ -0,0 +1,206 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class KeyConfiguration +{ +public: + KeyConfiguration(); + + void importHactoolGenericKeyfile(const std::string& path); + //void importHactoolTitleKeyfile(const std::string& path); + + void clearGeneralKeyConfiguration(); + void clearNcaExternalKeys(); + + // nca keys + bool getNcaHeaderKey(fnd::aes::sAesXts128Key& key) const; + bool getNcaHeader0SignKey(fnd::rsa::sRsa2048Key& key) const; + bool getAcidSignKey(fnd::rsa::sRsa2048Key& key) const; + bool getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const; + bool getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const; + + // external content keys + void addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key); + bool getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const; + + // pkg1/pkg2 + bool getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; + bool getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; + bool getPkg2SignKey(fnd::rsa::sRsa2048Key& key) const; + + // xci keys + bool getXciHeaderSignKey(fnd::rsa::sRsa2048Key& key) const; + bool getXciHeaderKey(fnd::aes::sAes128Key& key) const; + + // ticket + bool getETicketCommonKey(byte_t masterkey_index, fnd::aes::sAes128Key& key) const; + + // pki + bool getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa4096Key& key) const; + bool getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa2048Key& key) const; + bool getPkiRootSignKey(const std::string& root_name, fnd::ecdsa::sEcdsa240Key& key) const; +private: + const std::string kModuleName = "KeyConfiguration"; + const fnd::aes::sAes128Key kNullAesKey = {{0}}; + const fnd::aes::sAesXts128Key kNullAesXtsKey = {{{0}}}; + const fnd::rsa::sRsa4096Key kNullRsa4096Key = {{0}, {0}, {0}}; + const fnd::rsa::sRsa2048Key kNullRsa2048Key = {{0}, {0}, {0}}; + static const size_t kMasterKeyNum = 0x20; + static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum; + + // keynames + enum NameVariantIndex + { + NNTOOLS, + LEGACY_HACTOOL, + LEGACY_0 + }; + static const size_t kNameVariantNum = 3; + const std::string kMasterBase[kNameVariantNum] = { "master", "master", "master" }; + const std::string kPkg1Base[kNameVariantNum] = { "package1", "package1", "package1" }; + const std::string kPkg2Base[kNameVariantNum] = { "package2", "package2", "package2" }; + const std::string kXciHeaderBase[kNameVariantNum] = { "xci_header", "xci_header", "xci_header" }; + const std::string kNcaHeaderBase[kNameVariantNum] = { "nca_header", "header", "nca_header" }; + const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" }; + const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" }; + const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" }; + const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_body_keak", "key_area_key", "nca_body_keak" }; + const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_body_keakhw", "key_area_hw_key", "nca_body_keakhw" }; + const std::string kKekGenBase[kNameVariantNum] = { "aes_kek_generation", "aes_kek_generation", "aes_kek_generation" }; + const std::string kKeyGenBase[kNameVariantNum] = { "aes_key_generation", "aes_key_generation", "aes_key_generation" }; + + // misc str + const std::string kKeyStr = "key"; + const std::string kKekStr = "kek"; + const std::string kSourceStr = "source"; + const std::string kRsaKeyModulus = "sign_key_modulus"; + const std::string kRsaKeyPrivate = "sign_key_private"; + const std::string kNcaKeyAreaKeyIndexStr[kNcaKeakNum] = { "application", "ocean", "system" }; + const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"}; + + struct sRightsId + { + byte_t data[nn::hac::nca::kRightsIdLen]; + + void operator=(const sRightsId& other) + { + memcpy(this->data, other.data, nn::hac::nca::kRightsIdLen); + } + + bool operator==(const sRightsId& other) const + { + return memcmp(this->data, other.data, nn::hac::nca::kRightsIdLen) == 0; + } + + bool operator!=(const sRightsId& other) const + { + return !(operator==(other)); + } + }; + + struct sNcaExternalContentKey + { + sRightsId rights_id; + fnd::aes::sAes128Key key; + + void operator=(const sNcaExternalContentKey& other) + { + rights_id = other.rights_id; + key = other.key; + } + + bool operator==(const sNcaExternalContentKey& other) const + { + return (rights_id == other.rights_id) \ + && (key == other.key); + } + + bool operator!=(const sNcaExternalContentKey& other) const + { + return !(operator==(other)); + } + }; + + struct sPkiRootKey + { + std::string name; + nn::pki::sign::SignatureAlgo key_type; + fnd::rsa::sRsa4096Key rsa4096_key; + fnd::rsa::sRsa2048Key rsa2048_key; + fnd::ecdsa::sEcdsa240Key ecdsa240_key; + + void operator=(const sPkiRootKey& other) + { + name = other.name; + key_type = other.key_type; + rsa4096_key = other.rsa4096_key; + rsa2048_key = other.rsa2048_key; + ecdsa240_key = other.ecdsa240_key; + } + + bool operator==(const sPkiRootKey& other) const + { + return (name == other.name) \ + && (key_type == other.key_type) \ + && (rsa4096_key == other.rsa4096_key) \ + && (rsa2048_key == other.rsa2048_key) \ + && (ecdsa240_key == other.ecdsa240_key); + } + + bool operator!=(const sPkiRootKey& other) const + { + return !(operator==(other)); + } + }; + + + /* general key config */ + // acid + fnd::rsa::sRsa2048Key mAcidSignKey; + + // pkg1 and pkg2 + fnd::aes::sAes128Key mPkg1Key[kMasterKeyNum]; + fnd::rsa::sRsa2048Key mPkg2SignKey; + fnd::aes::sAes128Key mPkg2Key[kMasterKeyNum]; + + // nca + fnd::rsa::sRsa2048Key mNcaHeader0SignKey; + fnd::aes::sAesXts128Key mNcaHeaderKey; + fnd::aes::sAes128Key mNcaKeyAreaEncryptionKey[kNcaKeakNum][kMasterKeyNum]; + fnd::aes::sAes128Key mNcaKeyAreaEncryptionKeyHw[kNcaKeakNum][kMasterKeyNum]; + + // xci + fnd::rsa::sRsa2048Key mXciHeaderSignKey; + fnd::aes::sAes128Key mXciHeaderKey; + + // ticket + fnd::aes::sAes128Key mETicketCommonKey[kMasterKeyNum]; + + // pki + fnd::List mPkiRootKeyList; + + /* Nca External Keys */ + fnd::List mNcaExternalContentKeyList; + + template + bool copyOutKeyResourceIfExists(const T& src, T& dst, const T& null_sample) const + { + bool resource_exists = false; + + if (src != null_sample) + { + resource_exists = true; + dst = src; + } + + return resource_exists; + } +}; \ No newline at end of file From 67a13b9d34dbfc479d042a962c35af6a81fd2f42 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 20 Aug 2018 19:56:28 +0800 Subject: [PATCH 19/50] [nstool] First stage integrate KeyConfiguration --- programs/nstool/source/UserSettings.cpp | 285 ++++++------------------ programs/nstool/source/UserSettings.h | 13 +- programs/nstool/source/nstool.h | 17 +- 3 files changed, 90 insertions(+), 225 deletions(-) diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index b556caa..a587ede 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -1,6 +1,7 @@ #include "UserSettings.h" #include "version.h" #include "PkiValidator.h" +#include "KeyConfiguration.h" #include #include #include @@ -385,36 +386,25 @@ void UserSettings::populateCmdArgs(const std::vector& arg_list, sCm void UserSettings::populateKeyset(sCmdArgs& args) { - fnd::aes::sAes128Key zeros_aes_key; - fnd::aes::sAesXts128Key zeros_aes_xts_key; - memset((void*)&zeros_aes_key, 0, sizeof(fnd::aes::sAes128Key)); - memset((void*)&zeros_aes_xts_key, 0, sizeof(fnd::aes::sAesXts128Key)); memset((void*)&mKeyset, 0, sizeof(sKeyset)); - fnd::ResourceFileReader res; if (args.keyset_path.isSet) { - res.processFile(*args.keyset_path); + mKeyCfg.importHactoolGenericKeyfile(*args.keyset_path); } else { // open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set). - std::string home; - if (home.empty()) fnd::io::getEnvironVar(home, "HOME"); - if (home.empty()) fnd::io::getEnvironVar(home, "USERPROFILE"); - if (home.empty()) return; - - const std::string kKeysetNameStr[2] = {"prod.keys", "dev.keys"}; - const std::string kHomeSwitchDirStr = ".switch"; - std::string keyset_path; - fnd::io::appendToPath(keyset_path, home); - fnd::io::appendToPath(keyset_path, kHomeSwitchDirStr); - fnd::io::appendToPath(keyset_path, kKeysetNameStr[args.devkit_keys.isSet ? *args.devkit_keys : 0]); + getSwitchPath(keyset_path); + if (keyset_path.empty()) + return; + + fnd::io::appendToPath(keyset_path, kGeneralKeyfileName[args.devkit_keys.isSet]); try { - res.processFile(keyset_path); + mKeyCfg.importHactoolGenericKeyfile(keyset_path); } catch (const fnd::Exception&) { @@ -422,132 +412,44 @@ void UserSettings::populateKeyset(sCmdArgs& args) } } - - // suffix - const std::string kKeyStr = "key"; - const std::string kKekStr = "kek"; - const std::string kSourceStr = "source"; - const std::string kRsaKeySuffix[2] = {"sign_key_private", "sign_key_modulus"}; - const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"}; - // keyname bases - const std::string kMasterBase = "master"; - const std::string kPackage1Base = "package1"; - const std::string kPackage2Base = "package2"; - const std::string kXciHeaderBase = "xci_header"; - const std::string kNcaHeaderBase[2] = {"header", "nca_header"}; - const std::string kKekGenSource = "aes_kek_generation"; - const std::string kKeyGenSource = "aes_key_generation"; - const std::string kAcidBase = "acid"; - const std::string kPkiRootBase = "pki_root"; - const std::string kTicketCommonKeyBase[2] = { "titlekek", "ticket_commonkey" }; - const std::string kNcaBodyBase[2] = {"key_area_key", "nca_body_keak"}; - const std::string kNcaBodyKeakIndexName[3] = {"application", "ocean", "system"}; - - - // sources - fnd::aes::sAes128Key master_key[kMasterKeyNum] = { zeros_aes_key }; - fnd::aes::sAes128Key package2_key_source = zeros_aes_key; - fnd::aes::sAes128Key ticket_titlekek_source = zeros_aes_key; - fnd::aes::sAes128Key key_area_key_source[3] = { zeros_aes_key, zeros_aes_key, zeros_aes_key }; - fnd::aes::sAes128Key aes_kek_generation_source = zeros_aes_key; - fnd::aes::sAes128Key aes_key_generation_source = zeros_aes_key; - fnd::aes::sAes128Key nca_header_kek_source = zeros_aes_key; - fnd::aes::sAesXts128Key nca_header_key_source = zeros_aes_xts_key; - - -#define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2)) -#define _CONCAT_3_STRINGS(str1, str2, str3) ((str1) + "_"+ (str2) + "_" + (str3)) - - std::string key,val; - -#define _SAVE_KEYDATA(key_name, array, len) \ - key = (key_name); \ - val = res[key]; \ - if (val.empty() == false) { \ - decodeHexStringToBytes(key, val, (byte_t*)array, len); \ - } - - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage2Base, kKeyStr, kSourceStr), package2_key_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[0], kSourceStr), ticket_titlekek_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[1], kSourceStr), ticket_titlekek_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[0], kSourceStr), key_area_key_source[0].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[1], kSourceStr), key_area_key_source[1].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[2], kSourceStr), key_area_key_source[2].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[0], kSourceStr), key_area_key_source[0].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[1], kSourceStr), key_area_key_source[1].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[2], kSourceStr), key_area_key_source[2].key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKekGenSource, kSourceStr), aes_kek_generation_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKeyGenSource, kSourceStr), aes_key_generation_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[0], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[0], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[1], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[1], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20); - - // Store Key Variants/Derivatives - for (size_t i = 0; i < kMasterKeyNum; i++) + mKeyCfg.getPkiRootSignKey(nn::pki::sign::kRootIssuerStr, mKeyset.pki.root_sign_key); + mKeyCfg.getAcidSignKey(mKeyset.acid_sign_key); + mKeyCfg.getNcaHeader0SignKey(mKeyset.nca.header_sign_key); + mKeyCfg.getNcaHeaderKey(mKeyset.nca.header_key); + mKeyCfg.getXciHeaderSignKey(mKeyset.xci.header_sign_key); + mKeyCfg.getXciHeaderKey(mKeyset.xci.header_key); + mKeyCfg.getPkg2SignKey(mKeyset.package2_sign_key); + for (size_t mkeyidx = 0; mkeyidx < 32; mkeyidx++) { - - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kMasterBase, kKeyStr, kKeyIndex[i]), master_key[i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage1Base, kKeyStr, kKeyIndex[i]), mKeyset.package1_key[i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage2Base, kKeyStr, kKeyIndex[i]), mKeyset.package2_key[i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[0], kKeyIndex[i]), mKeyset.ticket.titlekey_kek[i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[1], kKeyIndex[i]), mKeyset.ticket.titlekey_kek[i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[0], kKeyIndex[i]), mKeyset.nca.key_area_key[0][i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[1], kKeyIndex[i]), mKeyset.nca.key_area_key[1][i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[2], kKeyIndex[i]), mKeyset.nca.key_area_key[2][i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[0], kKeyIndex[i]), mKeyset.nca.key_area_key[0][i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[1], kKeyIndex[i]), mKeyset.nca.key_area_key[1][i].key, 0x10); - _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[2], kKeyIndex[i]), mKeyset.nca.key_area_key[2][i].key, 0x10); + mKeyCfg.getPkg1Key(mkeyidx, mKeyset.package1_key[mkeyidx]); + mKeyCfg.getPkg2Key(mkeyidx, mKeyset.package1_key[mkeyidx]); + mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 0, mKeyset.nca.key_area_key[0][mkeyidx]); + mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 1, mKeyset.nca.key_area_key[1][mkeyidx]); + mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 2, mKeyset.nca.key_area_key[2][mkeyidx]); + mKeyCfg.getETicketCommonKey(mkeyidx, mKeyset.ticket.titlekey_kek[mkeyidx]); } - - // store nca header key - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[0], kKeyStr), mKeyset.nca.header_key.key[0], 0x20); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kKeyStr), mKeyset.nca.header_key.key[0], 0x20); - // store xci header key - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kKeyStr), mKeyset.xci.header_key.key, 0x10); - - // store rsa keys - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[0]), mKeyset.nca.header_sign_key.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[1]), mKeyset.nca.header_sign_key.modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[0]), mKeyset.xci.header_sign_key.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[1]), mKeyset.xci.header_sign_key.modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[0]), mKeyset.acid_sign_key.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[1]), mKeyset.acid_sign_key.modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[0]), mKeyset.package2_sign_key.priv_exponent, fnd::rsa::kRsa2048Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[1]), mKeyset.package2_sign_key.modulus, fnd::rsa::kRsa2048Size); - - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase, kRsaKeySuffix[0]), mKeyset.pki.root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size); - _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase, kRsaKeySuffix[1]), mKeyset.pki.root_sign_key.modulus, fnd::rsa::kRsa4096Size); - - - // save keydata from input args if (args.nca_bodykey.isSet) { - if (args.nca_bodykey.var.length() == (sizeof(fnd::aes::sAes128Key)*2)) - { - decodeHexStringToBytes("--bodykey", args.nca_bodykey.var, mKeyset.nca.manual_body_key_aesctr.key, sizeof(fnd::aes::sAes128Key)); - } - else - { - decodeHexStringToBytes("--bodykey", args.nca_bodykey.var, mKeyset.nca.manual_body_key_aesxts.key[0], sizeof(fnd::aes::sAesXts128Key)); - } + fnd::aes::sAes128Key tmp_key; + fnd::Vec tmp_raw; + fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw); + if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key)) + throw fnd::Exception(kModuleName, "Key: \"--bodykey\" has incorrect length"); + memcpy(tmp_key.key, tmp_raw.data(), 16); + mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserBodyKey, tmp_key); } if (args.nca_titlekey.isSet) { - if (args.nca_titlekey.var.length() == (sizeof(fnd::aes::sAes128Key)*2)) - { - decodeHexStringToBytes("--titlekey", args.nca_titlekey.var, mKeyset.nca.manual_title_key_aesctr.key, sizeof(fnd::aes::sAes128Key)); - } - else - { - decodeHexStringToBytes("--titlekey", args.nca_titlekey.var, mKeyset.nca.manual_title_key_aesxts.key[0], sizeof(fnd::aes::sAesXts128Key)); - } + fnd::aes::sAes128Key tmp_key; + fnd::Vec tmp_raw; + fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw); + if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key)) + throw fnd::Exception(kModuleName, "Key: \"--titlekey\" has incorrect length"); + memcpy(tmp_key.key, tmp_raw.data(), 16); + mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key); } // import certificate chain @@ -615,7 +517,19 @@ void UserSettings::populateKeyset(sCmdArgs& args) // extract title key if (tik.getBody().getTitleKeyEncType() == nn::es::ticket::AES128_CBC) { - memcpy(mKeyset.nca.manual_title_key_aesctr.key, tik.getBody().getEncTitleKey(), fnd::aes::kAes128KeySize); + fnd::aes::sAes128Key enc_title_key; + memcpy(enc_title_key.key, tik.getBody().getEncTitleKey(), 16); + mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, enc_title_key); + fnd::aes::sAes128Key common_key, external_content_key; + if (mKeyCfg.getETicketCommonKey(nn::hac::NcaUtils::getMasterKeyRevisionFromKeyGeneration(tik.getBody().getCommonKeyId()), common_key) == true) + { + nn::hac::AesKeygen::generateKey(external_content_key.key, tik.getBody().getEncTitleKey(), common_key.key); + mKeyCfg.addNcaExternalContentKey(tik.getBody().getRightsId(), external_content_key); + } + else + { + std::cout << "[WARNING] Titlekey not imported from ticket because commonkey was not available" << std::endl; + } } else { @@ -623,67 +537,9 @@ void UserSettings::populateKeyset(sCmdArgs& args) } } -#undef _SAVE_KEYDATA -#undef _CONCAT_3_STRINGS -#undef _CONCAT_2_STRINGS - - // Derive keys - for (size_t i = 0; i < kMasterKeyNum; i++) - { - if (master_key[i] != zeros_aes_key) - { - if (aes_kek_generation_source != zeros_aes_key && aes_key_generation_source != zeros_aes_key) - { - if (i == 0 && nca_header_kek_source != zeros_aes_key && nca_header_key_source != zeros_aes_xts_key) - { - if (mKeyset.nca.header_key == zeros_aes_xts_key) - { - fnd::aes::sAes128Key nca_header_kek; - nn::hac::AesKeygen::generateKey(nca_header_kek.key, aes_kek_generation_source.key, nca_header_kek_source.key, aes_key_generation_source.key, master_key[i].key); - nn::hac::AesKeygen::generateKey(mKeyset.nca.header_key.key[0], nca_header_key_source.key[0], nca_header_kek.key); - nn::hac::AesKeygen::generateKey(mKeyset.nca.header_key.key[1], nca_header_key_source.key[1], nca_header_kek.key); - //printf("nca header key[0] "); - //fnd::SimpleTextOutput::hexDump(mKeyset.nca.header_key.key[0], 0x10); - //printf("nca header key[1] "); - //fnd::SimpleTextOutput::hexDump(mKeyset.nca.header_key.key[1], 0x10); - } - } - - for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++) - { - if (key_area_key_source[j] != zeros_aes_key && mKeyset.nca.key_area_key[j][i] == zeros_aes_key) - { - nn::hac::AesKeygen::generateKey(mKeyset.nca.key_area_key[j][i].key, aes_kek_generation_source.key, key_area_key_source[j].key, aes_key_generation_source.key, master_key[i].key); - //printf("nca keak %d/%02d ", j, i); - //fnd::SimpleTextOutput::hexDump(mKeyset.nca.key_area_key[j][i].key, 0x10); - } - } - } - - if (ticket_titlekek_source != zeros_aes_key && mKeyset.ticket.titlekey_kek[i] == zeros_aes_key) - { - nn::hac::AesKeygen::generateKey(mKeyset.ticket.titlekey_kek[i].key, ticket_titlekek_source.key, master_key[i].key); - //printf("ticket titlekek %02d ", i); - //fnd::SimpleTextOutput::hexDump(mKeyset.ticket.titlekey_kek[i].key, 0x10); - } - if (package2_key_source != zeros_aes_key && mKeyset.package2_key[i] == zeros_aes_key) - { - nn::hac::AesKeygen::generateKey(mKeyset.package2_key[i].key, package2_key_source.key, master_key[i].key); - //printf("package2 key %02d ", i); - //fnd::SimpleTextOutput::hexDump(mKeyset.package2_key[i].key, 0x10); - } - } - /* - for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++) - { - if (mKeyset.nca.key_area_key[j][i] != zeros_aes_key) - { - printf("nca body keak %d/%02d ", j, i); - fnd::SimpleTextOutput::hexDump(mKeyset.nca.key_area_key[j][i].key, 0x10); - } - } - */ - } + // replicate keys into old keyset + mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mKeyset.nca.manual_body_key_aesctr); + mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, mKeyset.nca.manual_title_key_aesctr); } void UserSettings::populateUserSettings(sCmdArgs& args) @@ -747,21 +603,6 @@ void UserSettings::populateUserSettings(sCmdArgs& args) throw fnd::Exception(kModuleName, "Unknown file type."); } - -void UserSettings::decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len) -{ - size_t size = str.size(); - if ((size % 2) || ((size / 2) != out_len)) - { - throw fnd::Exception(kModuleName, "Key: \"" + name + "\" has incorrect length"); - } - - for (size_t i = 0; i < out_len; i++) - { - out[i] = (charToByte(str[i * 2]) << 4) | charToByte(str[(i * 2) + 1]); - } -} - FileType UserSettings::getFileTypeFromString(const std::string& type_str) { std::string str = type_str; @@ -1019,3 +860,25 @@ nn::hac::npdm::InstructionType UserSettings::getInstructionTypeFromString(const return type; } + +void UserSettings::getHomePath(std::string& path) const +{ + // open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set). + path.clear(); + if (path.empty()) fnd::io::getEnvironVar(path, "HOME"); + if (path.empty()) fnd::io::getEnvironVar(path, "USERPROFILE"); + if (path.empty()) return; +} + +void UserSettings::getSwitchPath(std::string& path) const +{ + std::string home; + home.clear(); + getHomePath(home); + if (home.empty()) + return; + + path.clear(); + fnd::io::appendToPath(path, home); + fnd::io::appendToPath(path, kHomeSwitchDirStr); +} \ No newline at end of file diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index a3fd6ed..573e124 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -8,6 +8,7 @@ #include #include #include "nstool.h" +#include "KeyConfiguration.h" class UserSettings { @@ -19,6 +20,7 @@ public: // generic options const std::string getInputPath() const; + const KeyConfiguration& getKeyCfg() const; const sKeyset& getKeyset() const; FileType getFileType() const; bool isVerifyFile() const; @@ -44,8 +46,15 @@ public: const sOptional& getAssetNacpPath() const; const fnd::List>& getCertificateChain() const; + void dumpKeys() const; + private: const std::string kModuleName = "UserSettings"; + + const std::string kHomeSwitchDirStr = ".switch"; + const std::string kGeneralKeyfileName[2] = { "prod.keys", "dev.keys" }; + const std::string kTitleKeyfileName = "title.keys"; + struct sCmdArgs { @@ -82,6 +91,7 @@ private: std::string mInputPath; FileType mFileType; sKeyset mKeyset; + KeyConfiguration mKeyCfg; bool mVerifyFile; CliOutputMode mOutputMode; @@ -109,7 +119,6 @@ private: void populateCmdArgs(const std::vector& arg_list, sCmdArgs& cmd_args); void populateKeyset(sCmdArgs& args); void populateUserSettings(sCmdArgs& args); - void decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len); FileType getFileTypeFromString(const std::string& type_str); FileType determineFileTypeFromFile(const std::string& path); bool determineValidNcaFromSample(const fnd::Vec& sample) const; @@ -118,4 +127,6 @@ private: bool determineValidEsCertFromSample(const fnd::Vec& sample) const; bool determineValidEsTikFromSample(const fnd::Vec& sample) const; nn::hac::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str); + void getHomePath(std::string& path) const; + void getSwitchPath(std::string& path) const; }; \ No newline at end of file diff --git a/programs/nstool/source/nstool.h b/programs/nstool/source/nstool.h index ba36f7a..f1e3cf6 100644 --- a/programs/nstool/source/nstool.h +++ b/programs/nstool/source/nstool.h @@ -1,5 +1,4 @@ #pragma once -#pragma once #include #include #include @@ -61,6 +60,9 @@ struct sOptional inline T& operator*() { return var; } }; +const byte_t kDummyRightsIdForUserTitleKey[nn::hac::nca::kRightsIdLen] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +const byte_t kDummyRightsIdForUserBodyKey[nn::hac::nca::kRightsIdLen] = {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe}; + struct sKeyset { fnd::rsa::sRsa2048Key acid_sign_key; @@ -96,15 +98,4 @@ struct sKeyset { fnd::rsa::sRsa4096Key root_sign_key; } pki; -}; - -inline byte_t charToByte(char chr) -{ - if (chr >= 'a' && chr <= 'f') - return (chr - 'a') + 0xa; - else if (chr >= 'A' && chr <= 'F') - return (chr - 'A') + 0xa; - else if (chr >= '0' && chr <= '9') - return chr - '0'; - return 0; -} +}; \ No newline at end of file From 1fd8f59025b2e1e99b5657ffd19433c6f43ac039 Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 21 Aug 2018 20:03:19 +0800 Subject: [PATCH 20/50] [nstool] Migrated from sKeyset to KeyConfiguration --- programs/nstool/source/EsTikProcess.cpp | 6 +- programs/nstool/source/EsTikProcess.h | 5 +- programs/nstool/source/KeyConfiguration.cpp | 33 ++++++++++ programs/nstool/source/KeyConfiguration.h | 3 + programs/nstool/source/NcaProcess.cpp | 69 ++++++++++++--------- programs/nstool/source/NcaProcess.h | 5 +- programs/nstool/source/NpdmProcess.cpp | 11 ++-- programs/nstool/source/NpdmProcess.h | 5 +- programs/nstool/source/PkiCertProcess.cpp | 6 +- programs/nstool/source/PkiCertProcess.h | 5 +- programs/nstool/source/PkiValidator.cpp | 27 ++++++-- programs/nstool/source/PkiValidator.h | 6 +- programs/nstool/source/UserSettings.cpp | 34 +++------- programs/nstool/source/UserSettings.h | 2 - programs/nstool/source/XciProcess.cpp | 14 +++-- programs/nstool/source/XciProcess.h | 9 ++- programs/nstool/source/main.cpp | 10 +-- programs/nstool/source/nstool.h | 39 +----------- 18 files changed, 149 insertions(+), 140 deletions(-) diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp index 5a3801a..5bae731 100644 --- a/programs/nstool/source/EsTikProcess.cpp +++ b/programs/nstool/source/EsTikProcess.cpp @@ -41,9 +41,9 @@ void EsTikProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void EsTikProcess::setKeyset(const sKeyset* keyset) +void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg) { - mKeyset = keyset; + mKeyCfg = keycfg; } void EsTikProcess::setCertificateChain(const fnd::List>& certs) @@ -95,7 +95,7 @@ void EsTikProcess::verifyTicket() try { - pki_validator.setRootKey(mKeyset->pki.root_sign_key); + pki_validator.setKeyCfg(mKeyCfg); pki_validator.addCertificates(mCerts); pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash); } diff --git a/programs/nstool/source/EsTikProcess.h b/programs/nstool/source/EsTikProcess.h index 82d82d0..ae77ec3 100644 --- a/programs/nstool/source/EsTikProcess.h +++ b/programs/nstool/source/EsTikProcess.h @@ -6,6 +6,7 @@ #include #include #include +#include "KeyConfiguration.h" #include "nstool.h" class EsTikProcess @@ -17,7 +18,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setKeyset(const sKeyset* keyset); + void setKeyCfg(const KeyConfiguration& keycfg); void setCertificateChain(const fnd::List>& certs); void setCliOutputMode(CliOutputMode mode); void setVerifyMode(bool verify); @@ -27,7 +28,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - const sKeyset* mKeyset; + KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/KeyConfiguration.cpp b/programs/nstool/source/KeyConfiguration.cpp index 0a4f7b1..91c1122 100644 --- a/programs/nstool/source/KeyConfiguration.cpp +++ b/programs/nstool/source/KeyConfiguration.cpp @@ -10,6 +10,39 @@ KeyConfiguration::KeyConfiguration() clearNcaExternalKeys(); } +KeyConfiguration::KeyConfiguration(const KeyConfiguration& other) +{ + *this = other; +} + +void KeyConfiguration::operator=(const KeyConfiguration& other) +{ + mAcidSignKey = other.mAcidSignKey; + mPkg2SignKey = other.mPkg2SignKey; + mNcaHeader0SignKey = other.mNcaHeader0SignKey; + mXciHeaderSignKey = other.mXciHeaderSignKey; + + mNcaHeaderKey = other.mNcaHeaderKey; + mXciHeaderKey = other.mXciHeaderKey; + + for (size_t i = 0; i < kMasterKeyNum; i++) + { + mPkg2Key[i] = other.mPkg2Key[i]; + mPkg1Key[i] = other.mPkg1Key[i]; + mNcaKeyAreaEncryptionKey[0][i] = other.mNcaKeyAreaEncryptionKey[0][i]; + mNcaKeyAreaEncryptionKey[1][i] = other.mNcaKeyAreaEncryptionKey[1][i]; + mNcaKeyAreaEncryptionKey[2][i] = other.mNcaKeyAreaEncryptionKey[2][i]; + mNcaKeyAreaEncryptionKeyHw[0][i] = other.mNcaKeyAreaEncryptionKeyHw[0][i]; + mNcaKeyAreaEncryptionKeyHw[1][i] = other.mNcaKeyAreaEncryptionKeyHw[1][i]; + mNcaKeyAreaEncryptionKeyHw[2][i] = other.mNcaKeyAreaEncryptionKeyHw[2][i]; + mETicketCommonKey[i] = other.mETicketCommonKey[i]; + } + + mPkiRootKeyList = other.mPkiRootKeyList; + + mNcaExternalContentKeyList = other.mNcaExternalContentKeyList; +} + void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path) { clearGeneralKeyConfiguration(); diff --git a/programs/nstool/source/KeyConfiguration.h b/programs/nstool/source/KeyConfiguration.h index f5197cb..41a59e9 100644 --- a/programs/nstool/source/KeyConfiguration.h +++ b/programs/nstool/source/KeyConfiguration.h @@ -13,6 +13,9 @@ class KeyConfiguration { public: KeyConfiguration(); + KeyConfiguration(const KeyConfiguration& other); + + void operator=(const KeyConfiguration& other); void importHactoolGenericKeyfile(const std::string& path); //void importHactoolTitleKeyfile(const std::string& path); diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 90de628..3878764 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -15,7 +15,6 @@ NcaProcess::NcaProcess() : mFile(nullptr), mOwnIFile(false), - mKeyset(nullptr), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mListFs(false) @@ -72,9 +71,9 @@ void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void NcaProcess::setKeyset(const sKeyset* keyset) +void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg) { - mKeyset = keyset; + mKeyCfg = keycfg; } void NcaProcess::setCliOutputMode(CliOutputMode type) @@ -127,7 +126,9 @@ void NcaProcess::importHeader() mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); // decrypt header block - nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); + fnd::aes::sAesXts128Key header_key; + mKeyCfg.getNcaHeaderKey(header_key); + nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, header_key); // generate header hash fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes); @@ -149,23 +150,31 @@ void NcaProcess::generateNcaBodyEncryptionKeys() byte_t keak_index = mHdr.getKaekIndex(); // process key area - sKeys::sKeyAreaKey keak; + sKeys::sKeyAreaKey kak; + fnd::aes::sAes128Key key_area_enc_key; for (size_t i = 0; i < nn::hac::nca::kAesKeyNum; i++) { if (mHdr.getEncAesKeys()[i] != zero_aesctr_key) { - keak.index = (byte_t)i; - keak.enc = mHdr.getEncAesKeys()[i]; - if (i < 4 && mKeyset->nca.key_area_key[keak_index][masterkey_rev] != zero_aesctr_key) + kak.index = (byte_t)i; + kak.enc = mHdr.getEncAesKeys()[i]; + // key[0-3] + if (i < 4 && mKeyCfg.getNcaKeyAreaEncryptionKey(masterkey_rev, keak_index, key_area_enc_key) == true) { - keak.decrypted = true; - nn::hac::AesKeygen::generateKey(keak.dec.key, keak.enc.key, mKeyset->nca.key_area_key[keak_index][masterkey_rev].key); + kak.decrypted = true; + nn::hac::AesKeygen::generateKey(kak.dec.key, kak.enc.key, key_area_enc_key.key); + } + // key[4] + else if (i == 4 && mKeyCfg.getNcaKeyAreaEncryptionKeyHw(masterkey_rev, keak_index, key_area_enc_key) == true) + { + kak.decrypted = true; + nn::hac::AesKeygen::generateKey(kak.dec.key, kak.enc.key, key_area_enc_key.key); } else { - keak.decrypted = false; + kak.decrypted = false; } - mBodyKeys.keak_list.addElement(keak); + mBodyKeys.keak_list.addElement(kak); } } @@ -176,21 +185,19 @@ void NcaProcess::generateNcaBodyEncryptionKeys() // if this has a rights id, the key needs to be sourced from a ticket if (mHdr.hasRightsId() == true) { - // if the titlekey_kek is available - if (mKeyset->ticket.titlekey_kek[masterkey_rev] != zero_aesctr_key) + fnd::aes::sAes128Key tmp_key; + if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true) { - // the title key is provided (sourced from ticket) - if (mKeyset->nca.manual_title_key_aesctr != zero_aesctr_key) + mBodyKeys.aes_ctr = tmp_key; + } + else if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key) == true) + { + fnd::aes::sAes128Key common_key; + if (mKeyCfg.getETicketCommonKey(masterkey_rev, common_key) == true) { - nn::hac::AesKeygen::generateKey(mBodyKeys.aes_ctr.var.key, mKeyset->nca.manual_title_key_aesctr.key, mKeyset->ticket.titlekey_kek[masterkey_rev].key); - mBodyKeys.aes_ctr.isSet = true; - } - if (mKeyset->nca.manual_title_key_aesxts != zero_aesxts_key) - { - nn::hac::AesKeygen::generateKey(mBodyKeys.aes_xts.var.key[0], mKeyset->nca.manual_title_key_aesxts.key[0], mKeyset->ticket.titlekey_kek[masterkey_rev].key); - nn::hac::AesKeygen::generateKey(mBodyKeys.aes_xts.var.key[1], mKeyset->nca.manual_title_key_aesxts.key[1], mKeyset->ticket.titlekey_kek[masterkey_rev].key); - mBodyKeys.aes_xts.isSet = true; + nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.key); } + mBodyKeys.aes_ctr = tmp_key; } } // otherwise decrypt key area @@ -225,15 +232,13 @@ void NcaProcess::generateNcaBodyEncryptionKeys() } // if the keys weren't generated, check if the keys were supplied by the user - if (mBodyKeys.aes_ctr.isSet == false && mKeyset->nca.manual_body_key_aesctr != zero_aesctr_key) + if (mBodyKeys.aes_ctr.isSet == false) { - mBodyKeys.aes_ctr = mKeyset->nca.manual_body_key_aesctr; - } - if (mBodyKeys.aes_xts.isSet == false && mKeyset->nca.manual_body_key_aesxts != zero_aesxts_key) - { - mBodyKeys.aes_xts = mKeyset->nca.manual_body_key_aesxts; + if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mBodyKeys.aes_ctr.var) == true) + mBodyKeys.aes_ctr.isSet = true; } + if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { if (mBodyKeys.aes_ctr.isSet) @@ -365,7 +370,9 @@ void NcaProcess::generatePartitionConfiguration() void NcaProcess::validateNcaSignatures() { // validate signature[0] - if (fnd::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0) + fnd::rsa::sRsa2048Key sign0_key; + mKeyCfg.getNcaHeader0SignKey(sign0_key); + if (fnd::rsa::pss::rsaVerify(sign0_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0) { std::cout << "[WARNING] NCA Header Main Signature: FAIL" << std::endl; } diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index a9b0806..3a34e98 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -4,6 +4,7 @@ #include #include #include "HashTreeMeta.h" +#include "KeyConfiguration.h" #include "nstool.h" @@ -18,7 +19,7 @@ public: // generic void setInputFile(fnd::IFile* file, bool ownIFile); - void setKeyset(const sKeyset* keyset); + void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -36,7 +37,7 @@ private: // user options fnd::IFile* mFile; bool mOwnIFile; - const sKeyset* mKeyset; + KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index b9f5fe6..71b9f14 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -5,7 +5,6 @@ NpdmProcess::NpdmProcess() : mFile(nullptr), mOwnIFile(false), - mKeyset(nullptr), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { @@ -57,9 +56,9 @@ void NpdmProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void NpdmProcess::setKeyset(const sKeyset* keyset) +void NpdmProcess::setKeyCfg(const KeyConfiguration& keycfg) { - mKeyset = keyset; + mKeyCfg = keycfg; } void NpdmProcess::setCliOutputMode(CliOutputMode type) @@ -95,7 +94,11 @@ void NpdmProcess::importNpdm() void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid) { try { - acid.validateSignature(mKeyset->acid_sign_key); + fnd::rsa::sRsa2048Key acid_sign_key; + if (mKeyCfg.getAcidSignKey(acid_sign_key) != true) + throw fnd::Exception(); + + acid.validateSignature(acid_sign_key); } catch (...) { std::cout << "[WARNING] ACID Signature: FAIL" << std::endl; diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index d476493..68c3523 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -3,6 +3,7 @@ #include #include #include +#include "KeyConfiguration.h" #include "nstool.h" @@ -15,7 +16,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setKeyset(const sKeyset* keyset); + void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -26,7 +27,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - const sKeyset* mKeyset; + KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/PkiCertProcess.cpp b/programs/nstool/source/PkiCertProcess.cpp index bc71e09..f9912a3 100644 --- a/programs/nstool/source/PkiCertProcess.cpp +++ b/programs/nstool/source/PkiCertProcess.cpp @@ -39,9 +39,9 @@ void PkiCertProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void PkiCertProcess::setKeyset(const sKeyset* keyset) +void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg) { - mKeyset = keyset; + mKeyCfg = keycfg; } void PkiCertProcess::setCliOutputMode(CliOutputMode mode) @@ -80,7 +80,7 @@ void PkiCertProcess::validateCerts() try { - pki.setRootKey(mKeyset->pki.root_sign_key); + pki.setKeyCfg(mKeyCfg); pki.addCertificates(mCert); } catch (const fnd::Exception& e) diff --git a/programs/nstool/source/PkiCertProcess.h b/programs/nstool/source/PkiCertProcess.h index e7dd144..964a70d 100644 --- a/programs/nstool/source/PkiCertProcess.h +++ b/programs/nstool/source/PkiCertProcess.h @@ -6,6 +6,7 @@ #include #include #include +#include "KeyConfiguration.h" #include "nstool.h" class PkiCertProcess @@ -17,7 +18,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setKeyset(const sKeyset* keyset); + void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -27,7 +28,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - const sKeyset* mKeyset; + KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/PkiValidator.cpp b/programs/nstool/source/PkiValidator.cpp index 70c1589..37bb9b5 100644 --- a/programs/nstool/source/PkiValidator.cpp +++ b/programs/nstool/source/PkiValidator.cpp @@ -9,7 +9,7 @@ PkiValidator::PkiValidator() clearCertificates(); } -void PkiValidator::setRootKey(const fnd::rsa::sRsa4096Key& root_key) +void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg) { // save a copy of the certificate bank fnd::List> old_certs = mCertificateBank; @@ -18,7 +18,7 @@ void PkiValidator::setRootKey(const fnd::rsa::sRsa4096Key& root_key) mCertificateBank.clear(); // overwrite the root key - mRootKey = root_key; + mKeyCfg = keycfg; // if there were certificates before, reimport them (so they are checked against the new root key) if (old_certs.size() > 0) @@ -96,13 +96,28 @@ void PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::S int sig_validate_res = -1; // special case if signed by Root - if (issuer == nn::pki::sign::kRootIssuerStr) + if (issuer.find('-', 0) == std::string::npos) { - if (sign_algo != nn::pki::sign::SIGN_ALGO_RSA4096) + fnd::rsa::sRsa4096Key rsa4096_pub; + fnd::rsa::sRsa2048Key rsa2048_pub; + fnd::ecdsa::sEcdsa240Key ecdsa_pub; + + if (mKeyCfg.getPkiRootSignKey(issuer, rsa4096_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_RSA4096) { - throw fnd::Exception(kModuleName, "Issued by Root, but does not have a RSA4096 signature"); + sig_validate_res = fnd::rsa::pkcs::rsaVerify(rsa4096_pub, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data()); + } + else if (mKeyCfg.getPkiRootSignKey(issuer, rsa2048_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_RSA2048) + { + sig_validate_res = fnd::rsa::pkcs::rsaVerify(rsa2048_pub, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data()); + } + else if (mKeyCfg.getPkiRootSignKey(issuer, ecdsa_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_ECDSA240) + { + throw fnd::Exception(kModuleName, "ECDSA signatures are not supported"); + } + else + { + throw fnd::Exception(kModuleName, "Public key for issuer \"" + issuer + "\" does not exist."); } - sig_validate_res = fnd::rsa::pkcs::rsaVerify(mRootKey, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data()); } else { diff --git a/programs/nstool/source/PkiValidator.h b/programs/nstool/source/PkiValidator.h index 6ef0bd2..7b7a0ab 100644 --- a/programs/nstool/source/PkiValidator.h +++ b/programs/nstool/source/PkiValidator.h @@ -6,13 +6,14 @@ #include #include #include +#include "KeyConfiguration.h" class PkiValidator { public: PkiValidator(); - void setRootKey(const fnd::rsa::sRsa4096Key& root_key); + void setKeyCfg(const KeyConfiguration& keycfg); void addCertificates(const fnd::List>& certs); void addCertificate(const nn::pki::SignedData& cert); void clearCertificates(); @@ -22,8 +23,7 @@ public: private: const std::string kModuleName = "NNPkiValidator"; - - fnd::rsa::sRsa4096Key mRootKey; + KeyConfiguration mKeyCfg; fnd::List> mCertificateBank; void makeCertIdent(const nn::pki::SignedData& cert, std::string& ident) const; diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index a587ede..ce1e929 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -96,9 +96,9 @@ const std::string UserSettings::getInputPath() const return mInputPath; } -const sKeyset& UserSettings::getKeyset() const +const KeyConfiguration& UserSettings::getKeyCfg() const { - return mKeyset; + return mKeyCfg; } FileType UserSettings::getFileType() const @@ -386,8 +386,6 @@ void UserSettings::populateCmdArgs(const std::vector& arg_list, sCm void UserSettings::populateKeyset(sCmdArgs& args) { - memset((void*)&mKeyset, 0, sizeof(sKeyset)); - if (args.keyset_path.isSet) { mKeyCfg.importHactoolGenericKeyfile(*args.keyset_path); @@ -413,22 +411,7 @@ void UserSettings::populateKeyset(sCmdArgs& args) } - mKeyCfg.getPkiRootSignKey(nn::pki::sign::kRootIssuerStr, mKeyset.pki.root_sign_key); - mKeyCfg.getAcidSignKey(mKeyset.acid_sign_key); - mKeyCfg.getNcaHeader0SignKey(mKeyset.nca.header_sign_key); - mKeyCfg.getNcaHeaderKey(mKeyset.nca.header_key); - mKeyCfg.getXciHeaderSignKey(mKeyset.xci.header_sign_key); - mKeyCfg.getXciHeaderKey(mKeyset.xci.header_key); - mKeyCfg.getPkg2SignKey(mKeyset.package2_sign_key); - for (size_t mkeyidx = 0; mkeyidx < 32; mkeyidx++) - { - mKeyCfg.getPkg1Key(mkeyidx, mKeyset.package1_key[mkeyidx]); - mKeyCfg.getPkg2Key(mkeyidx, mKeyset.package1_key[mkeyidx]); - mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 0, mKeyset.nca.key_area_key[0][mkeyidx]); - mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 1, mKeyset.nca.key_area_key[1][mkeyidx]); - mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 2, mKeyset.nca.key_area_key[2][mkeyidx]); - mKeyCfg.getETicketCommonKey(mkeyidx, mKeyset.ticket.titlekey_kek[mkeyidx]); - } + if (args.nca_bodykey.isSet) { @@ -503,7 +486,7 @@ void UserSettings::populateKeyset(sCmdArgs& args) try { - pki_validator.setRootKey(mKeyset.pki.root_sign_key); + pki_validator.setKeyCfg(mKeyCfg); pki_validator.addCertificates(mCertChain); pki_validator.validateSignature(tik.getBody().getIssuer(), tik.getSignature().getSignType(), tik.getSignature().getSignature(), tik_hash); } @@ -519,7 +502,6 @@ void UserSettings::populateKeyset(sCmdArgs& args) { fnd::aes::sAes128Key enc_title_key; memcpy(enc_title_key.key, tik.getBody().getEncTitleKey(), 16); - mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, enc_title_key); fnd::aes::sAes128Key common_key, external_content_key; if (mKeyCfg.getETicketCommonKey(nn::hac::NcaUtils::getMasterKeyRevisionFromKeyGeneration(tik.getBody().getCommonKeyId()), common_key) == true) { @@ -536,10 +518,6 @@ void UserSettings::populateKeyset(sCmdArgs& args) std::cout << "[WARNING] Titlekey not imported from ticket because it is personalised" << std::endl; } } - - // replicate keys into old keyset - mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mKeyset.nca.manual_body_key_aesctr); - mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, mKeyset.nca.manual_title_key_aesctr); } void UserSettings::populateUserSettings(sCmdArgs& args) @@ -721,7 +699,9 @@ bool UserSettings::determineValidNcaFromSample(const fnd::Vec& sample) c if (sample.size() < nn::hac::nca::kHeaderSize) return false; - nn::hac::NcaUtils::decryptNcaHeader(sample.data(), nca_raw, mKeyset.nca.header_key); + fnd::aes::sAesXts128Key header_key; + mKeyCfg.getNcaHeaderKey(header_key); + nn::hac::NcaUtils::decryptNcaHeader(sample.data(), nca_raw, header_key); if (nca_header->st_magic.get() != nn::hac::nca::kNca2StructMagic && nca_header->st_magic.get() != nn::hac::nca::kNca3StructMagic) return false; diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index 573e124..84450ba 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -21,7 +21,6 @@ public: // generic options const std::string getInputPath() const; const KeyConfiguration& getKeyCfg() const; - const sKeyset& getKeyset() const; FileType getFileType() const; bool isVerifyFile() const; CliOutputMode getCliOutputMode() const; @@ -90,7 +89,6 @@ private: std::string mInputPath; FileType mFileType; - sKeyset mKeyset; KeyConfiguration mKeyCfg; bool mVerifyFile; CliOutputMode mOutputMode; diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index b535204..48bde39 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -8,7 +8,6 @@ XciProcess::XciProcess() : mFile(nullptr), mOwnIFile(false), - mKeyset(nullptr), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mListFs(false), @@ -50,9 +49,9 @@ void XciProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void XciProcess::setKeyset(const sKeyset* keyset) +void XciProcess::setKeyCfg(const KeyConfiguration& keycfg) { - mKeyset = keyset; + mKeyCfg = keycfg; } void XciProcess::setCliOutputMode(CliOutputMode type) @@ -89,7 +88,10 @@ void XciProcess::importHeader() // allocate memory for and decrypt sXciHeader scratch.alloc(sizeof(nn::hac::sXciHeader)); - nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), mKeyset->xci.header_key.key); + + fnd::aes::sAes128Key header_key; + mKeyCfg.getXciHeaderKey(header_key); + nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), header_key.key); // deserialise header mHdr.fromBytes(scratch.data(), scratch.size()); @@ -198,9 +200,11 @@ bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* t void XciProcess::validateXciSignature() { + fnd::rsa::sRsa2048Key header_sign_key; fnd::sha::sSha256Hash calc_hash; fnd::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nn::hac::sXciHeader), calc_hash.bytes); - if (fnd::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, fnd::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0) + mKeyCfg.getXciHeaderSignKey(header_sign_key); + if (fnd::rsa::pkcs::rsaVerify(header_sign_key, fnd::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0) { std::cout << "[WARNING] XCI Header Signature: FAIL" << std::endl; } diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index c3da185..0978b18 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -4,11 +4,10 @@ #include #include #include - -#include "nstool.h" - +#include "KeyConfiguration.h" #include "PfsProcess.h" +#include "nstool.h" class XciProcess { @@ -20,7 +19,7 @@ public: // generic void setInputFile(fnd::IFile* file, bool ownIFile); - void setKeyset(const sKeyset* keyset); + void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -34,7 +33,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - const sKeyset* mKeyset; + KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/main.cpp b/programs/nstool/source/main.cpp index 6a30e29..9659241 100644 --- a/programs/nstool/source/main.cpp +++ b/programs/nstool/source/main.cpp @@ -41,7 +41,7 @@ int main(int argc, char** argv) xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - xci.setKeyset(&user_set.getKeyset()); + xci.setKeyCfg(user_set.getKeyCfg()); xci.setCliOutputMode(user_set.getCliOutputMode()); xci.setVerifyMode(user_set.isVerifyFile()); @@ -90,7 +90,7 @@ int main(int argc, char** argv) NcaProcess nca; nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - nca.setKeyset(&user_set.getKeyset()); + nca.setKeyCfg(user_set.getKeyCfg()); nca.setCliOutputMode(user_set.getCliOutputMode()); nca.setVerifyMode(user_set.isVerifyFile()); @@ -112,7 +112,7 @@ int main(int argc, char** argv) NpdmProcess npdm; npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - npdm.setKeyset(&user_set.getKeyset()); + npdm.setKeyCfg(user_set.getKeyCfg()); npdm.setCliOutputMode(user_set.getCliOutputMode()); npdm.setVerifyMode(user_set.isVerifyFile()); @@ -180,7 +180,7 @@ int main(int argc, char** argv) PkiCertProcess cert; cert.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - cert.setKeyset(&user_set.getKeyset()); + cert.setKeyCfg(user_set.getKeyCfg()); cert.setCliOutputMode(user_set.getCliOutputMode()); cert.setVerifyMode(user_set.isVerifyFile()); @@ -191,7 +191,7 @@ int main(int argc, char** argv) EsTikProcess tik; tik.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - tik.setKeyset(&user_set.getKeyset()); + tik.setKeyCfg(user_set.getKeyCfg()); tik.setCertificateChain(user_set.getCertificateChain()); tik.setCliOutputMode(user_set.getCliOutputMode()); tik.setVerifyMode(user_set.isVerifyFile()); diff --git a/programs/nstool/source/nstool.h b/programs/nstool/source/nstool.h index f1e3cf6..6bdf571 100644 --- a/programs/nstool/source/nstool.h +++ b/programs/nstool/source/nstool.h @@ -61,41 +61,4 @@ struct sOptional }; const byte_t kDummyRightsIdForUserTitleKey[nn::hac::nca::kRightsIdLen] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -const byte_t kDummyRightsIdForUserBodyKey[nn::hac::nca::kRightsIdLen] = {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe}; - -struct sKeyset -{ - fnd::rsa::sRsa2048Key acid_sign_key; - fnd::aes::sAes128Key package1_key[kMasterKeyNum]; - fnd::rsa::sRsa2048Key package2_sign_key; - fnd::aes::sAes128Key package2_key[kMasterKeyNum]; - - struct sNcaData - { - fnd::rsa::sRsa2048Key header_sign_key; - fnd::aes::sAesXts128Key header_key; - fnd::aes::sAes128Key key_area_key[kNcaKeakNum][kMasterKeyNum]; - - fnd::aes::sAes128Key manual_title_key_aesctr; - fnd::aes::sAesXts128Key manual_title_key_aesxts; - fnd::aes::sAes128Key manual_body_key_aesctr; - fnd::aes::sAesXts128Key manual_body_key_aesxts; - } nca; - - struct sXciData - { - fnd::rsa::sRsa2048Key header_sign_key; - fnd::aes::sAes128Key header_key; - } xci; - - struct sTicketData - { - fnd::rsa::sRsa2048Key sign_key; - fnd::aes::sAes128Key titlekey_kek[kMasterKeyNum]; - } ticket; - - struct sPkiData - { - fnd::rsa::sRsa4096Key root_sign_key; - } pki; -}; \ No newline at end of file +const byte_t kDummyRightsIdForUserBodyKey[nn::hac::nca::kRightsIdLen] = {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe}; \ No newline at end of file From 0e9fa495b2b86f62e9f5a7d6a97a30f4e71773bf Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 21 Aug 2018 20:07:29 +0800 Subject: [PATCH 21/50] [nstool] Fix typo. --- programs/nstool/source/NcaProcess.cpp | 28 +++++++++++++-------------- programs/nstool/source/NcaProcess.h | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 3878764..6f5594e 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -174,7 +174,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { kak.decrypted = false; } - mBodyKeys.keak_list.addElement(kak); + mBodyKeys.kak_list.addElement(kak); } } @@ -205,19 +205,19 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { fnd::aes::sAes128Key keak_aesctr_key = zero_aesctr_key; fnd::aes::sAesXts128Key keak_aesxts_key = zero_aesxts_key; - for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++) + for (size_t i = 0; i < mBodyKeys.kak_list.size(); i++) { - if (mBodyKeys.keak_list[i].index == nn::hac::nca::KEY_AESCTR && mBodyKeys.keak_list[i].decrypted) + if (mBodyKeys.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mBodyKeys.kak_list[i].decrypted) { - keak_aesctr_key = mBodyKeys.keak_list[i].dec; + keak_aesctr_key = mBodyKeys.kak_list[i].dec; } - else if (mBodyKeys.keak_list[i].index == nn::hac::nca::KEY_AESXTS_0 && mBodyKeys.keak_list[i].decrypted) + else if (mBodyKeys.kak_list[i].index == nn::hac::nca::KEY_AESXTS_0 && mBodyKeys.kak_list[i].decrypted) { - memcpy(keak_aesxts_key.key[0], mBodyKeys.keak_list[i].dec.key, sizeof(fnd::aes::sAes128Key)); + memcpy(keak_aesxts_key.key[0], mBodyKeys.kak_list[i].dec.key, sizeof(fnd::aes::sAes128Key)); } - else if (mBodyKeys.keak_list[i].index == nn::hac::nca::KEY_AESXTS_1 && mBodyKeys.keak_list[i].decrypted) + else if (mBodyKeys.kak_list[i].index == nn::hac::nca::KEY_AESXTS_1 && mBodyKeys.kak_list[i].decrypted) { - memcpy(keak_aesxts_key.key[1], mBodyKeys.keak_list[i].dec.key, sizeof(fnd::aes::sAes128Key)); + memcpy(keak_aesxts_key.key[1], mBodyKeys.kak_list[i].dec.key, sizeof(fnd::aes::sAes128Key)); } } @@ -441,21 +441,21 @@ void NcaProcess::displayHeader() std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl; } - if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) + if (mBodyKeys.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { std::cout << " Key Area:" << std::endl; std::cout << " <--------------------------------------------------------------------------->" << std::endl; std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl; std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl; - for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++) + for (size_t i = 0; i < mBodyKeys.kak_list.size(); i++) { - std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mBodyKeys.keak_list[i].index << " | "; + std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mBodyKeys.kak_list[i].index << " | "; - std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].enc.key, 16, false, "") << " | "; + std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.kak_list[i].enc.key, 16, false, "") << " | "; - if (mBodyKeys.keak_list[i].decrypted) - std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.keak_list[i].dec.key, 16, false, ""); + if (mBodyKeys.kak_list[i].decrypted) + std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.kak_list[i].dec.key, 16, false, ""); else std::cout << " "; diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index 3a34e98..fbe96a0 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -85,7 +85,7 @@ private: return !(*this == other); } }; - fnd::List keak_list; + fnd::List kak_list; sOptional aes_ctr; sOptional aes_xts; From e89351881cfb7bbad40824f8f0bd0bbb009aed82 Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 21 Aug 2018 20:18:14 +0800 Subject: [PATCH 22/50] [nstool] Formally remove aes-xts content code from NcaProcess. --- programs/nstool/source/NcaProcess.cpp | 71 +++++++++------------------ programs/nstool/source/NcaProcess.h | 3 +- 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 6f5594e..781e471 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -142,8 +142,6 @@ void NcaProcess::generateNcaBodyEncryptionKeys() // create zeros key fnd::aes::sAes128Key zero_aesctr_key; memset(zero_aesctr_key.key, 0, sizeof(zero_aesctr_key)); - fnd::aes::sAesXts128Key zero_aesxts_key; - memset(zero_aesxts_key.key, 0, sizeof(zero_aesxts_key)); // get key data from header byte_t masterkey_rev = nn::hac::NcaUtils::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration()); @@ -174,13 +172,12 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { kak.decrypted = false; } - mBodyKeys.kak_list.addElement(kak); + mContentKey.kak_list.addElement(kak); } } // set flag to indicate that the keys are not available - mBodyKeys.aes_ctr.isSet = false; - mBodyKeys.aes_xts.isSet = false; + mContentKey.aes_ctr.isSet = false; // if this has a rights id, the key needs to be sourced from a ticket if (mHdr.hasRightsId() == true) @@ -188,7 +185,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys() fnd::aes::sAes128Key tmp_key; if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true) { - mBodyKeys.aes_ctr = tmp_key; + mContentKey.aes_ctr = tmp_key; } else if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key) == true) { @@ -197,61 +194,41 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.key); } - mBodyKeys.aes_ctr = tmp_key; + mContentKey.aes_ctr = tmp_key; } } // otherwise decrypt key area else { - fnd::aes::sAes128Key keak_aesctr_key = zero_aesctr_key; - fnd::aes::sAesXts128Key keak_aesxts_key = zero_aesxts_key; - for (size_t i = 0; i < mBodyKeys.kak_list.size(); i++) + fnd::aes::sAes128Key kak_aes_ctr = zero_aesctr_key; + for (size_t i = 0; i < mContentKey.kak_list.size(); i++) { - if (mBodyKeys.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mBodyKeys.kak_list[i].decrypted) + if (mContentKey.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mContentKey.kak_list[i].decrypted) { - keak_aesctr_key = mBodyKeys.kak_list[i].dec; - } - else if (mBodyKeys.kak_list[i].index == nn::hac::nca::KEY_AESXTS_0 && mBodyKeys.kak_list[i].decrypted) - { - memcpy(keak_aesxts_key.key[0], mBodyKeys.kak_list[i].dec.key, sizeof(fnd::aes::sAes128Key)); - } - else if (mBodyKeys.kak_list[i].index == nn::hac::nca::KEY_AESXTS_1 && mBodyKeys.kak_list[i].decrypted) - { - memcpy(keak_aesxts_key.key[1], mBodyKeys.kak_list[i].dec.key, sizeof(fnd::aes::sAes128Key)); + kak_aes_ctr = mContentKey.kak_list[i].dec; } } - if (keak_aesctr_key != zero_aesctr_key) + if (kak_aes_ctr != zero_aesctr_key) { - mBodyKeys.aes_ctr = keak_aesctr_key; - } - if (keak_aesxts_key != zero_aesxts_key) - { - mBodyKeys.aes_xts = keak_aesxts_key; + mContentKey.aes_ctr = kak_aes_ctr; } } // if the keys weren't generated, check if the keys were supplied by the user - if (mBodyKeys.aes_ctr.isSet == false) + if (mContentKey.aes_ctr.isSet == false) { - if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mBodyKeys.aes_ctr.var) == true) - mBodyKeys.aes_ctr.isSet = true; + if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mContentKey.aes_ctr.var) == true) + mContentKey.aes_ctr.isSet = true; } if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { - if (mBodyKeys.aes_ctr.isSet) + if (mContentKey.aes_ctr.isSet) { - std::cout << "[NCA Body Key]" << std::endl; - std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; - } - - if (mBodyKeys.aes_xts.isSet) - { - std::cout << "[NCA Body Key]" << std::endl; - std::cout << " AES-XTS Key0: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; - std::cout << " AES-XTS Key1: " << fnd::SimpleTextOutput::arrayToString(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var), true, "") << std::endl; + std::cout << "[NCA Content Key]" << std::endl; + std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, "") << std::endl; } } @@ -326,9 +303,9 @@ void NcaProcess::generatePartitionConfiguration() } else if (info.enc_type == nn::hac::nca::CRYPT_AESCTR) { - if (mBodyKeys.aes_ctr.isSet == false) + if (mContentKey.aes_ctr.isSet == false) throw fnd::Exception(kModuleName, "AES-CTR Key was not determined"); - info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, SHARED_IFILE, mBodyKeys.aes_ctr.var, info.aes_ctr), OWN_IFILE, info.offset, info.size); + info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, SHARED_IFILE, mContentKey.aes_ctr.var, info.aes_ctr), OWN_IFILE, info.offset, info.size); } else if (info.enc_type == nn::hac::nca::CRYPT_AESXTS || info.enc_type == nn::hac::nca::CRYPT_AESCTREX) { @@ -441,21 +418,21 @@ void NcaProcess::displayHeader() std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl; } - if (mBodyKeys.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) + if (mContentKey.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { std::cout << " Key Area:" << std::endl; std::cout << " <--------------------------------------------------------------------------->" << std::endl; std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl; std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl; - for (size_t i = 0; i < mBodyKeys.kak_list.size(); i++) + for (size_t i = 0; i < mContentKey.kak_list.size(); i++) { - std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mBodyKeys.kak_list[i].index << " | "; + std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mContentKey.kak_list[i].index << " | "; - std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.kak_list[i].enc.key, 16, false, "") << " | "; + std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].enc.key, 16, false, "") << " | "; - if (mBodyKeys.kak_list[i].decrypted) - std::cout << fnd::SimpleTextOutput::arrayToString(mBodyKeys.kak_list[i].dec.key, 16, false, ""); + if (mContentKey.kak_list[i].decrypted) + std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].dec.key, 16, false, ""); else std::cout << " "; diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index fbe96a0..b263278 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -88,8 +88,7 @@ private: fnd::List kak_list; sOptional aes_ctr; - sOptional aes_xts; - } mBodyKeys; + } mContentKey; struct sPartitionInfo { From badebc6b653044a64a5f483c2b69ca4367fc34a3 Mon Sep 17 00:00:00 2001 From: jakcron Date: Fri, 24 Aug 2018 16:08:16 +0800 Subject: [PATCH 23/50] [nstool] Add more constructors to sOptional --- programs/nstool/source/nstool.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/nstool/source/nstool.h b/programs/nstool/source/nstool.h index 6bdf571..883ee44 100644 --- a/programs/nstool/source/nstool.h +++ b/programs/nstool/source/nstool.h @@ -48,6 +48,8 @@ struct sOptional bool isSet; T var; inline sOptional() : isSet(false) {} + inline sOptional(const T& other) : isSet(true), var(other) {} + inline sOptional(const sOptional& other) : isSet(other.isSet), var(other.var) {} inline const T& operator=(const T& other) { isSet = true; var = other; return var; } inline const sOptional& operator=(const sOptional& other) { From 6974e23ed332499644630780c444d65c0d892321 Mon Sep 17 00:00:00 2001 From: jakcron Date: Fri, 24 Aug 2018 16:08:43 +0800 Subject: [PATCH 24/50] [nstool] Fixed typos in KeyConfiguration keynames. --- programs/nstool/source/KeyConfiguration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/nstool/source/KeyConfiguration.h b/programs/nstool/source/KeyConfiguration.h index 41a59e9..8925708 100644 --- a/programs/nstool/source/KeyConfiguration.h +++ b/programs/nstool/source/KeyConfiguration.h @@ -75,8 +75,8 @@ private: const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" }; const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" }; const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" }; - const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_body_keak", "key_area_key", "nca_body_keak" }; - const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_body_keakhw", "key_area_hw_key", "nca_body_keakhw" }; + const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_key_area_key", "key_area_key", "nca_body_keak" }; + const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_key_area_key_hw", "key_area_hw_key", "nca_key_area_key_hw" }; const std::string kKekGenBase[kNameVariantNum] = { "aes_kek_generation", "aes_kek_generation", "aes_kek_generation" }; const std::string kKeyGenBase[kNameVariantNum] = { "aes_key_generation", "aes_key_generation", "aes_key_generation" }; From 4dcf413dbc28c8fa4ce248ae99ac206799e20a0a Mon Sep 17 00:00:00 2001 From: jakcron Date: Fri, 24 Aug 2018 16:09:27 +0800 Subject: [PATCH 25/50] [nstool] Added keycfg state dumping. (--showkeys) --- programs/nstool/source/UserSettings.cpp | 164 ++++++++++++++++++++++++ programs/nstool/source/UserSettings.h | 8 +- 2 files changed, 170 insertions(+), 2 deletions(-) diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index ce1e929..7ea6125 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ void UserSettings::parseCmdArgs(const std::vector& arg_list) populateCmdArgs(arg_list, args); populateKeyset(args); populateUserSettings(args); + if (_HAS_BIT(mOutputMode, OUTPUT_KEY_DATA)) + dumpKeyConfig(); } void UserSettings::showHelp() @@ -861,4 +864,165 @@ void UserSettings::getSwitchPath(std::string& path) const path.clear(); fnd::io::appendToPath(path, home); fnd::io::appendToPath(path, kHomeSwitchDirStr); +} + +void UserSettings::dumpKeyConfig() const +{ + fnd::aes::sAes128Key aes_key; + fnd::aes::sAesXts128Key aesxts_key; + fnd::rsa::sRsa2048Key rsa2048_key; + fnd::rsa::sRsa4096Key rsa4096_key; + + const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"}; + + + std::cout << "[KeyConfiguration]" << std::endl; + std::cout << " NCA Keys:" << std::endl; + if (mKeyCfg.getNcaHeader0SignKey(rsa2048_key) == true) + dumpRsa2048Key(rsa2048_key, "Header Signature[0] Key", 2); + if (mKeyCfg.getNcaHeaderKey(aesxts_key) == true) + dumpAesXtsKey(aesxts_key, "Header Encryption Key", 2); + + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,0, aes_key) == true) + dumpAesKey(aes_key, "KeyAreaEncryptionKey-Application-" + kKeyIndex[i], 2); + if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,1, aes_key) == true) + dumpAesKey(aes_key, "KeyAreaEncryptionKey-Ocean-" + kKeyIndex[i], 2); + if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,2, aes_key) == true) + dumpAesKey(aes_key, "KeyAreaEncryptionKey-System-" + kKeyIndex[i], 2); + } + + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,0, aes_key) == true) + dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Application-" + kKeyIndex[i], 2); + if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,1, aes_key) == true) + dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Ocean-" + kKeyIndex[i], 2); + if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,2, aes_key) == true) + dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-System-" + kKeyIndex[i], 2); + } + + std::cout << " XCI Keys:" << std::endl; + if (mKeyCfg.getXciHeaderSignKey(rsa2048_key) == true) + dumpRsa2048Key(rsa2048_key, "Header Signature Key", 2); + if (mKeyCfg.getXciHeaderKey(aes_key) == true) + dumpAesKey(aes_key, "Extended Header Encryption Key", 2); + + + if (mKeyCfg.getAcidSignKey(rsa2048_key) == true) + dumpRsa2048Key(rsa2048_key, "ACID Signer Key", 1); + + + std::cout << " Package1 Keys:" << std::endl; + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getPkg1Key(i, aes_key) == true) + dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2); + } + + std::cout << " Package2 Keys:" << std::endl; + if (mKeyCfg.getPkg2SignKey(rsa2048_key) == true) + dumpRsa2048Key(rsa2048_key, "Signature Key", 2); + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getPkg2Key(i, aes_key) == true) + dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2); + } + + std::cout << " ETicket Keys:" << std::endl; + for (size_t i = 0; i < kMasterKeyNum; i++) + { + if (mKeyCfg.getETicketCommonKey(i, aes_key) == true) + dumpAesKey(aes_key, "CommonKey-" + kKeyIndex[i], 2); + } + + if (mKeyCfg.getPkiRootSignKey("Root", rsa4096_key) == true) + dumpRsa4096Key(rsa4096_key, "NNPKI Root Key", 1); +} + +void UserSettings::dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const +{ + std::string indent_str; + + indent_str.clear(); + for (size_t i = 0; i < indent; i++) + { + indent_str += " "; + } + + std::cout << indent_str << name << ":" << std::endl; + if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00) + { + std::cout << indent_str << " Modulus:" << std::endl; + for (size_t i = 0; i < 0x10; i++) + { + std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl; + } + } + if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00) + { + std::cout << indent_str << " Private Exponent:" << std::endl; + for (size_t i = 0; i < 0x10; i++) + { + std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl; + } + } +} + +void UserSettings::dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const +{ + std::string indent_str; + + indent_str.clear(); + for (size_t i = 0; i < indent; i++) + { + indent_str += " "; + } + + std::cout << indent_str << name << ":" << std::endl; + if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00) + { + std::cout << indent_str << " Modulus:" << std::endl; + for (size_t i = 0; i < 0x20; i++) + { + std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl; + } + } + if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00) + { + std::cout << indent_str << " Private Exponent:" << std::endl; + for (size_t i = 0; i < 0x20; i++) + { + std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl; + } + } +} + +void UserSettings::dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const +{ + std::string indent_str; + + indent_str.clear(); + for (size_t i = 0; i < indent; i++) + { + indent_str += " "; + } + + std::cout << indent_str << name << ":" << std::endl; + std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key, 0x10, true, ":") << std::endl; +} + +void UserSettings::dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const +{ + std::string indent_str; + + indent_str.clear(); + for (size_t i = 0; i < indent; i++) + { + indent_str += " "; + } + + std::cout << indent_str << name << ":" << std::endl; + std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key[0], 0x20, true, ":") << std::endl; } \ No newline at end of file diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index 84450ba..a3c61db 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -45,8 +45,6 @@ public: const sOptional& getAssetNacpPath() const; const fnd::List>& getCertificateChain() const; - void dumpKeys() const; - private: const std::string kModuleName = "UserSettings"; @@ -127,4 +125,10 @@ private: nn::hac::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str); void getHomePath(std::string& path) const; void getSwitchPath(std::string& path) const; + + void dumpKeyConfig() const; + void dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const; + void dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const; + void dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const; + void dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const; }; \ No newline at end of file From bec682649eb165e650366c48a314a15539528605 Mon Sep 17 00:00:00 2001 From: jakcron Date: Fri, 24 Aug 2018 16:10:03 +0800 Subject: [PATCH 26/50] [nstool] Made key data representation consistent. --- programs/nstool/source/NcaProcess.cpp | 25 +++++++++++++++---------- programs/nstool/source/XciProcess.cpp | 14 +++++++------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 781e471..f637e17 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -228,7 +228,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys() if (mContentKey.aes_ctr.isSet) { std::cout << "[NCA Content Key]" << std::endl; - std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, "") << std::endl; + std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, ":") << std::endl; } } @@ -421,24 +421,24 @@ void NcaProcess::displayHeader() if (mContentKey.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { std::cout << " Key Area:" << std::endl; - std::cout << " <--------------------------------------------------------------------------->" << std::endl; - std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl; - std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl; + std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl; + std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl; + std::cout << " |-----|-------------------------------------------------|-------------------------------------------------|" << std::endl; for (size_t i = 0; i < mContentKey.kak_list.size(); i++) { std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mContentKey.kak_list[i].index << " | "; - std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].enc.key, 16, false, "") << " | "; + std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].enc.key, 16, true, ":") << " | "; if (mContentKey.kak_list[i].decrypted) - std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].dec.key, 16, false, ""); + std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].dec.key, 16, true, ":"); else std::cout << " "; std::cout << " |" << std::endl; } - std::cout << " <--------------------------------------------------------------------------->" << std::endl; + std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) @@ -459,7 +459,8 @@ void NcaProcess::displayHeader() { fnd::aes::sAesIvCtr ctr; fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); - std::cout << " AES-CTR: " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, "") << std::endl; + std::cout << " AesCtr Counter:" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, ":") << std::endl; } if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY) { @@ -479,14 +480,18 @@ void NcaProcess::displayHeader() std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++) { - std::cout << " Master Hash " << std::dec << j << ": " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl; + std::cout << " Master Hash " << std::dec << j << ":" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, 0x10, true, ":") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes+0x10, 0x10, true, ":") << std::endl; } } else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256) { HashTreeMeta& hash_hdr = info.hash_tree_meta; std::cout << " HierarchicalSha256 Header:" << std::endl; - std::cout << " Master Hash: " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl; + std::cout << " Master Hash:" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, 0x10, true, ":") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes+0x10, 0x10, true, ":") << std::endl; std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl; std::cout << " Hash Layer:" << std::endl; std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl; diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index 48bde39..b68b32b 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -123,13 +123,13 @@ void XciProcess::displayHeader() std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl; std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl; std::cout << " Hash:" << std::endl; - std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, "") << std::endl; - std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, "") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, ":") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, ":") << std::endl; } if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - std::cout << " Extended Header AES-IV:" << std::endl; - std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, "") << std::endl; + std::cout << " Extended Header AesCbc IV:" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, ":") << std::endl; } std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl; std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl; @@ -162,8 +162,8 @@ void XciProcess::displayHeader() if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { std::cout << " Hash:" << std::endl; - std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, "") << std::endl; - std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, "") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, ":") << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, ":") << std::endl; } } @@ -184,7 +184,7 @@ void XciProcess::displayHeader() std::cout << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl; #undef _SPLIT_VER std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl; - std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, "") << std::endl; + std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, ":") << std::endl; } } From 8dba27581e8a5ec0d16d43beb921224929058a32 Mon Sep 17 00:00:00 2001 From: jakcron Date: Fri, 24 Aug 2018 16:10:26 +0800 Subject: [PATCH 27/50] [nstool] Dump version to 1.0.2 --- programs/nstool/source/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/nstool/source/version.h b/programs/nstool/source/version.h index f2109d4..90f7950 100644 --- a/programs/nstool/source/version.h +++ b/programs/nstool/source/version.h @@ -1,5 +1,5 @@ #pragma once #define VER_MAJOR 1 #define VER_MINOR 0 -#define VER_PATCH 1 +#define VER_PATCH 2 #define AUTHORS "jakcron" \ No newline at end of file From 7b2d682203be6a0671a8ee491ab0cade96b61ecd Mon Sep 17 00:00:00 2001 From: jakcron Date: Fri, 24 Aug 2018 19:22:23 +0800 Subject: [PATCH 28/50] [nstool] Fixed bugs in --titlekey processing. --- programs/nstool/source/EsTikProcess.cpp | 18 +++++++++++++++--- programs/nstool/source/UserSettings.cpp | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp index 5bae731..4832276 100644 --- a/programs/nstool/source/EsTikProcess.cpp +++ b/programs/nstool/source/EsTikProcess.cpp @@ -122,9 +122,21 @@ void EsTikProcess::displayTicket() std::cout << " Title Key:" << std::endl; std::cout << " EncMode: " << getTitleKeyPersonalisationStr(body.getTitleKeyEncType()) << std::endl; std::cout << " KeyGeneration: " << std::dec << (uint32_t)body.getCommonKeyId() << std::endl; - std::cout << " Data:" << std::endl; - size_t size = body.getTitleKeyEncType() == nn::es::ticket::RSA2048 ? fnd::rsa::kRsa2048Size : fnd::aes::kAes128KeySize; - fnd::SimpleTextOutput::hexDump(body.getEncTitleKey(), size, 0x10, 6); + if (body.getTitleKeyEncType() == nn::es::ticket::RSA2048) + { + std::cout << " Data:" << std::endl; + for (size_t i = 0; i < 0x10; i++) + std::cout << " " << fnd::SimpleTextOutput::arrayToString(body.getEncTitleKey() + 0x10*i, 0x10, true, ":") << std::endl; + } + else if (body.getTitleKeyEncType() == nn::es::ticket::AES128_CBC) + { + std::cout << " Data:" << std::endl; + std::cout << " " << fnd::SimpleTextOutput::arrayToString(body.getEncTitleKey(), 0x10, true, ":") << std::endl; + } + else + { + std::cout << " Data: " << std::endl; + } std::cout << " Version: v" << _SPLIT_VER(body.getTicketVersion()); if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index 7ea6125..e9ad32e 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -431,7 +431,7 @@ void UserSettings::populateKeyset(sCmdArgs& args) { fnd::aes::sAes128Key tmp_key; fnd::Vec tmp_raw; - fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw); + fnd::SimpleTextOutput::stringToArray(args.nca_titlekey.var, tmp_raw); if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key)) throw fnd::Exception(kModuleName, "Key: \"--titlekey\" has incorrect length"); memcpy(tmp_key.key, tmp_raw.data(), 16); From 9bef4145102856f446faf5cc4e0c1ddad818bc03 Mon Sep 17 00:00:00 2001 From: jakcron Date: Thu, 6 Sep 2018 21:12:15 +0800 Subject: [PATCH 29/50] [nstool|fnd|hac] Fixed bugs in elf symbol processing (NSO|NRO handling). --- lib/libfnd/include/fnd/elf.h | 624 +++++++++++++------ lib/libhac/include/nn/hac/elf.h | 70 --- programs/nstool/source/ElfSymbolParser.cpp | 27 +- programs/nstool/source/ElfSymbolParser.h | 9 +- programs/nstool/source/RoMetadataProcess.cpp | 52 +- programs/nstool/source/RoMetadataProcess.h | 6 +- programs/nstool/source/version.h | 2 +- 7 files changed, 482 insertions(+), 308 deletions(-) delete mode 100644 lib/libhac/include/nn/hac/elf.h diff --git a/lib/libfnd/include/fnd/elf.h b/lib/libfnd/include/fnd/elf.h index d46d20d..0f32ccd 100644 --- a/lib/libfnd/include/fnd/elf.h +++ b/lib/libfnd/include/fnd/elf.h @@ -1,216 +1,458 @@ #pragma once #include "types.h" -typedef byte_t Elf_Byte; -typedef word_t Elf32_Addr; -typedef word_t Elf32_Off; -typedef long_t Elf32_Sword; // lol "sword" -typedef word_t Elf32_Word; -typedef hword_t Elf32_Half; - -enum +namespace fnd { - EI_MAG0 = 0, // 0x7F - EI_MAG1 = 1, // 'E' - EI_MAG2 = 2, // 'L' - EI_MAG3 = 3, // 'F' - EI_CLASS = 4, // File class - EI_DATA = 5, // Data encoding - EI_VERSION = 6, // File version - EI_PAD = 7, // Start of padding bytes - EI_NIDENT = 16 // Size of e_ident[] -}; + namespace elf + { + /* These constants are for the segment types stored in the image headers */ + enum SegmentType + { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, /* Thread local storage segment */ + PT_LOOS = 0x60000000, /* OS-specific */ + PT_HIOS = 0x6fffffff, /* OS-specific */ + PT_LOPROC = 0x70000000, + PT_HIPROC = 0x7fffffff + }; -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; // Identification bytes - Elf32_Half e_type; // Object file type - Elf32_Half e_machine; // Object architecture - Elf32_Word e_version; // Object file version - Elf32_Addr e_entry; // Object entry point - Elf32_Off e_phoff; // Program header file offset - Elf32_Off e_shoff; // Section header file offset - Elf32_Word e_flags; // Processor-specific flags - Elf32_Half e_ehsize; // ELF header size - Elf32_Half e_phentsize; // Program header entry size - Elf32_Half e_phnum; // Program header entries - Elf32_Half e_shentsize; // Section header entry size - Elf32_Half e_shnum; // Section header entries - Elf32_Half e_shstrndx; // String table index -} Elf32_Ehdr; + /* These constants define the different elf file types */ + enum ElfType + { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xff00, + ET_HIPROC = 0xffff + }; -typedef struct -{ - Elf32_Word p_type; // Segment type - Elf32_Off p_offset; // File offset - Elf32_Addr p_vaddr; // Virtual address - Elf32_Addr p_paddr; // Physical address - Elf32_Word p_filesz; // File image size - Elf32_Word p_memsz; // Memory image size - Elf32_Word p_flags; // Segment flags - Elf32_Word p_align; // Alignment value -} Elf32_Phdr; + /* This is the info that is needed to parse the dynamic section of the file */ + enum DynamicSectionType + { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_TEXTREL = 22, + DT_JMPREL = 23, + DT_ENCODING = 32, + OLD_DT_LOOS = 0x60000000, + DT_LOOS = 0x6000000d, + DT_HIOS = 0x6ffff000, + DT_VALRNGLO = 0x6ffffd00, + DT_VALRNGHI = 0x6ffffdff, + DT_ADDRRNGLO = 0x6ffffe00, + DT_ADDRRNGHI = 0x6ffffeff, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff, + OLD_DT_HIOS = 0x6fffffff, + DT_LOPROC = 0x70000000, + DT_HIPROC = 0x7fffffff + }; -typedef struct -{ - Elf32_Word sh_name; // Name (index into section header string table section) - Elf32_Word sh_type; // Type - Elf32_Word sh_flags; // Flags - Elf32_Addr sh_addr; // Address - Elf32_Off sh_offset; // File offset - Elf32_Word sh_size; // Section size - Elf32_Word sh_link; // Section header table index link - Elf32_Word sh_info; // Extra information - Elf32_Word sh_addralign; // Address alignment - Elf32_Word sh_entsize; // Section entry size -} Elf32_Shdr; + /* This info is needed when parsing the symbol table */ + enum SymbolBinding + { + STB_LOCAL = 0, + STB_GLOBAL = 1, + STB_WEAK = 2, + STB_LOOS = 10, + STB_HIOS = 12, + STB_LOPROC, + STB_HIPROC = 0xf + }; -typedef struct -{ - Elf32_Addr r_offset; // Offset of relocation - Elf32_Word r_info; // Symbol table index and type -} Elf32_Rel; + enum SymbolType + { + STT_NOTYPE = 0, + STT_OBJECT = 1, + STT_FUNC = 2, + STT_SECTION = 3, + STT_FILE = 4, + STT_COMMON = 5, + STT_TLS = 6, + STT_LOOS = 10, + STT_HIOS = 12, + STT_LOPROC, + STT_HIPROC = 0xf + }; -typedef struct -{ - Elf32_Word st_name; // Name - index into string table - Elf32_Addr st_value; // Symbol value - Elf32_Word st_size; // Symbol size - unsigned char st_info; // Type and binding - unsigned char st_other; // Visibility - Elf32_Half st_shndx; // Section header index -} Elf32_Sym; + /* These constants define the permissions on sections in the program + header, p_flags. */ + enum PermissionFlag + { + PF_R = 0x4, + PF_W = 0x2, + PF_X = 0x1 + }; -enum -{ - ET_NONE = 0, // No file type - ET_REL = 1, // Relocatable file - ET_EXEC = 2, // Executable file - ET_DYN = 3, // Shared object file - ET_CORE = 4, // Core file -}; + /* sh_type */ + enum SectionHeaderType + { + SHT_NULL = 0, + SHT_PROGBITS = 1, + SHT_SYMTAB = 2, + SHT_STRTAB = 3, + SHT_RELA = 4, + SHT_HASH = 5, + SHT_DYNAMIC = 6, + SHT_NOTE = 7, + SHT_NOBITS = 8, + SHT_REL = 9, + SHT_SHLIB = 10, + SHT_DYNSYM = 11, + SHT_NUM = 12, + SHT_LOPROC = 0x70000000, + SHT_HIPROC = 0x7fffffff, + SHT_LOUSER = 0x80000000, + SHT_HIUSER = 0xffffffff + }; + + /* sh_flags */ + enum SectionHeaderFlag + { + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_RELA_LIVEPATCH = 0x00100000, + SHF_RO_AFTER_INIT = 0x00200000, + SHF_MASKPROC = 0xf0000000 + }; + + /* special section indexes */ + enum SpecialSectionIndex + { + SHN_UNDEF = 0, + SHN_LORESERVE = 0xff00, + SHN_LOPROC = 0xff00, + SHN_HIPROC = 0xff1f, + SHN_LOOS = 0xff20, + SHN_HIOS = 0xff3f, + SHN_ABS = 0xfff1, + SHN_COMMON = 0xfff2, + SHN_HIRESERVE = 0xffff + }; -enum -{ - ET_ARM = 40 // ARM architecture -}; + enum ElfIdentIndex + { + EI_MAG0 = 0, /* e_ident[] indexes */ + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, + EI_DATA = 5, + EI_VERSION = 6, + EI_OSABI = 7, + EI_PAD = 8 + }; -enum -{ - EV_NONE = 0, // Invalid version - EV_CURRENT = 1 // Current version -}; + enum ElfClass + { + ELFCLASSNONE = 0, /* EI_CLASS */ + ELFCLASS32 = 1, + ELFCLASS64 = 2, + ELFCLASSNUM = 3 + }; + + enum ElfData + { + ELFDATANONE = 0, /* e_ident[EI_DATA] */ + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 + }; + + enum ElfVersion + { + EV_NONE = 0, /* e_version, EI_VERSION */ + EV_CURRENT = 1, + EV_NUM = 2, + }; + + enum ElfOsAbi + { + ELFOSABI_NONE = 0, + ELFOSABI_LINUX =3 + }; + -#define ELF_MAGIC "\177ELF" + /* + * Notes used in ET_CORE. Architectures export some of the arch register sets + * using the corresponding note types via the PTRACE_GETREGSET and + * PTRACE_SETREGSET requests. + */ + enum NoteType + { + NT_PRSTATUS = 1, + NT_PRFPREG = 2, + NT_PRPSINFO = 3, + NT_TASKSTRUCT = 4, + NT_AUXV = 6, + /* + * Note to userspace developers: size of NT_SIGINFO note may increase + * in the future to accomodate more fields, don't assume it is fixed! + */ + NT_SIGINFO = 0x53494749, + NT_FILE = 0x46494c45, + NT_PRXFPREG = 0x46e62b7f, /* copied from gdb5.1/include/elf/common.h */ + NT_PPC_VMX = 0x100, /* PowerPC Altivec/VMX registers */ + NT_PPC_SPE = 0x101, /* PowerPC SPE/EVR registers */ + NT_PPC_VSX = 0x102, /* PowerPC VSX registers */ + NT_PPC_TAR = 0x103, /* Target Address Register */ + NT_PPC_PPR = 0x104, /* Program Priority Register */ + NT_PPC_DSCR = 0x105, /* Data Stream Control Register */ + NT_PPC_EBB = 0x106, /* Event Based Branch Registers */ + NT_PPC_PMU = 0x107, /* Performance Monitor Registers */ + NT_PPC_TM_CGPR = 0x108, /* TM checkpointed GPR Registers */ + NT_PPC_TM_CFPR = 0x109, /* TM checkpointed FPR Registers */ + NT_PPC_TM_CVMX = 0x10a, /* TM checkpointed VMX Registers */ + NT_PPC_TM_CVSX = 0x10b, /* TM checkpointed VSX Registers */ + NT_PPC_TM_SPR = 0x10c, /* TM Special Purpose Registers */ + NT_PPC_TM_CTAR = 0x10d, /* TM checkpointed Target Address Register */ + NT_PPC_TM_CPPR = 0x10e, /* TM checkpointed Program Priority Register */ + NT_PPC_TM_CDSCR = 0x10f, /* TM checkpointed Data Stream Control Register */ + NT_PPC_PKEY = 0x110, /* Memory Protection Keys registers */ + NT_386_TLS = 0x200, /* i386 TLS slots (struct user_desc) */ + NT_386_IOPERM = 0x201, /* x86 io permission bitmap (1=deny) */ + NT_X86_XSTATE = 0x202, /* x86 extended state using xsave */ + NT_S390_HIGH_GPRS = 0x300, /* s390 upper register halves */ + NT_S390_TIMER = 0x301, /* s390 timer register */ + NT_S390_TODCMP = 0x302, /* s390 TOD clock comparator register */ + NT_S390_TODPREG = 0x303, /* s390 TOD programmable register */ + NT_S390_CTRS = 0x304, /* s390 control registers */ + NT_S390_PREFIX = 0x305, /* s390 prefix register */ + NT_S390_LAST_BREAK = 0x306, /* s390 breaking event address */ + NT_S390_SYSTEM_CALL = 0x307, /* s390 system call restart data */ + NT_S390_TDB = 0x308, /* s390 transaction diagnostic block */ + NT_S390_VXRS_LOW = 0x309, /* s390 vector registers 0-15 upper half */ + NT_S390_VXRS_HIGH = 0x30a, /* s390 vector registers 16-31 */ + NT_S390_GS_CB = 0x30b, /* s390 guarded storage registers */ + NT_S390_GS_BC = 0x30c, /* s390 guarded storage broadcast control block */ + NT_S390_RI_CB = 0x30d, /* s390 runtime instrumentation */ + NT_ARM_VFP = 0x400, /* ARM VFP/NEON registers */ + NT_ARM_TLS = 0x401, /* ARM TLS register */ + NT_ARM_HW_BREAK = 0x402, /* ARM hardware breakpoint registers */ + NT_ARM_HW_WATCH = 0x403, /* ARM hardware watchpoint registers */ + NT_ARM_SYSTEM_CALL = 0x404, /* ARM system call number */ + NT_ARM_SVE = 0x405, /* ARM Scalable Vector Extension registers */ + NT_ARC_V2 = 0x600, /* ARCv2 accumulator/extra registers */ + NT_VMCOREDD = 0x700, /* Vmcore Device Dump Note */ + NT_MIPS_DSP = 0x800, /* MIPS DSP ASE registers */ + NT_MIPS_FP_MODE = 0x801, /* MIPS floating-point mode */ + }; + + static const size_t kEIdentSize = 0x10; + static const byte_t kElfMagic[sizeof(uint32_t)] = {0x7f, 'E', 'L', 'F'}; -enum -{ - ELFDATANONE = 0, // Invalid data encoding - ELFDATA2LSB = 1, // Little endian - ELFDATA2MSB = 2, // Big endian -}; -enum -{ - PT_NULL = 0, // Unused - PT_LOAD = 1, // Loadable segment - PT_DYNAMIC = 2, // Dynamic linking information - PT_INTERP = 3, // Interpreter - PT_NOTE = 4, // Auxiliary information - PT_SHLIB = 5, // Reserved - PT_PHDR = 6 // Program header table -}; + inline byte_t get_elf_st_bind(byte_t st_info) { return st_info >> 4; } + inline byte_t get_elf_st_type(byte_t st_info) { return st_info & 0xf; } + inline byte_t get_elf_st_info(byte_t st_bind, byte_t st_type) { return (st_type & 0xf) | ((st_bind & 0xf) << 4);} -enum -{ - PF_R = 4, // Read flag - PF_W = 2, // Write flag - PF_X = 1, // Execute flag - PF_OS_SHARED = 0x100000, // OS-specific - PF_CTRSDK = 0x80000000, // Set in CTRSDK ELF Text segments -}; + /* The following are used with relocations */ + #define ELF32_R_SYM(x) ((x) >> 8) + #define ELF32_R_TYPE(x) ((x) & 0xff) -enum -{ - SHN_LORESERVE = 0xFF00, - SHN_HIRESERVE = 0xFFFF -}; + #define ELF64_R_SYM(i) ((i) >> 32) + #define ELF64_R_TYPE(i) ((i) & 0xffffffff) + } -enum -{ - SHT_NULL = 0, // Inactive - SHT_PROGBITS = 1, // Program defined information - SHT_SYMTAB = 2, // Symbol table section - SHT_STRTAB = 3, // String table section - SHT_RELA = 4, // Relocation section with addends - SHT_HASH = 5, // Symbol hash table section - SHT_DYNAMIC = 6, // Dynamic section - SHT_NOTE = 7, // Note section - SHT_NOBITS = 8, // No space section - SHT_REL = 9, // Relation section without addends - SHT_SHLIB = 10, // Reserved - SHT_DYNSYM = 11, // Dynamic symbol table section - SHT_NUM = 12, // Number of section types - SHT_LOPROC = 0x70000000, // Reserved range for processor - SHT_ARM_EXIDX = 0x70000001, // ARM exception index table - SHT_HIPROC = 0x7fffffff, // Specific section header types - SHT_LOUSER = 0x80000000, // Reserved range for application - SHT_HIUSER = 0xffffffff // Specific indexes -}; + struct Elf32_Dyn + { + int32_t d_tag; + union{ + int32_t d_val; + uint32_t d_ptr; + } d_un; + }; -enum -{ - SHF_WRITE = 1, // Writable section - SHF_ALLOC = 2, // Loadable section - SHF_EXECINSTR = 4, // Executable section - SHF_MASKPROC = 0xf0000000, // Processor-specific -}; + struct Elf64_Dyn + { + int64_t d_tag; /* entry tag value */ + union { + uint64_t d_val; + uint64_t d_ptr; + } d_un; + }; -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + struct Elf32_Rel + { + uint32_t r_offset; + uint32_t r_info; + }; -enum -{ - R_ARM_NONE = 0, - R_ARM_PC24 = 1, - R_ARM_ABS32 = 2, - R_ARM_REL32 = 3, - R_ARM_THM_CALL = 10, - R_ARM_PLT32 = 27, - R_ARM_CALL = 28, - R_ARM_JUMP24 = 29, - R_ARM_TARGET1 = 38, - R_ARM_TARGET2 = 41, - R_ARM_PREL31 = 42, - R_ARM_THM_JUMP11 = 102, - R_ARM_THM_JUMP8 = 103 -}; + struct Elf64_Rel + { + uint64_t r_offset; /* Location at which to apply the action */ + uint64_t r_info; /* index and type of relocation */ + }; -// Symbol scope -enum -{ - STB_LOCAL = 0, - STB_GLOBAL = 1, - STB_WEAK = 2 -}; + struct Elf32_Rela + { + uint32_t r_offset; + uint32_t r_info; + int32_t r_addend; + }; -#define ELF32_ST_BIND(i) (((unsigned char)(i)) >> 4) -#define ELF32_ST_TYPE(val) ((val) & 0xf) + struct Elf64_Rela + { + uint64_t r_offset; /* Location at which to apply the action */ + uint64_t r_info; /* index and type of relocation */ + int64_t r_addend; /* Constant addend used to compute value */ + }; -// Symbol type -enum -{ - STT_NOTYPE = 0, - STT_OBJECT = 1, - STT_FUNC = 2 -}; + struct Elf32_Sym + { + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + byte_t st_info; + byte_t st_other; + uint16_t st_shndx; + }; -// Symbol visibility -enum -{ - STV_DEFAULT = 0, - STV_INTERNAL = 1, - STV_HIDDEN = 2, - STV_PROTECTED = 3 -}; + struct Elf64_Sym + { + uint32_t st_name; /* Symbol name, index in string tbl */ + byte_t st_info; /* Type and binding attributes */ + byte_t st_other; /* No defined meaning, 0 */ + uint16_t st_shndx; /* Associated section index */ + uint64_t st_value; /* Value of the symbol */ + uint64_t st_size; /* Associated symbol size */ + }; + + struct Elf32_Ehdr + { + byte_t e_ident[elf::kEIdentSize]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; /* Entry point */ + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + }; + + struct Elf64_Ehdr + { + byte_t e_ident[elf::kEIdentSize]; /* ELF "magic number" */ + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; /* Entry point virtual address */ + uint64_t e_phoff; /* Program header table file offset */ + uint64_t e_shoff; /* Section header table file offset */ + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + }; + + struct Elf32_Phdr + { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; + }; + + struct Elf64_Phdr + { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; /* Segment file offset */ + uint64_t p_vaddr; /* Segment virtual address */ + uint64_t p_paddr; /* Segment physical address */ + uint64_t p_filesz; /* Segment size in file */ + uint64_t p_memsz; /* Segment size in memory */ + uint64_t p_align; /* Segment alignment, file & memory */ + }; + + struct Elf32_Shdr + { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; + }; + + struct Elf64_Shdr + { + uint32_t sh_name; /* Section name, index in string tbl */ + uint32_t sh_type; /* Type of section */ + uint64_t sh_flags; /* Miscellaneous section attributes */ + uint64_t sh_addr; /* Section virtual addr at execution */ + uint64_t sh_offset; /* Section file offset */ + uint64_t sh_size; /* Size of section in bytes */ + uint32_t sh_link; /* Index of another section */ + uint32_t sh_info; /* Additional section information */ + uint64_t sh_addralign; /* Section alignment */ + uint64_t sh_entsize; /* Entry size if section holds table */ + }; + + /* Note header in a PT_NOTE section */ + struct Elf32_Nhdr + { + uint32_t n_namesz; /* Name size */ + uint32_t n_descsz; /* Content size */ + uint32_t n_type; /* Content type */ + }; + + /* Note header in a PT_NOTE section */ + struct Elf64_Nhdr + { + uint32_t n_namesz; /* Name size */ + uint32_t n_descsz; /* Content size */ + uint32_t n_type; /* Content type */ + }; +} \ No newline at end of file diff --git a/lib/libhac/include/nn/hac/elf.h b/lib/libhac/include/nn/hac/elf.h deleted file mode 100644 index 2083238..0000000 --- a/lib/libhac/include/nn/hac/elf.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include - -namespace nn -{ -namespace hac -{ - namespace elf - { - enum SpecialSectionIndex - { - SHN_UNDEF, - SHN_LORESERVE = 0xFF00, - SHN_LOPROC = 0xFF00, - SHN_HIPROC = 0xFF1F, - SHN_LOOS, - SHN_HIOS = 0xFF3F, - SHN_ABS = 0xFFF1, - SHN_COMMON, - SHN_HIRESERVE = 0xFFFF - }; - - enum SymbolType - { - STT_NOTYPE, - STT_OBJECT, - STT_FUNC, - STT_SECTION, - STT_FILE, - STT_LOOS = 10, - STT_HIOS = 12, - STT_LOPROC, - STT_HIPROC = 0xF - }; - - enum SymbolBinding - { - STB_LOCAL, - STB_GLOBAL, - STB_WEAK, - STB_LOOS = 10, - STB_HIOS = 12, - STB_LOPROC, - STB_HIPROC = 0xF - }; - } - -#pragma pack(push,1) - struct sElfSymbol32Bit - { - le_uint32_t name; - le_uint32_t value; - le_uint32_t size; - le_uint32_t info; - le_uint32_t other; - le_uint32_t special_section_index; - }; - - struct sElfSymbol64Bit - { - le_uint32_t name; - byte_t info; - byte_t other; - le_uint16_t special_section_index; - le_uint64_t value; - le_uint64_t size; - }; -#pragma pack(pop) -} -} \ No newline at end of file diff --git a/programs/nstool/source/ElfSymbolParser.cpp b/programs/nstool/source/ElfSymbolParser.cpp index acac3d0..9f4bed9 100644 --- a/programs/nstool/source/ElfSymbolParser.cpp +++ b/programs/nstool/source/ElfSymbolParser.cpp @@ -23,37 +23,38 @@ bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit) { //printf("ElfSymbolParser::parseData()"); - size_t dynSymSize = is64Bit ? sizeof(nn::hac::sElfSymbol64Bit) : sizeof(nn::hac::sElfSymbol32Bit); + size_t dynSymSize = is64Bit ? sizeof(fnd::Elf64_Sym) : sizeof(fnd::Elf32_Sym); sElfSymbol symbol; for (size_t i = 0; i < dyn_sym_size; i += dynSymSize) { - //printf("pos %x\n", i); - uint32_t name_pos; if (is64Bit) { - name_pos = ((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->name.get(); - symbol.shn_index = (nn::hac::elf::SpecialSectionIndex)((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->special_section_index.get(); - symbol.symbol_type = (nn::hac::elf::SymbolType)((((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->info) & nn::hac::elf::STT_HIPROC); - symbol.symbol_binding = (nn::hac::elf::SymbolBinding)(((((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->info) >> 4) & nn::hac::elf::STB_HIPROC); + name_pos = le_word(((fnd::Elf64_Sym*)(dyn_sym + i))->st_name); + symbol.shn_index = le_hword(((fnd::Elf64_Sym*)(dyn_sym + i))->st_shndx); + symbol.symbol_type = fnd::elf::get_elf_st_type(((fnd::Elf64_Sym*)(dyn_sym + i))->st_info); + symbol.symbol_binding = fnd::elf::get_elf_st_bind(((fnd::Elf64_Sym*)(dyn_sym + i))->st_info); } else { - name_pos = ((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->name.get(); - symbol.shn_index = (nn::hac::elf::SpecialSectionIndex)((nn::hac::sElfSymbol32Bit*)(dyn_sym + i))->special_section_index.get(); - symbol.symbol_type = (nn::hac::elf::SymbolType)((((nn::hac::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) & nn::hac::elf::STT_HIPROC); - symbol.symbol_binding = (nn::hac::elf::SymbolBinding)(((((nn::hac::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) >> 4) & nn::hac::elf::STB_HIPROC); + name_pos = le_word(((fnd::Elf32_Sym*)(dyn_sym + i))->st_name); + symbol.shn_index = le_hword(((fnd::Elf32_Sym*)(dyn_sym + i))->st_shndx); + symbol.symbol_type = fnd::elf::get_elf_st_type(((fnd::Elf32_Sym*)(dyn_sym + i))->st_info); + symbol.symbol_binding = fnd::elf::get_elf_st_bind(((fnd::Elf32_Sym*)(dyn_sym + i))->st_info); + } + + if (name_pos >= dyn_str_size) + { + throw fnd::Exception(kModuleName, "Out of bounds symbol name offset"); } for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++); - //printf("name_pos = 0x%x\n", name_pos); symbol.name = std::string((char*)&dyn_str[name_pos]); mSymbolList.addElement(symbol); } - //printf("ElfSymbolParser::parseData() end\n"); } const fnd::List& ElfSymbolParser::getSymbolList() const diff --git a/programs/nstool/source/ElfSymbolParser.h b/programs/nstool/source/ElfSymbolParser.h index a4e4b5c..e06bdf3 100644 --- a/programs/nstool/source/ElfSymbolParser.h +++ b/programs/nstool/source/ElfSymbolParser.h @@ -1,16 +1,16 @@ #pragma once #include #include -#include +#include class ElfSymbolParser { public: struct sElfSymbol { - nn::hac::elf::SpecialSectionIndex shn_index; - nn::hac::elf::SymbolType symbol_type; - nn::hac::elf::SymbolBinding symbol_binding; + uint16_t shn_index; + byte_t symbol_type; + byte_t symbol_binding; std::string name; void operator=(const sElfSymbol& other) @@ -42,6 +42,7 @@ public: const fnd::List& getSymbolList() const; private: + const std::string kModuleName = "ElfSymbolParser"; // data fnd::List mSymbolList; diff --git a/programs/nstool/source/RoMetadataProcess.cpp b/programs/nstool/source/RoMetadataProcess.cpp index afbb982..6d0f4ba 100644 --- a/programs/nstool/source/RoMetadataProcess.cpp +++ b/programs/nstool/source/RoMetadataProcess.cpp @@ -177,30 +177,30 @@ void RoMetadataProcess::displayRoMetaData() } } -const char* RoMetadataProcess::getSectionIndexStr(nn::hac::elf::SpecialSectionIndex shn_index) const +const char* RoMetadataProcess::getSectionIndexStr(uint16_t shn_index) const { const char* str; switch (shn_index) { - case (nn::hac::elf::SHN_UNDEF): + case (fnd::elf::SHN_UNDEF): str = "UNDEF"; break; - case (nn::hac::elf::SHN_LOPROC): + case (fnd::elf::SHN_LOPROC): str = "LOPROC"; break; - case (nn::hac::elf::SHN_HIPROC): + case (fnd::elf::SHN_HIPROC): str = "HIPROC"; break; - case (nn::hac::elf::SHN_LOOS): + case (fnd::elf::SHN_LOOS): str = "LOOS"; break; - case (nn::hac::elf::SHN_HIOS): + case (fnd::elf::SHN_HIOS): str = "HIOS"; break; - case (nn::hac::elf::SHN_ABS): + case (fnd::elf::SHN_ABS): str = "ABS"; break; - case (nn::hac::elf::SHN_COMMON): + case (fnd::elf::SHN_COMMON): str = "COMMON"; break; default: @@ -210,36 +210,36 @@ const char* RoMetadataProcess::getSectionIndexStr(nn::hac::elf::SpecialSectionIn return str; } -const char* RoMetadataProcess::getSymbolTypeStr(nn::hac::elf::SymbolType symbol_type) const +const char* RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const { const char* str; switch (symbol_type) { - case (nn::hac::elf::STT_NOTYPE): + case (fnd::elf::STT_NOTYPE): str = "NOTYPE"; break; - case (nn::hac::elf::STT_OBJECT): + case (fnd::elf::STT_OBJECT): str = "OBJECT"; break; - case (nn::hac::elf::STT_FUNC): + case (fnd::elf::STT_FUNC): str = "FUNC"; break; - case (nn::hac::elf::STT_SECTION): + case (fnd::elf::STT_SECTION): str = "SECTION"; break; - case (nn::hac::elf::STT_FILE): + case (fnd::elf::STT_FILE): str = "FILE"; break; - case (nn::hac::elf::STT_LOOS): + case (fnd::elf::STT_LOOS): str = "LOOS"; break; - case (nn::hac::elf::STT_HIOS): + case (fnd::elf::STT_HIOS): str = "HIOS"; break; - case (nn::hac::elf::STT_LOPROC): + case (fnd::elf::STT_LOPROC): str = "LOPROC"; break; - case (nn::hac::elf::STT_HIPROC): + case (fnd::elf::STT_HIPROC): str = "HIPROC"; break; default: @@ -249,30 +249,30 @@ const char* RoMetadataProcess::getSymbolTypeStr(nn::hac::elf::SymbolType symbol_ return str; } -const char* RoMetadataProcess::getSymbolBindingStr(nn::hac::elf::SymbolBinding symbol_binding) const +const char* RoMetadataProcess::getSymbolBindingStr(byte_t symbol_binding) const { const char* str; switch (symbol_binding) { - case (nn::hac::elf::STB_LOCAL): + case (fnd::elf::STB_LOCAL): str = "LOCAL"; break; - case (nn::hac::elf::STB_GLOBAL): + case (fnd::elf::STB_GLOBAL): str = "GLOBAL"; break; - case (nn::hac::elf::STB_WEAK): + case (fnd::elf::STB_WEAK): str = "WEAK"; break; - case (nn::hac::elf::STB_LOOS): + case (fnd::elf::STB_LOOS): str = "LOOS"; break; - case (nn::hac::elf::STB_HIOS): + case (fnd::elf::STB_HIOS): str = "HIOS"; break; - case (nn::hac::elf::STB_LOPROC): + case (fnd::elf::STB_LOPROC): str = "LOPROC"; break; - case (nn::hac::elf::STB_HIPROC): + case (fnd::elf::STB_HIPROC): str = "HIPROC"; break; default: diff --git a/programs/nstool/source/RoMetadataProcess.h b/programs/nstool/source/RoMetadataProcess.h index 84ff4af..e1dbff2 100644 --- a/programs/nstool/source/RoMetadataProcess.h +++ b/programs/nstool/source/RoMetadataProcess.h @@ -62,7 +62,7 @@ private: void importApiList(); void displayRoMetaData(); - const char* getSectionIndexStr(nn::hac::elf::SpecialSectionIndex shn_index) const; - const char* getSymbolTypeStr(nn::hac::elf::SymbolType symbol_type) const; - const char* getSymbolBindingStr(nn::hac::elf::SymbolBinding symbol_binding) const; + const char* getSectionIndexStr(uint16_t shn_index) const; + const char* getSymbolTypeStr(byte_t symbol_type) const; + const char* getSymbolBindingStr(byte_t symbol_binding) const; }; \ No newline at end of file diff --git a/programs/nstool/source/version.h b/programs/nstool/source/version.h index 90f7950..88311a6 100644 --- a/programs/nstool/source/version.h +++ b/programs/nstool/source/version.h @@ -1,5 +1,5 @@ #pragma once #define VER_MAJOR 1 #define VER_MINOR 0 -#define VER_PATCH 2 +#define VER_PATCH 3 #define AUTHORS "jakcron" \ No newline at end of file From 2c328c40b15d7914acf3069f08d8708163b22ac3 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 16:43:40 +0800 Subject: [PATCH 30/50] [nstool] Fix bug in ElfSymbolParser --- programs/nstool/source/ElfSymbolParser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/programs/nstool/source/ElfSymbolParser.cpp b/programs/nstool/source/ElfSymbolParser.cpp index 9f4bed9..b57c9f2 100644 --- a/programs/nstool/source/ElfSymbolParser.cpp +++ b/programs/nstool/source/ElfSymbolParser.cpp @@ -22,7 +22,6 @@ bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit) { - //printf("ElfSymbolParser::parseData()"); size_t dynSymSize = is64Bit ? sizeof(fnd::Elf64_Sym) : sizeof(fnd::Elf32_Sym); sElfSymbol symbol; @@ -50,7 +49,7 @@ void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, cons throw fnd::Exception(kModuleName, "Out of bounds symbol name offset"); } - for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++); + //for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++); symbol.name = std::string((char*)&dyn_str[name_pos]); mSymbolList.addElement(symbol); From 61c3cb8cf3c7b724c5db9f7ab984ff8a769b6b37 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 16:44:40 +0800 Subject: [PATCH 31/50] [nstool] Fix bug in UserSettings where NSO files were incorrectly identified as NACP. --- programs/nstool/source/UserSettings.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index e9ad32e..5b837b0 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -626,7 +626,7 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str) FileType UserSettings::determineFileTypeFromFile(const std::string& path) { - static const size_t kMaxReadSize = 0x4000; + static const size_t kMaxReadSize = 0x5000; FileType file_type = FILE_INVALID; fnd::SimpleFile file; fnd::Vec scratch; @@ -640,6 +640,8 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path) // close file file.close(); + fnd::SimpleTextOutput::hxdStyleDump(scratch.data(), 0x100); + // _TYPE_PTR resolves to a pointer of type 'st' located at scratch.data() #define _TYPE_PTR(st) ((st*)(scratch.data())) #define _ASSERT_SIZE(sz) (scratch.size() >= (sz)) @@ -662,12 +664,6 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path) // test nca else if (determineValidNcaFromSample(scratch)) file_type = FILE_NCA; - // test cnmt - else if (determineValidCnmtFromSample(scratch)) - file_type = FILE_CNMT; - // test nacp - else if (determineValidNacpFromSample(scratch)) - file_type = FILE_NACP; // test nso else if (_ASSERT_SIZE(sizeof(nn::hac::sNsoHeader)) && _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.get() == nn::hac::nso::kNsoStructMagic) file_type = FILE_NSO; @@ -683,6 +679,16 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path) // test hb asset else if (_ASSERT_SIZE(sizeof(nn::hac::sAssetHeader)) && _TYPE_PTR(nn::hac::sAssetHeader)->st_magic.get() == nn::hac::aset::kAssetStructMagic) file_type = FILE_HB_ASSET; + + // do heuristics + // test cnmt + else if (determineValidCnmtFromSample(scratch)) + file_type = FILE_CNMT; + // test nacp + else if (determineValidNacpFromSample(scratch)) + file_type = FILE_NACP; + + // else unrecognised else file_type = FILE_INVALID; From 3707969d7b7c1b729434333691d98715f6e85624 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 17:06:48 +0800 Subject: [PATCH 32/50] [nstool] Removed debug code. --- programs/nstool/source/UserSettings.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index 5b837b0..fd4cf97 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -640,8 +640,6 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path) // close file file.close(); - fnd::SimpleTextOutput::hxdStyleDump(scratch.data(), 0x100); - // _TYPE_PTR resolves to a pointer of type 'st' located at scratch.data() #define _TYPE_PTR(st) ((st*)(scratch.data())) #define _ASSERT_SIZE(sz) (scratch.size() >= (sz)) From bba9d21a47618077702fbe38f3b1fcac763cf19c Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 19:54:46 +0800 Subject: [PATCH 33/50] [fnd|polarssl] Added rsa-pss sign support. --- lib/libfnd/include/fnd/rsa.h | 2 +- lib/libfnd/source/rsa_wrapper.cpp | 29 + lib/libpolarssl/include/polarssl/config.h | 6 +- lib/libpolarssl/include/polarssl/ctr_drbg.h | 234 ++++++ lib/libpolarssl/include/polarssl/entropy.h | 180 +++++ .../include/polarssl/entropy_poll.h | 72 ++ lib/libpolarssl/include/polarssl/sha4.h | 183 +++++ lib/libpolarssl/libpolarssl.vcxproj | 14 +- lib/libpolarssl/libpolarssl.vcxproj.filters | 38 +- lib/libpolarssl/source/ctr_drbg.c | 582 +++++++++++++ lib/libpolarssl/source/entropy.c | 261 ++++++ lib/libpolarssl/source/entropy_poll.c | 133 +++ lib/libpolarssl/source/sha4.c | 762 ++++++++++++++++++ 13 files changed, 2482 insertions(+), 14 deletions(-) create mode 100644 lib/libpolarssl/include/polarssl/ctr_drbg.h create mode 100644 lib/libpolarssl/include/polarssl/entropy.h create mode 100644 lib/libpolarssl/include/polarssl/entropy_poll.h create mode 100644 lib/libpolarssl/include/polarssl/sha4.h create mode 100644 lib/libpolarssl/source/ctr_drbg.c create mode 100644 lib/libpolarssl/source/entropy.c create mode 100644 lib/libpolarssl/source/entropy_poll.c create mode 100644 lib/libpolarssl/source/sha4.c diff --git a/lib/libfnd/include/fnd/rsa.h b/lib/libfnd/include/fnd/rsa.h index 455fd21..fd05987 100644 --- a/lib/libfnd/include/fnd/rsa.h +++ b/lib/libfnd/include/fnd/rsa.h @@ -114,7 +114,7 @@ namespace fnd //int rsaSign(const sRsa1024Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa1024Size]); //int rsaVerify(const sRsa1024Key& key, sha::HashType hash_type, const uint8_t* hash, const uint8_t signature[kRsa1024Size]); // rsa2048 - //int rsaSign(const sRsa2048Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa2048Size]); + int rsaSign(const sRsa2048Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa2048Size]); int rsaVerify(const sRsa2048Key& key, sha::HashType hash_type, const uint8_t* hash, const uint8_t signature[kRsa2048Size]); // rsa4096 //int rsaSign(const sRsa4096Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa4096Size]); diff --git a/lib/libfnd/source/rsa_wrapper.cpp b/lib/libfnd/source/rsa_wrapper.cpp index 197a813..c6aee2a 100644 --- a/lib/libfnd/source/rsa_wrapper.cpp +++ b/lib/libfnd/source/rsa_wrapper.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include using namespace fnd::rsa; using namespace fnd::sha; @@ -165,6 +167,33 @@ int fnd::rsa::pkcs::rsaVerify(const sRsa4096Key & key, HashType hash_type, const return ret; } +int fnd::rsa::pss::rsaSign(const sRsa2048Key & key, HashType hash_type, const uint8_t * hash, uint8_t signature[kRsa2048Size]) +{ + int ret; + const char* pers = "fnd::rsa::pss::rsaSign"; + + // rsa + rsa_context rsa; + rsa_init(&rsa, RSA_PKCS_V21, getMdWrappedHashType(hash_type)); + rsa.len = kRsa2048Size; + mpi_read_binary(&rsa.D, key.priv_exponent, rsa.len); + mpi_read_binary(&rsa.N, key.modulus, rsa.len); + + entropy_context entropy; + entropy_init(&entropy); + + ctr_drbg_context ctr_drbg; + ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const uint8_t*)pers, strlen(pers)); + + ret = rsa_rsassa_pss_sign(&rsa, ctr_drbg_random, &ctr_drbg, RSA_PRIVATE, getWrappedHashType(hash_type), getWrappedHashSize(hash_type), hash, signature); + + rsa_free(&rsa); + + + return ret; +} + + int fnd::rsa::pss::rsaVerify(const sRsa2048Key & key, HashType hash_type, const uint8_t * hash, const uint8_t signature[kRsa2048Size]) { static const uint8_t public_exponent[3] = { 0x01, 0x00, 0x01 }; diff --git a/lib/libpolarssl/include/polarssl/config.h b/lib/libpolarssl/include/polarssl/config.h index ae0d486..035238b 100644 --- a/lib/libpolarssl/include/polarssl/config.h +++ b/lib/libpolarssl/include/polarssl/config.h @@ -506,7 +506,7 @@ * * This module provides the CTR_DRBG AES-256 random number generator. */ -//#define POLARSSL_CTR_DRBG_C +#define POLARSSL_CTR_DRBG_C /** * \def POLARSSL_DEBUG_C @@ -578,7 +578,7 @@ * * This module provides a generic entropy pool */ -//#define POLARSSL_ENTROPY_C +#define POLARSSL_ENTROPY_C /** * \def POLARSSL_ERROR_C @@ -838,7 +838,7 @@ * * This module adds support for SHA-384 and SHA-512. */ -//#define POLARSSL_SHA4_C +#define POLARSSL_SHA4_C /** * \def POLARSSL_SSL_CACHE_C diff --git a/lib/libpolarssl/include/polarssl/ctr_drbg.h b/lib/libpolarssl/include/polarssl/ctr_drbg.h new file mode 100644 index 0000000..6f81af8 --- /dev/null +++ b/lib/libpolarssl/include/polarssl/ctr_drbg.h @@ -0,0 +1,234 @@ +/** + * \file ctr_drbg.h + * + * \brief CTR_DRBG based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CTR_DRBG_H +#define POLARSSL_CTR_DRBG_H + +#include + +#include "aes.h" + +#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */ +#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */ +#define CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */ +#define CTR_DRBG_KEYBITS ( CTR_DRBG_KEYSIZE * 8 ) +#define CTR_DRBG_SEEDLEN ( CTR_DRBG_KEYSIZE + CTR_DRBG_BLOCKSIZE ) + /**< The seed length (counter + AES key) */ + +#if !defined(POLARSSL_CONFIG_OPTIONS) +#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default */ +#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +#define CTR_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CTR_DRBG context structure + */ +typedef struct +{ + unsigned char counter[16]; /*!< counter (V) */ + int reseed_counter; /*!< reseed counter */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + size_t entropy_len; /*!< amount of entropy grabbed on each (re)seed */ + int reseed_interval; /*!< reseed interval */ + + aes_context aes_ctx; /*!< AES context */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + + void *p_entropy; /*!< context for the entropy function */ +} +ctr_drbg_context; + +/** + * \brief CTR_DRBG initialization + * + * Note: Personalization data can be provided in addition to the more generic + * entropy source to make this instantiation as unique as possible. + * + * \param ctx CTR_DRBG context to be initialized + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_init( ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx CTR_DRBG context + * \param resistance CTR_DRBG_PR_ON or CTR_DRBG_PR_OFF + */ +void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each (re)seed + * (Default: CTR_DRBG_ENTROPY_LEN) + * + * \param ctx CTR_DRBG context + * \param len Amount of entropy to grab + */ +void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: CTR_DRBG_RESEED_INTERVAL) + * + * \param ctx CTR_DRBG context + * \param interval Reseed interval + */ +void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx, + int interval ); + +/** + * \brief CTR_DRBG reseeding (extracts data from entropy source) + * + * \param ctx CTR_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_reseed( ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG context + * \param additional Additional data to update state with + * \param add_len Length of additional data + * + * \note If add_len is greater than CTR_DRBG_MAX_SEED_INPUT, + * only the first CTR_DRBG_MAX_SEED_INPUT bytes are used, + * the remaining ones are silently discarded. + */ +void ctr_drbg_update( ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (Can be NULL) + * \param add_len Length of additional data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Write a seed file + * + * \param path Name of the file + * + * \return 0 if successful, + * POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR on file error, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param path Name of the file + * + * \return 0 if successful, + * POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR on file error, + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG + */ +int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path ); +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int ctr_drbg_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/lib/libpolarssl/include/polarssl/entropy.h b/lib/libpolarssl/include/polarssl/entropy.h new file mode 100644 index 0000000..7ce7a5a --- /dev/null +++ b/lib/libpolarssl/include/polarssl/entropy.h @@ -0,0 +1,180 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ENTROPY_H +#define POLARSSL_ENTROPY_H + +#include + +#include "config.h" + +#include "sha4.h" +#if defined(POLARSSL_HAVEGE_C) +#include "havege.h" +#endif + +#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define POLARSSL_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ +#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR -0x0058 /**< Read/write error in file. */ + +#if !defined(POLARSSL_CONFIG_OPTIONS) +#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +#define ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ + +#define ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */ +#define ENTROPY_SOURCE_MANUAL ENTROPY_MAX_SOURCES + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * POLARSSL_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*f_source_ptr)(void *data, unsigned char *output, size_t len, size_t *olen); + +/** + * \brief Entropy source state + */ +typedef struct +{ + f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received */ + size_t threshold; /**< Minimum level required before release */ +} +source_state; + +/** + * \brief Entropy context structure + */ +typedef struct +{ + sha4_context accumulator; + int source_count; + source_state source[ENTROPY_MAX_SOURCES]; +#if defined(POLARSSL_HAVEGE_C) + havege_state havege_data; +#endif +} +entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void entropy_init( entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with entropy_func() ) + * + * \return 0 if successful or POLARSSL_ERR_ENTROPY_MAX_SOURCES + */ +int entropy_add_source( entropy_context *ctx, + f_source_ptr f_source, void *p_source, + size_t threshold ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * + * \param ctx Entropy context + * + * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_gather( entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator (Max ENTROPY_BLOCK_SIZE) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int entropy_update_manual( entropy_context *ctx, + const unsigned char *data, size_t len ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * POLARSSL_ERR_ENTROPY_FILE_IO_ERROR on file error, or + * POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_write_seed_file( entropy_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance. No more than ENTROPY_MAX_SEED_SIZE bytes are + * read from the seed file. The rest is ignored. + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * POLARSSL_ERR_ENTROPY_FILE_IO_ERROR on file error, + * POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_update_seed_file( entropy_context *ctx, const char *path ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/lib/libpolarssl/include/polarssl/entropy_poll.h b/lib/libpolarssl/include/polarssl/entropy_poll.h new file mode 100644 index 0000000..82842ce --- /dev/null +++ b/lib/libpolarssl/include/polarssl/entropy_poll.h @@ -0,0 +1,72 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ENTROPY_POLL_H +#define POLARSSL_ENTROPY_POLL_H + +#include + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources + */ +#define ENTROPY_MIN_PLATFORM 128 /**< Minimum for platform source */ +#define ENTROPY_MIN_HAVEGE 128 /**< Minimum for HAVEGE */ +#define ENTROPY_MIN_HARDCLOCK 32 /**< Minimum for hardclock() */ + +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(POLARSSL_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(POLARSSL_TIMING_C) +/** + * \brief hardclock-based entropy poll callback + */ +int hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/lib/libpolarssl/include/polarssl/sha4.h b/lib/libpolarssl/include/polarssl/sha4.h new file mode 100644 index 0000000..fa57d4d --- /dev/null +++ b/lib/libpolarssl/include/polarssl/sha4.h @@ -0,0 +1,183 @@ +/** + * \file sha4.h + * + * \brief SHA-384 and SHA-512 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA4_H +#define POLARSSL_SHA4_H + +#include "config.h" + +#include + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 + typedef unsigned __int64 uint64_t; +#else + #include + #define UL64(x) x##ULL +#endif + +#define POLARSSL_ERR_SHA4_FILE_IO_ERROR -0x007A /**< Read/write error in file. */ + +#if !defined(POLARSSL_SHA1_ALT) +// Regular implementation +// + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + + unsigned char ipad[128]; /*!< HMAC: inner padding */ + unsigned char opad[128]; /*!< HMAC: outer padding */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +sha4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_starts( sha4_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void sha4_finish( sha4_context *ctx, unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_SHA4_ALT */ +#include "sha4_alt.h" +#endif /* POLARSSL_SHA4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Output = SHA-512( file contents ) + * + * \param path input file name + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + * + * \return 0 if successful, or POLARSSL_ERR_SHA4_FILE_IO_ERROR + */ +int sha4_file( const char *path, unsigned char output[64], int is384 ); + +/** + * \brief SHA-512 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen, + int is384 ); + +/** + * \brief SHA-512 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_hmac_update( sha4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-512 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-384/512 HMAC checksum result + */ +void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] ); + +/** + * \brief SHA-512 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha4_hmac_reset( sha4_context *ctx ); + +/** + * \brief Output = HMAC-SHA-512( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-384/512 result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha4.h */ diff --git a/lib/libpolarssl/libpolarssl.vcxproj b/lib/libpolarssl/libpolarssl.vcxproj index 18336ba..da665c4 100644 --- a/lib/libpolarssl/libpolarssl.vcxproj +++ b/lib/libpolarssl/libpolarssl.vcxproj @@ -117,30 +117,38 @@ true + + + + + + + + + + - - - + diff --git a/lib/libpolarssl/libpolarssl.vcxproj.filters b/lib/libpolarssl/libpolarssl.vcxproj.filters index 1b4bf96..035cf2a 100644 --- a/lib/libpolarssl/libpolarssl.vcxproj.filters +++ b/lib/libpolarssl/libpolarssl.vcxproj.filters @@ -14,6 +14,9 @@ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + Header Files @@ -30,6 +33,21 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + Header Files @@ -39,10 +57,7 @@ Header Files - - Header Files - - + Header Files @@ -56,6 +71,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + Source Files @@ -71,8 +95,8 @@ Source Files - - - + + Source Files + \ No newline at end of file diff --git a/lib/libpolarssl/source/ctr_drbg.c b/lib/libpolarssl/source/ctr_drbg.c new file mode 100644 index 0000000..989eb45 --- /dev/null +++ b/lib/libpolarssl/source/ctr_drbg.c @@ -0,0 +1,582 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publucation. + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_CTR_DRBG_C) + +#include "polarssl/ctr_drbg.h" + +#if defined(POLARSSL_FS_IO) +#include +#endif + +/* + * Non-public function wrapped by ctr_crbg_init(). Necessary to allow NIST + * tests to succeed (which require known length fixed entropy) + */ +int ctr_drbg_init_entropy_len( + ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ); + +int ctr_drbg_init_entropy_len( + ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ) +{ + int ret; + unsigned char key[CTR_DRBG_KEYSIZE]; + + memset( ctx, 0, sizeof(ctr_drbg_context) ); + memset( key, 0, CTR_DRBG_KEYSIZE ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->entropy_len = entropy_len; + ctx->reseed_interval = CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + aes_setkey_enc( &ctx->aes_ctx, key, CTR_DRBG_KEYBITS ); + + if( ( ret = ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int ctr_drbg_init( ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + return( ctr_drbg_init_entropy_len( ctx, f_entropy, p_entropy, custom, len, + CTR_DRBG_ENTROPY_LEN ) ); +} + +void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx, int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +static int block_cipher_df( unsigned char *output, + const unsigned char *data, size_t data_len ) +{ + unsigned char buf[CTR_DRBG_MAX_SEED_INPUT + CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[CTR_DRBG_SEEDLEN]; + unsigned char key[CTR_DRBG_KEYSIZE]; + unsigned char chain[CTR_DRBG_BLOCKSIZE]; + unsigned char *p, *iv; + aes_context aes_ctx; + + int i, j, buf_len, use_len; + + if( data_len > CTR_DRBG_MAX_SEED_INPUT ) + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( buf, 0, CTR_DRBG_MAX_SEED_INPUT + CTR_DRBG_BLOCKSIZE + 16 ); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xff; + *p++ = ( data_len >> 16 ) & 0xff; + *p++ = ( data_len >> 8 ) & 0xff; + *p++ = ( data_len ) & 0xff; + p += 3; + *p++ = CTR_DRBG_SEEDLEN; + memcpy( p, data, data_len ); + p[data_len] = 0x80; + + buf_len = CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for( i = 0; i < CTR_DRBG_KEYSIZE; i++ ) + key[i] = i; + + aes_setkey_enc( &aes_ctx, key, CTR_DRBG_KEYBITS ); + + /* + * Reduce data to POLARSSL_CTR_DRBG_SEEDLEN bytes of data + */ + for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE ) + { + p = buf; + memset( chain, 0, CTR_DRBG_BLOCKSIZE ); + use_len = buf_len; + + while( use_len > 0 ) + { + for( i = 0; i < CTR_DRBG_BLOCKSIZE; i++ ) + chain[i] ^= p[i]; + p += CTR_DRBG_BLOCKSIZE; + use_len -= CTR_DRBG_BLOCKSIZE; + + aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, chain, chain ); + } + + memcpy( tmp + j, chain, CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + aes_setkey_enc( &aes_ctx, tmp, CTR_DRBG_KEYBITS ); + iv = tmp + CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE ) + { + aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, iv, iv ); + memcpy( p, iv, CTR_DRBG_BLOCKSIZE ); + p += CTR_DRBG_BLOCKSIZE; + } + + return( 0 ); +} + +static int ctr_drbg_update_internal( ctr_drbg_context *ctx, + const unsigned char data[CTR_DRBG_SEEDLEN] ) +{ + unsigned char tmp[CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int i, j; + + memset( tmp, 0, CTR_DRBG_SEEDLEN ); + + for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE ) + { + /* + * Increase counter + */ + for( i = CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, p ); + + p += CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + aes_setkey_enc( &ctx->aes_ctx, tmp, CTR_DRBG_KEYBITS ); + memcpy( ctx->counter, tmp + CTR_DRBG_KEYSIZE, CTR_DRBG_BLOCKSIZE ); + + return( 0 ); +} + +void ctr_drbg_update( ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + unsigned char add_input[CTR_DRBG_SEEDLEN]; + + if( add_len > 0 ) + { + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > CTR_DRBG_MAX_SEED_INPUT ) + add_len = CTR_DRBG_MAX_SEED_INPUT; + + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } +} + +int ctr_drbg_reseed( ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + + if( ctx->entropy_len + len > CTR_DRBG_MAX_SEED_INPUT ) + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, CTR_DRBG_MAX_SEED_INPUT ); + + /* + * Gather enropy_len bytes of entropy to seed state + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + ctx->entropy_len ) ) + { + return( POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len; + + /* + * Add additional data + */ + if( additional && len ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* + * Reduce to 384 bits + */ + block_cipher_df( seed, seed, seedlen ); + + /* + * Update state + */ + ctr_drbg_update_internal( ctx, seed ); + ctx->reseed_counter = 1; + + return( 0 ); +} + +int ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ) +{ + int ret = 0; + ctr_drbg_context *ctx = (ctr_drbg_context *) p_rng; + unsigned char add_input[CTR_DRBG_SEEDLEN]; + unsigned char *p = output; + unsigned char tmp[CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if( output_len > CTR_DRBG_MAX_REQUEST ) + return( POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG ); + + if( add_len > CTR_DRBG_MAX_INPUT ) + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( add_input, 0, CTR_DRBG_SEEDLEN ); + + if( ctx->reseed_counter > ctx->reseed_interval || + ctx->prediction_resistance ) + { + if( ( ret = ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; + } + + if( add_len > 0 ) + { + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } + + while( output_len > 0 ) + { + /* + * Increase counter + */ + for( i = CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, tmp ); + + use_len = (output_len > CTR_DRBG_BLOCKSIZE ) ? CTR_DRBG_BLOCKSIZE : output_len; + /* + * Copy random block to destination + */ + memcpy( p, tmp, use_len ); + p += use_len; + output_len -= use_len; + } + + ctr_drbg_update_internal( ctx, add_input ); + + ctx->reseed_counter++; + + return( 0 ); +} + +int ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ) +{ + return ctr_drbg_random_with_add( p_rng, output, output_len, NULL, 0 ); +} + +#if defined(POLARSSL_FS_IO) +int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path ) +{ + int ret; + FILE *f; + unsigned char buf[ CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + + if( ( ret = ctr_drbg_random( ctx, buf, CTR_DRBG_MAX_INPUT ) ) != 0 ) + { + fclose( f ); + return( ret ); + } + + if( fwrite( buf, 1, CTR_DRBG_MAX_INPUT, f ) != CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} + +int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + ctr_drbg_update( ctx, buf, n ); + + fclose( f ); + + return( ctr_drbg_write_seed_file( ctx, path ) ); +} +#endif /* POLARSSL_FS_IO */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +unsigned char entropy_source_pr[96] = + { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16, + 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02, + 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b, + 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb, + 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9, + 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95, + 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63, + 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3, + 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31, + 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4, + 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56, + 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 }; + +unsigned char entropy_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + +unsigned char nonce_pers_pr[16] = + { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2, + 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c }; + +unsigned char nonce_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + +unsigned char result_pr[16] = + { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f, + 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 }; + +unsigned char result_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + +static size_t test_offset; +static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, + size_t len ) +{ + unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += 32; + return( 0 ); +} + +/* + * Checkup routine + */ +int ctr_drbg_self_test( int verbose ) +{ + ctr_drbg_context ctx; + unsigned char buf[16]; + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if( verbose != 0 ) + printf( " CTR_DRBG (PR = TRUE) : " ); + + test_offset = 0; + if( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_pr, nonce_pers_pr, 16, 32 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + ctr_drbg_set_prediction_resistance( &ctx, CTR_DRBG_PR_ON ); + + if( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( buf, result_pr, CTR_DRBG_BLOCKSIZE ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if( verbose != 0 ) + printf( " CTR_DRBG (PR = FALSE): " ); + + test_offset = 0; + if( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_nopr, nonce_pers_nopr, 16, 32 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_random( &ctx, buf, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_reseed( &ctx, NULL, 0 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_random( &ctx, buf, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( buf, result_nopr, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} +#endif + +#endif diff --git a/lib/libpolarssl/source/entropy.c b/lib/libpolarssl/source/entropy.c new file mode 100644 index 0000000..a9d2f1b --- /dev/null +++ b/lib/libpolarssl/source/entropy.c @@ -0,0 +1,261 @@ +/* + * Entropy accumulator implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_ENTROPY_C) + +#include "polarssl/entropy.h" +#include "polarssl/entropy_poll.h" + +#if defined(POLARSSL_FS_IO) +#include +#endif + +#if defined(POLARSSL_HAVEGE_C) +#include "polarssl/havege.h" +#endif + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void entropy_init( entropy_context *ctx ) +{ + memset( ctx, 0, sizeof(entropy_context) ); + + sha4_starts( &ctx->accumulator, 0 ); +#if defined(POLARSSL_HAVEGE_C) + havege_init( &ctx->havege_data ); +#endif + +#if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES) +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) + entropy_add_source( ctx, platform_entropy_poll, NULL, + ENTROPY_MIN_PLATFORM ); +#endif +#if defined(POLARSSL_TIMING_C) + entropy_add_source( ctx, hardclock_poll, NULL, ENTROPY_MIN_HARDCLOCK ); +#endif +#if defined(POLARSSL_HAVEGE_C) + entropy_add_source( ctx, havege_poll, &ctx->havege_data, + ENTROPY_MIN_HAVEGE ); +#endif +#endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */ +} + +int entropy_add_source( entropy_context *ctx, + f_source_ptr f_source, void *p_source, + size_t threshold ) +{ + int index = ctx->source_count; + + if( index >= ENTROPY_MAX_SOURCES ) + return( POLARSSL_ERR_ENTROPY_MAX_SOURCES ); + + ctx->source[index].f_source = f_source; + ctx->source[index].p_source = p_source; + ctx->source[index].threshold = threshold; + + ctx->source_count++; + + return( 0 ); +} + +/* + * Entropy accumulator update + */ +static int entropy_update( entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len ) +{ + unsigned char header[2]; + unsigned char tmp[ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + + if( use_len > ENTROPY_BLOCK_SIZE ) + { + sha4( data, len, tmp, 0 ); + + p = tmp; + use_len = ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + + sha4_update( &ctx->accumulator, header, 2 ); + sha4_update( &ctx->accumulator, p, use_len ); + + return( 0 ); +} + +int entropy_update_manual( entropy_context *ctx, + const unsigned char *data, size_t len ) +{ + return entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len ); +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +int entropy_gather( entropy_context *ctx ) +{ + int ret, i; + unsigned char buf[ENTROPY_MAX_GATHER]; + size_t olen; + + if( ctx->source_count == 0 ) + return( POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED ); + + /* + * Run through our entropy sources + */ + for( i = 0; i < ctx->source_count; i++ ) + { + olen = 0; + if ( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, + buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 ) + { + return( ret ); + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + entropy_update( ctx, (unsigned char) i, buf, olen ); + ctx->source[i].size += olen; + } + } + + return( 0 ); +} + +int entropy_func( void *data, unsigned char *output, size_t len ) +{ + int ret, count = 0, i, reached; + entropy_context *ctx = (entropy_context *) data; + unsigned char buf[ENTROPY_BLOCK_SIZE]; + + if( len > ENTROPY_BLOCK_SIZE ) + return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); + + /* + * Always gather extra entropy before a call + */ + do + { + if( count++ > ENTROPY_MAX_LOOP ) + return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); + + if( ( ret = entropy_gather( ctx ) ) != 0 ) + return( ret ); + + reached = 0; + + for( i = 0; i < ctx->source_count; i++ ) + if( ctx->source[i].size >= ctx->source[i].threshold ) + reached++; + } + while( reached != ctx->source_count ); + + memset( buf, 0, ENTROPY_BLOCK_SIZE ); + + sha4_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( sha4_context ) ); + sha4_starts( &ctx->accumulator, 0 ); + sha4_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-512 on entropy + */ + sha4( buf, ENTROPY_BLOCK_SIZE, buf, 0 ); + + for( i = 0; i < ctx->source_count; i++ ) + ctx->source[i].size = 0; + + memcpy( output, buf, len ); + + return( 0 ); +} + +#if defined(POLARSSL_FS_IO) +int entropy_write_seed_file( entropy_context *ctx, const char *path ) +{ + int ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR; + FILE *f; + unsigned char buf[ENTROPY_BLOCK_SIZE]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR ); + + if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE ) + { + ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int entropy_update_seed_file( entropy_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ ENTROPY_MAX_SEED_SIZE ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > ENTROPY_MAX_SEED_SIZE ) + n = ENTROPY_MAX_SEED_SIZE; + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR ); + } + + fclose( f ); + + entropy_update_manual( ctx, buf, n ); + + return( entropy_write_seed_file( ctx, path ) ); +} +#endif /* POLARSSL_FS_IO */ + +#endif diff --git a/lib/libpolarssl/source/entropy_poll.c b/lib/libpolarssl/source/entropy_poll.c new file mode 100644 index 0000000..17be637 --- /dev/null +++ b/lib/libpolarssl/source/entropy_poll.c @@ -0,0 +1,133 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_ENTROPY_C) + +#include "polarssl/entropy.h" +#include "polarssl/entropy_poll.h" + +#if defined(POLARSSL_TIMING_C) +#include "polarssl/timing.h" +#endif +#if defined(POLARSSL_HAVEGE_C) +#include "polarssl/havege.h" +#endif + +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) +#if defined(_WIN32) + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +int platform_entropy_poll( void *data, unsigned char *output, size_t len, + size_t *olen ) +{ + HCRYPTPROV provider; + ((void) data); + *olen = 0; + + if( CryptAcquireContext( &provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) + { + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + } + + if( CryptGenRandom( provider, len, output ) == FALSE ) + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + + CryptReleaseContext( provider, 0 ); + *olen = len; + + return( 0 ); +} +#else + +#include + +int platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + FILE *file; + size_t ret; + ((void) data); + + *olen = 0; + + file = fopen( "/dev/urandom", "rb" ); + if( file == NULL ) + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + + ret = fread( output, 1, len, file ); + if( ret != len ) + { + fclose( file ); + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + } + + fclose( file ); + *olen = len; + + return( 0 ); +} +#endif +#endif + +#if defined(POLARSSL_TIMING_C) +int hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned long timer = hardclock(); + ((void) data); + *olen = 0; + + if( len < sizeof(unsigned long) ) + return( 0 ); + + memcpy( output, &timer, sizeof(unsigned long) ); + *olen = sizeof(unsigned long); + + return( 0 ); +} +#endif + +#if defined(POLARSSL_HAVEGE_C) +int havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + havege_state *hs = (havege_state *) data; + *olen = 0; + + if( havege_random( hs, output, len ) != 0 ) + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + + *olen = len; + + return( 0 ); +} +#endif + +#endif /* POLARSSL_ENTROPY_C */ diff --git a/lib/libpolarssl/source/sha4.c b/lib/libpolarssl/source/sha4.c new file mode 100644 index 0000000..ebdc997 --- /dev/null +++ b/lib/libpolarssl/source/sha4.c @@ -0,0 +1,762 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://polarssl.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_SHA4_C) + +#include "polarssl/sha4.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_SHA4_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void polarssl_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} +#endif + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +/* + * SHA-512 context setup + */ +void sha4_starts( sha4_context *ctx, int is384 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } + + ctx->is384 = is384; +} + +static void sha4_process( sha4_context *ctx, const unsigned char data[128] ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-512 process buffer + */ +void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + unsigned int left; + + if( ilen <= 0 ) + return; + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = 128 - left; + + ctx->total[0] += (uint64_t) ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + sha4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + sha4_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha4_padding[128] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-512 final digest + */ +void sha4_finish( sha4_context *ctx, unsigned char output[64] ) +{ + size_t last, padn; + uint64_t high, low; + unsigned char msglen[16]; + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (size_t)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + sha4_update( ctx, sha4_padding, padn ); + sha4_update( ctx, msglen, 16 ); + + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( ctx->is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } +} + +#endif /* !POLARSSL_SHA4_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +void sha4( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + sha4_context ctx; + + sha4_starts( &ctx, is384 ); + sha4_update( &ctx, input, ilen ); + sha4_finish( &ctx, output ); + + polarssl_zeroize( &ctx, sizeof( sha4_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = SHA-512( file contents ) + */ +int sha4_file( const char *path, unsigned char output[64], int is384 ) +{ + FILE *f; + size_t n; + sha4_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_SHA4_FILE_IO_ERROR ); + + sha4_starts( &ctx, is384 ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + sha4_update( &ctx, buf, n ); + + sha4_finish( &ctx, output ); + + polarssl_zeroize( &ctx, sizeof( sha4_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_SHA4_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * SHA-512 HMAC context setup + */ +void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen, + int is384 ) +{ + size_t i; + unsigned char sum[64]; + + if( keylen > 128 ) + { + sha4( key, keylen, sum, is384 ); + keylen = ( is384 ) ? 48 : 64; + key = sum; + } + + memset( ctx->ipad, 0x36, 128 ); + memset( ctx->opad, 0x5C, 128 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha4_starts( ctx, is384 ); + sha4_update( ctx, ctx->ipad, 128 ); + + polarssl_zeroize( sum, sizeof( sum ) ); +} + +/* + * SHA-512 HMAC process buffer + */ +void sha4_hmac_update( sha4_context *ctx, + const unsigned char *input, size_t ilen ) +{ + sha4_update( ctx, input, ilen ); +} + +/* + * SHA-512 HMAC final digest + */ +void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] ) +{ + int is384, hlen; + unsigned char tmpbuf[64]; + + is384 = ctx->is384; + hlen = ( is384 == 0 ) ? 64 : 48; + + sha4_finish( ctx, tmpbuf ); + sha4_starts( ctx, is384 ); + sha4_update( ctx, ctx->opad, 128 ); + sha4_update( ctx, tmpbuf, hlen ); + sha4_finish( ctx, output ); + + polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) ); +} + +/* + * SHA-512 HMAC context reset + */ +void sha4_hmac_reset( sha4_context *ctx ) +{ + sha4_starts( ctx, ctx->is384 ); + sha4_update( ctx, ctx->ipad, 128 ); +} + +/* + * output = HMAC-SHA-512( hmac key, input buffer ) + */ +void sha4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + sha4_context ctx; + + sha4_hmac_starts( &ctx, key, keylen, is384 ); + sha4_hmac_update( &ctx, input, ilen ); + sha4_hmac_finish( &ctx, output ); + + polarssl_zeroize( &ctx, sizeof( sha4_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static unsigned char sha4_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const int sha4_test_buflen[3] = +{ + 3, 112, 1000 +}; + +static const unsigned char sha4_test_sum[6][64] = +{ + /* + * SHA-384 test vectors + */ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 }, + + /* + * SHA-512 test vectors + */ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; + +/* + * RFC 4231 test vectors + */ +static unsigned char sha4_hmac_test_key[7][26] = +{ + { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B" }, + { "Jefe" }, + { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, + { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C" }, + { "" }, /* 0xAA 131 times */ + { "" } +}; + +static const int sha4_hmac_test_keylen[7] = +{ + 20, 4, 20, 25, 20, 131, 131 +}; + +static unsigned char sha4_hmac_test_buf[7][153] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "This is a test using a larger than block-size key " + "and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm." } +}; + +static const int sha4_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 152 +}; + +static const unsigned char sha4_hmac_test_sum[14][64] = +{ + /* + * HMAC-SHA-384 test vectors + */ + { 0xAF, 0xD0, 0x39, 0x44, 0xD8, 0x48, 0x95, 0x62, + 0x6B, 0x08, 0x25, 0xF4, 0xAB, 0x46, 0x90, 0x7F, + 0x15, 0xF9, 0xDA, 0xDB, 0xE4, 0x10, 0x1E, 0xC6, + 0x82, 0xAA, 0x03, 0x4C, 0x7C, 0xEB, 0xC5, 0x9C, + 0xFA, 0xEA, 0x9E, 0xA9, 0x07, 0x6E, 0xDE, 0x7F, + 0x4A, 0xF1, 0x52, 0xE8, 0xB2, 0xFA, 0x9C, 0xB6 }, + { 0xAF, 0x45, 0xD2, 0xE3, 0x76, 0x48, 0x40, 0x31, + 0x61, 0x7F, 0x78, 0xD2, 0xB5, 0x8A, 0x6B, 0x1B, + 0x9C, 0x7E, 0xF4, 0x64, 0xF5, 0xA0, 0x1B, 0x47, + 0xE4, 0x2E, 0xC3, 0x73, 0x63, 0x22, 0x44, 0x5E, + 0x8E, 0x22, 0x40, 0xCA, 0x5E, 0x69, 0xE2, 0xC7, + 0x8B, 0x32, 0x39, 0xEC, 0xFA, 0xB2, 0x16, 0x49 }, + { 0x88, 0x06, 0x26, 0x08, 0xD3, 0xE6, 0xAD, 0x8A, + 0x0A, 0xA2, 0xAC, 0xE0, 0x14, 0xC8, 0xA8, 0x6F, + 0x0A, 0xA6, 0x35, 0xD9, 0x47, 0xAC, 0x9F, 0xEB, + 0xE8, 0x3E, 0xF4, 0xE5, 0x59, 0x66, 0x14, 0x4B, + 0x2A, 0x5A, 0xB3, 0x9D, 0xC1, 0x38, 0x14, 0xB9, + 0x4E, 0x3A, 0xB6, 0xE1, 0x01, 0xA3, 0x4F, 0x27 }, + { 0x3E, 0x8A, 0x69, 0xB7, 0x78, 0x3C, 0x25, 0x85, + 0x19, 0x33, 0xAB, 0x62, 0x90, 0xAF, 0x6C, 0xA7, + 0x7A, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9C, + 0xC5, 0x57, 0x7C, 0x6E, 0x1F, 0x57, 0x3B, 0x4E, + 0x68, 0x01, 0xDD, 0x23, 0xC4, 0xA7, 0xD6, 0x79, + 0xCC, 0xF8, 0xA3, 0x86, 0xC6, 0x74, 0xCF, 0xFB }, + { 0x3A, 0xBF, 0x34, 0xC3, 0x50, 0x3B, 0x2A, 0x23, + 0xA4, 0x6E, 0xFC, 0x61, 0x9B, 0xAE, 0xF8, 0x97 }, + { 0x4E, 0xCE, 0x08, 0x44, 0x85, 0x81, 0x3E, 0x90, + 0x88, 0xD2, 0xC6, 0x3A, 0x04, 0x1B, 0xC5, 0xB4, + 0x4F, 0x9E, 0xF1, 0x01, 0x2A, 0x2B, 0x58, 0x8F, + 0x3C, 0xD1, 0x1F, 0x05, 0x03, 0x3A, 0xC4, 0xC6, + 0x0C, 0x2E, 0xF6, 0xAB, 0x40, 0x30, 0xFE, 0x82, + 0x96, 0x24, 0x8D, 0xF1, 0x63, 0xF4, 0x49, 0x52 }, + { 0x66, 0x17, 0x17, 0x8E, 0x94, 0x1F, 0x02, 0x0D, + 0x35, 0x1E, 0x2F, 0x25, 0x4E, 0x8F, 0xD3, 0x2C, + 0x60, 0x24, 0x20, 0xFE, 0xB0, 0xB8, 0xFB, 0x9A, + 0xDC, 0xCE, 0xBB, 0x82, 0x46, 0x1E, 0x99, 0xC5, + 0xA6, 0x78, 0xCC, 0x31, 0xE7, 0x99, 0x17, 0x6D, + 0x38, 0x60, 0xE6, 0x11, 0x0C, 0x46, 0x52, 0x3E }, + + /* + * HMAC-SHA-512 test vectors + */ + { 0x87, 0xAA, 0x7C, 0xDE, 0xA5, 0xEF, 0x61, 0x9D, + 0x4F, 0xF0, 0xB4, 0x24, 0x1A, 0x1D, 0x6C, 0xB0, + 0x23, 0x79, 0xF4, 0xE2, 0xCE, 0x4E, 0xC2, 0x78, + 0x7A, 0xD0, 0xB3, 0x05, 0x45, 0xE1, 0x7C, 0xDE, + 0xDA, 0xA8, 0x33, 0xB7, 0xD6, 0xB8, 0xA7, 0x02, + 0x03, 0x8B, 0x27, 0x4E, 0xAE, 0xA3, 0xF4, 0xE4, + 0xBE, 0x9D, 0x91, 0x4E, 0xEB, 0x61, 0xF1, 0x70, + 0x2E, 0x69, 0x6C, 0x20, 0x3A, 0x12, 0x68, 0x54 }, + { 0x16, 0x4B, 0x7A, 0x7B, 0xFC, 0xF8, 0x19, 0xE2, + 0xE3, 0x95, 0xFB, 0xE7, 0x3B, 0x56, 0xE0, 0xA3, + 0x87, 0xBD, 0x64, 0x22, 0x2E, 0x83, 0x1F, 0xD6, + 0x10, 0x27, 0x0C, 0xD7, 0xEA, 0x25, 0x05, 0x54, + 0x97, 0x58, 0xBF, 0x75, 0xC0, 0x5A, 0x99, 0x4A, + 0x6D, 0x03, 0x4F, 0x65, 0xF8, 0xF0, 0xE6, 0xFD, + 0xCA, 0xEA, 0xB1, 0xA3, 0x4D, 0x4A, 0x6B, 0x4B, + 0x63, 0x6E, 0x07, 0x0A, 0x38, 0xBC, 0xE7, 0x37 }, + { 0xFA, 0x73, 0xB0, 0x08, 0x9D, 0x56, 0xA2, 0x84, + 0xEF, 0xB0, 0xF0, 0x75, 0x6C, 0x89, 0x0B, 0xE9, + 0xB1, 0xB5, 0xDB, 0xDD, 0x8E, 0xE8, 0x1A, 0x36, + 0x55, 0xF8, 0x3E, 0x33, 0xB2, 0x27, 0x9D, 0x39, + 0xBF, 0x3E, 0x84, 0x82, 0x79, 0xA7, 0x22, 0xC8, + 0x06, 0xB4, 0x85, 0xA4, 0x7E, 0x67, 0xC8, 0x07, + 0xB9, 0x46, 0xA3, 0x37, 0xBE, 0xE8, 0x94, 0x26, + 0x74, 0x27, 0x88, 0x59, 0xE1, 0x32, 0x92, 0xFB }, + { 0xB0, 0xBA, 0x46, 0x56, 0x37, 0x45, 0x8C, 0x69, + 0x90, 0xE5, 0xA8, 0xC5, 0xF6, 0x1D, 0x4A, 0xF7, + 0xE5, 0x76, 0xD9, 0x7F, 0xF9, 0x4B, 0x87, 0x2D, + 0xE7, 0x6F, 0x80, 0x50, 0x36, 0x1E, 0xE3, 0xDB, + 0xA9, 0x1C, 0xA5, 0xC1, 0x1A, 0xA2, 0x5E, 0xB4, + 0xD6, 0x79, 0x27, 0x5C, 0xC5, 0x78, 0x80, 0x63, + 0xA5, 0xF1, 0x97, 0x41, 0x12, 0x0C, 0x4F, 0x2D, + 0xE2, 0xAD, 0xEB, 0xEB, 0x10, 0xA2, 0x98, 0xDD }, + { 0x41, 0x5F, 0xAD, 0x62, 0x71, 0x58, 0x0A, 0x53, + 0x1D, 0x41, 0x79, 0xBC, 0x89, 0x1D, 0x87, 0xA6 }, + { 0x80, 0xB2, 0x42, 0x63, 0xC7, 0xC1, 0xA3, 0xEB, + 0xB7, 0x14, 0x93, 0xC1, 0xDD, 0x7B, 0xE8, 0xB4, + 0x9B, 0x46, 0xD1, 0xF4, 0x1B, 0x4A, 0xEE, 0xC1, + 0x12, 0x1B, 0x01, 0x37, 0x83, 0xF8, 0xF3, 0x52, + 0x6B, 0x56, 0xD0, 0x37, 0xE0, 0x5F, 0x25, 0x98, + 0xBD, 0x0F, 0xD2, 0x21, 0x5D, 0x6A, 0x1E, 0x52, + 0x95, 0xE6, 0x4F, 0x73, 0xF6, 0x3F, 0x0A, 0xEC, + 0x8B, 0x91, 0x5A, 0x98, 0x5D, 0x78, 0x65, 0x98 }, + { 0xE3, 0x7B, 0x6A, 0x77, 0x5D, 0xC8, 0x7D, 0xBA, + 0xA4, 0xDF, 0xA9, 0xF9, 0x6E, 0x5E, 0x3F, 0xFD, + 0xDE, 0xBD, 0x71, 0xF8, 0x86, 0x72, 0x89, 0x86, + 0x5D, 0xF5, 0xA3, 0x2D, 0x20, 0xCD, 0xC9, 0x44, + 0xB6, 0x02, 0x2C, 0xAC, 0x3C, 0x49, 0x82, 0xB1, + 0x0D, 0x5E, 0xEB, 0x55, 0xC3, 0xE4, 0xDE, 0x15, + 0x13, 0x46, 0x76, 0xFB, 0x6D, 0xE0, 0x44, 0x60, + 0x65, 0xC9, 0x74, 0x40, 0xFA, 0x8C, 0x6A, 0x58 } +}; + +/* + * Checkup routine + */ +int sha4_self_test( int verbose ) +{ + int i, j, k, buflen; + unsigned char buf[1024]; + unsigned char sha4sum[64]; + sha4_context ctx; + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + sha4_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + sha4_update( &ctx, buf, buflen ); + } + else + sha4_update( &ctx, sha4_test_buf[j], + sha4_test_buflen[j] ); + + sha4_finish( &ctx, sha4sum ); + + if( memcmp( sha4sum, sha4_test_sum[i], 64 - k * 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + for( i = 0; i < 14; i++ ) + { + j = i % 7; + k = i < 7; + + if( verbose != 0 ) + printf( " HMAC-SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + if( j == 5 || j == 6 ) + { + memset( buf, '\xAA', buflen = 131 ); + sha4_hmac_starts( &ctx, buf, buflen, k ); + } + else + sha4_hmac_starts( &ctx, sha4_hmac_test_key[j], + sha4_hmac_test_keylen[j], k ); + + sha4_hmac_update( &ctx, sha4_hmac_test_buf[j], + sha4_hmac_test_buflen[j] ); + + sha4_hmac_finish( &ctx, sha4sum ); + + buflen = ( j == 4 ) ? 16 : 64 - k * 16; + + if( memcmp( sha4sum, sha4_hmac_test_sum[i], buflen ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif From 91468ede5b0fd079f80d0c8f5cd4b1c6cc654a8b Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 19:56:38 +0800 Subject: [PATCH 34/50] [fac] Fixed bug where incorrect sizes FAC contentid & saveownerid lists generated. --- lib/libhac/source/FileSystemAccessControlBinary.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/libhac/source/FileSystemAccessControlBinary.cpp b/lib/libhac/source/FileSystemAccessControlBinary.cpp index c8c7e94..18f08af 100644 --- a/lib/libhac/source/FileSystemAccessControlBinary.cpp +++ b/lib/libhac/source/FileSystemAccessControlBinary.cpp @@ -41,9 +41,17 @@ void nn::hac::FileSystemAccessControlBinary::toBytes() } content, savedata; content.offset = (uint32_t)align(sizeof(sFacHeader), fac::kSectionAlignSize); - content.size = (uint32_t)(sizeof(uint32_t) + mContentOwnerIdList.size() * sizeof(uint64_t)); + if (mContentOwnerIdList.size() > 0) + content.size = (uint32_t)(sizeof(uint32_t) + mContentOwnerIdList.size() * sizeof(uint64_t)); + else + content.size = 0; + savedata.offset = (uint32_t)(content.offset + (content.size > 0 ? align(content.size, fac::kSectionAlignSize) : 0)); - savedata.size = (uint32_t)(sizeof(uint32_t) + align(mSaveDataOwnerIdList.size(), fac::kSectionAlignSize) + mSaveDataOwnerIdList.size() * sizeof(uint64_t)); + if (mSaveDataOwnerIdList.size() > 0) + savedata.size = (uint32_t)(sizeof(uint32_t) + align(mSaveDataOwnerIdList.size(), fac::kSectionAlignSize) + mSaveDataOwnerIdList.size() * sizeof(uint64_t)); + else + savedata.size = 0; + // get total size size_t total_size = _MAX(_MAX(content.offset + content.size, savedata.offset + savedata.size), align(sizeof(sFacHeader), fac::kSectionAlignSize)); From 8a60ee94aea82c8cbee3dd077bd602c0146aebb9 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 19:57:06 +0800 Subject: [PATCH 35/50] [hac] Prevented a segfault when generating SysCall kernel caps. --- lib/libhac/source/SystemCallHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libhac/source/SystemCallHandler.cpp b/lib/libhac/source/SystemCallHandler.cpp index c2e58b5..da03380 100644 --- a/lib/libhac/source/SystemCallHandler.cpp +++ b/lib/libhac/source/SystemCallHandler.cpp @@ -54,7 +54,7 @@ void nn::hac::SystemCallHandler::exportKernelCapabilityList(fnd::List entries; + SystemCallEntry entries[kSyscallTotalEntryNum]; for (size_t i = 0; i < kSyscallTotalEntryNum; i++) { entries[i].setSystemCallUpperBits((uint32_t)i); @@ -71,7 +71,7 @@ void nn::hac::SystemCallHandler::exportKernelCapabilityList(fnd::List Date: Sun, 9 Sep 2018 19:57:54 +0800 Subject: [PATCH 36/50] [hac] Fixed a bug where the raw buffer was not cleared in KernelCapabilityBinary. --- lib/libhac/source/KernelCapabilityBinary.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libhac/source/KernelCapabilityBinary.cpp b/lib/libhac/source/KernelCapabilityBinary.cpp index 71d5eed..096c7b3 100644 --- a/lib/libhac/source/KernelCapabilityBinary.cpp +++ b/lib/libhac/source/KernelCapabilityBinary.cpp @@ -11,6 +11,7 @@ nn::hac::KernelCapabilityBinary::KernelCapabilityBinary(const KernelCapabilityBi void nn::hac::KernelCapabilityBinary::operator=(const KernelCapabilityBinary & other) { clear(); + mRawBinary = other.mRawBinary; mThreadInfo = other.mThreadInfo; mSystemCalls = other.mSystemCalls; mMemoryMap = other.mMemoryMap; From b543b73c66b40bb0741a21fc7f87d544046834e5 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 9 Sep 2018 19:59:40 +0800 Subject: [PATCH 37/50] [hac] Fixed bug where data was not serialised completely in AccessControlInfoBinary & AccessControlInfoDescBinary. --- lib/libhac/source/AccessControlInfoBinary.cpp | 17 +++++++++-------- .../source/AccessControlInfoDescBinary.cpp | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/libhac/source/AccessControlInfoBinary.cpp b/lib/libhac/source/AccessControlInfoBinary.cpp index cdf5a50..5a22449 100644 --- a/lib/libhac/source/AccessControlInfoBinary.cpp +++ b/lib/libhac/source/AccessControlInfoBinary.cpp @@ -34,14 +34,10 @@ bool nn::hac::AccessControlInfoBinary::operator!=(const AccessControlInfoBinary void nn::hac::AccessControlInfoBinary::toBytes() { - if (mFileSystemAccessControl.getBytes().size() == 0) - mFileSystemAccessControl.toBytes(); - - if (mServiceAccessControl.getBytes().size() == 0) - mServiceAccessControl.toBytes(); - - if (mKernelCapabilities.getBytes().size() == 0) - mKernelCapabilities.toBytes(); + // serialise the sections + mFileSystemAccessControl.toBytes(); + mServiceAccessControl.toBytes(); + mKernelCapabilities.toBytes(); // determine section layout struct sLayout { @@ -74,6 +70,11 @@ void nn::hac::AccessControlInfoBinary::toBytes() hdr->sac.size = sac.size; hdr->kc.offset = kc.offset; hdr->kc.size = kc.size; + + // write data + memcpy(mRawBinary.data() + fac.offset, mFileSystemAccessControl.getBytes().data(), fac.size); + memcpy(mRawBinary.data() + sac.offset, mServiceAccessControl.getBytes().data(), sac.size); + memcpy(mRawBinary.data() + kc.offset, mKernelCapabilities.getBytes().data(), kc.size); } void nn::hac::AccessControlInfoBinary::fromBytes(const byte_t* data, size_t len) diff --git a/lib/libhac/source/AccessControlInfoDescBinary.cpp b/lib/libhac/source/AccessControlInfoDescBinary.cpp index 50ac86e..efd29c4 100644 --- a/lib/libhac/source/AccessControlInfoDescBinary.cpp +++ b/lib/libhac/source/AccessControlInfoDescBinary.cpp @@ -38,14 +38,10 @@ bool nn::hac::AccessControlInfoDescBinary::operator!=(const AccessControlInfoDes void nn::hac::AccessControlInfoDescBinary::toBytes() { - if (mFileSystemAccessControl.getBytes().size() == 0) - mFileSystemAccessControl.toBytes(); - - if (mServiceAccessControl.getBytes().size() == 0) - mServiceAccessControl.toBytes(); - - if (mKernelCapabilities.getBytes().size() == 0) - mKernelCapabilities.toBytes(); + // serialise the sections + mFileSystemAccessControl.toBytes(); + mServiceAccessControl.toBytes(); + mKernelCapabilities.toBytes(); // determine section layout struct sLayout { @@ -91,6 +87,11 @@ void nn::hac::AccessControlInfoDescBinary::toBytes() hdr->sac.size = sac.size; hdr->kc.offset = kc.offset; hdr->kc.size = kc.size; + + // write data + memcpy(mRawBinary.data() + fac.offset, mFileSystemAccessControl.getBytes().data(), fac.size); + memcpy(mRawBinary.data() + sac.offset, mServiceAccessControl.getBytes().data(), sac.size); + memcpy(mRawBinary.data() + kc.offset, mKernelCapabilities.getBytes().data(), kc.size); } void nn::hac::AccessControlInfoDescBinary::fromBytes(const byte_t* data, size_t len) @@ -157,7 +158,7 @@ void nn::hac::AccessControlInfoDescBinary::generateSignature(const fnd::rsa::sRs byte_t hash[fnd::sha::kSha256HashLen]; fnd::sha::Sha256(mRawBinary.data() + fnd::rsa::kRsa2048Size, mRawBinary.size() - fnd::rsa::kRsa2048Size, hash); - if (fnd::rsa::pkcs::rsaSign(key, fnd::sha::HASH_SHA256, hash, mRawBinary.data()) != 0) + if (fnd::rsa::pss::rsaSign(key, fnd::sha::HASH_SHA256, hash, mRawBinary.data()) != 0) { throw fnd::Exception(kModuleName, "Failed to sign Access Control Info Desc"); } From 4bf1ca40a4aa65dec0251e18fee27620a39e3ae8 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 10 Sep 2018 16:51:37 +0800 Subject: [PATCH 38/50] [nstool] Update VS project files. --- programs/nstool/nstool.vcxproj | 2 ++ programs/nstool/nstool.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/programs/nstool/nstool.vcxproj b/programs/nstool/nstool.vcxproj index 882f63e..b72bf95 100644 --- a/programs/nstool/nstool.vcxproj +++ b/programs/nstool/nstool.vcxproj @@ -185,6 +185,7 @@ + @@ -210,6 +211,7 @@ + diff --git a/programs/nstool/nstool.vcxproj.filters b/programs/nstool/nstool.vcxproj.filters index 2227147..e9e9105 100644 --- a/programs/nstool/nstool.vcxproj.filters +++ b/programs/nstool/nstool.vcxproj.filters @@ -40,6 +40,9 @@ Header Files + + Header Files + Header Files @@ -111,6 +114,9 @@ Source Files + + Source Files + Source Files From b6a451442eb0efb628fadfcce3fd91d638fead65 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 10 Sep 2018 16:52:23 +0800 Subject: [PATCH 39/50] [nstool|hac] Fix typo in cnmt AocExtendedHeader field. --- lib/libhac/include/nn/hac/ContentMetaBinary.h | 6 +++--- lib/libhac/include/nn/hac/cnmt.h | 2 +- lib/libhac/source/ContentMetaBinary.cpp | 2 +- programs/nstool/source/CnmtProcess.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/libhac/include/nn/hac/ContentMetaBinary.h b/lib/libhac/include/nn/hac/ContentMetaBinary.h index 84f5d9c..8c57644 100644 --- a/lib/libhac/include/nn/hac/ContentMetaBinary.h +++ b/lib/libhac/include/nn/hac/ContentMetaBinary.h @@ -120,18 +120,18 @@ namespace hac struct AddOnContentMetaExtendedHeader { uint64_t application_id; - uint32_t required_system_version; + uint32_t required_application_version; void operator=(const AddOnContentMetaExtendedHeader& other) { application_id = other.application_id; - required_system_version = other.required_system_version; + required_application_version = other.required_application_version; } bool operator==(const AddOnContentMetaExtendedHeader& other) const { return (application_id == other.application_id) \ - && (required_system_version == other.required_system_version); + && (required_application_version == other.required_application_version); } bool operator!=(const AddOnContentMetaExtendedHeader& other) const diff --git a/lib/libhac/include/nn/hac/cnmt.h b/lib/libhac/include/nn/hac/cnmt.h index f7c8eb3..81871c0 100644 --- a/lib/libhac/include/nn/hac/cnmt.h +++ b/lib/libhac/include/nn/hac/cnmt.h @@ -118,7 +118,7 @@ namespace hac struct sAddOnContentMetaExtendedHeader { le_uint64_t application_id; - le_uint32_t required_system_version; + le_uint32_t required_application_version; byte_t reserved[4]; }; diff --git a/lib/libhac/source/ContentMetaBinary.cpp b/lib/libhac/source/ContentMetaBinary.cpp index 22c5ab7..7ebd628 100644 --- a/lib/libhac/source/ContentMetaBinary.cpp +++ b/lib/libhac/source/ContentMetaBinary.cpp @@ -100,7 +100,7 @@ void nn::hac::ContentMetaBinary::fromBytes(const byte_t* data, size_t len) break; case (cnmt::METATYPE_ADD_ON_CONTENT): mAddOnContentMetaExtendedHeader.application_id = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.data())->application_id.get(); - mAddOnContentMetaExtendedHeader.required_system_version = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.data())->required_system_version.get(); + mAddOnContentMetaExtendedHeader.required_application_version = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.data())->required_application_version.get(); break; case (cnmt::METATYPE_DELTA): mDeltaMetaExtendedHeader.application_id = ((sDeltaMetaExtendedHeader*)mExtendedHeader.data())->application_id.get(); diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index f40caab..29caeb4 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -90,7 +90,7 @@ void CnmtProcess::displayCnmt() break; case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT): std::cout << " AddOnContentMetaExtendedHeader:" << std::endl; - std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_system_version) << ")"<< std::endl; + std::cout << " RequiredApplicationVersion: v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().required_application_version << " (" << _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_application_version) << ")" << std::endl; std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getAddOnContentMetaExtendedHeader().application_id << std::endl; break; case (nn::hac::cnmt::METATYPE_DELTA): From c6847808a833978d34b8d88b722bdb88414b7e5b Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 10 Sep 2018 16:52:47 +0800 Subject: [PATCH 40/50] [hac] Add IdConverter. --- lib/libhac/include/nn/hac/IdConverter.h | 21 +++++++++++++++++++++ lib/libhac/libhac.vcxproj | 2 ++ lib/libhac/libhac.vcxproj.filters | 6 ++++++ lib/libhac/source/IdConverter.cpp | 16 ++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 lib/libhac/include/nn/hac/IdConverter.h create mode 100644 lib/libhac/source/IdConverter.cpp diff --git a/lib/libhac/include/nn/hac/IdConverter.h b/lib/libhac/include/nn/hac/IdConverter.h new file mode 100644 index 0000000..40702ea --- /dev/null +++ b/lib/libhac/include/nn/hac/IdConverter.h @@ -0,0 +1,21 @@ +#pragma once +#include + +namespace nn +{ +namespace hac +{ + class IdConverter + { + public: + static uint64_t convertToAocBaseId(uint64_t application_id); + static uint64_t convertToDeltaId(uint64_t application_id); + static uint64_t convertToPatchId(uint64_t application_id); + + private: + static const uint64_t kAocBaseId = 0x1000; + static const uint64_t kDeltaId = 0xc00; + static const uint64_t kPatchId = 0x800; + }; +} +} \ No newline at end of file diff --git a/lib/libhac/libhac.vcxproj b/lib/libhac/libhac.vcxproj index 3ff63ae..067835b 100644 --- a/lib/libhac/libhac.vcxproj +++ b/lib/libhac/libhac.vcxproj @@ -39,6 +39,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/lib/libhac/libhac.vcxproj.filters b/lib/libhac/libhac.vcxproj.filters index 3c44384..de979d9 100644 --- a/lib/libhac/libhac.vcxproj.filters +++ b/lib/libhac/libhac.vcxproj.filters @@ -183,6 +183,9 @@ Header Files + + Header Files + @@ -296,5 +299,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/lib/libhac/source/IdConverter.cpp b/lib/libhac/source/IdConverter.cpp new file mode 100644 index 0000000..5455263 --- /dev/null +++ b/lib/libhac/source/IdConverter.cpp @@ -0,0 +1,16 @@ +#include + +uint64_t nn::hac::IdConverter::convertToAocBaseId(uint64_t application_id) +{ + return application_id + kAocBaseId; +} + +uint64_t nn::hac::IdConverter::convertToDeltaId(uint64_t application_id) +{ + return application_id + kDeltaId; +} + +uint64_t nn::hac::IdConverter::convertToPatchId(uint64_t application_id) +{ + return application_id + kPatchId; +} \ No newline at end of file From dd1a97aec2753eea001c3922a7268c25866ae525 Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 10 Sep 2018 22:10:15 +0800 Subject: [PATCH 41/50] [hac] Add native Result class. --- lib/libhac/include/nn/hac/Result.h | 39 +++++++++++++++++++ lib/libhac/libhac.vcxproj | 2 + lib/libhac/libhac.vcxproj.filters | 6 +++ lib/libhac/source/Result.cpp | 62 ++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 lib/libhac/include/nn/hac/Result.h create mode 100644 lib/libhac/source/Result.cpp diff --git a/lib/libhac/include/nn/hac/Result.h b/lib/libhac/include/nn/hac/Result.h new file mode 100644 index 0000000..f13587a --- /dev/null +++ b/lib/libhac/include/nn/hac/Result.h @@ -0,0 +1,39 @@ +#pragma once +#include + +namespace nn +{ +namespace hac +{ + class Result + { + public: + Result(); + Result(uint32_t result); + Result(uint32_t module_num, uint32_t desc, uint32_t sub_desc); + + void operator=(const Result& other); + bool operator==(const Result& other) const; + bool operator!=(const Result& other) const; + + bool isSuccess() const; + bool isFailure() const; + + uint32_t getInnerValue() const; + uint32_t getModuleNum() const; + uint32_t getDescription() const; + uint32_t getSubDescription() const; + + private: + static const uint32_t kModuleNumBitWidth = 9; + static const uint32_t kModuleNumBitPos = 0; + static const uint32_t kDescriptionBitWidth = 13; + static const uint32_t kDescriptionBitPos = 9; + static const uint32_t kSubDescriptionBitWidth = 10; + static const uint32_t kSubDescriptionBitPos = 22; + inline uint32_t bitWidthToMask(uint32_t bit_width) const { return _BIT(bit_width) - 1; } + + uint32_t mResult; + }; +} +} \ No newline at end of file diff --git a/lib/libhac/libhac.vcxproj b/lib/libhac/libhac.vcxproj index 067835b..fa7d25c 100644 --- a/lib/libhac/libhac.vcxproj +++ b/lib/libhac/libhac.vcxproj @@ -68,6 +68,7 @@ + @@ -110,6 +111,7 @@ + diff --git a/lib/libhac/libhac.vcxproj.filters b/lib/libhac/libhac.vcxproj.filters index de979d9..2099435 100644 --- a/lib/libhac/libhac.vcxproj.filters +++ b/lib/libhac/libhac.vcxproj.filters @@ -186,6 +186,9 @@ Header Files + + Header Files + @@ -302,5 +305,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/lib/libhac/source/Result.cpp b/lib/libhac/source/Result.cpp new file mode 100644 index 0000000..da06c05 --- /dev/null +++ b/lib/libhac/source/Result.cpp @@ -0,0 +1,62 @@ +#include + +nn::hac::Result::Result() : + mResult(0) +{} + +nn::hac::Result::Result(uint32_t result) : + mResult(result) +{} + +nn::hac::Result::Result(uint32_t module_num, uint32_t desc, uint32_t sub_desc) : + mResult(0) +{ + mResult |= (module_num & bitWidthToMask(kModuleNumBitWidth)) << kModuleNumBitPos; + mResult |= (desc & bitWidthToMask(kDescriptionBitWidth)) << kDescriptionBitPos; + mResult |= (sub_desc & bitWidthToMask(kSubDescriptionBitWidth)) << kSubDescriptionBitPos; +} + +void nn::hac::Result::operator=(const Result & other) +{ + mResult = other.mResult; +} + +bool nn::hac::Result::operator==(const Result & other) const +{ + return mResult == other.mResult; +} + +bool nn::hac::Result::operator!=(const Result & other) const +{ + return !(*this == other); +} + +bool nn::hac::Result::isSuccess() const +{ + return mResult == 0; +} + +bool nn::hac::Result::isFailure() const +{ + return !isSuccess(); +} + +uint32_t nn::hac::Result::getInnerValue() const +{ + return mResult; +} + +uint32_t nn::hac::Result::getModuleNum() const +{ + return (mResult >> kModuleNumBitPos) & bitWidthToMask(kModuleNumBitWidth); +} + +uint32_t nn::hac::Result::getDescription() const +{ + return (mResult >> kDescriptionBitPos) & bitWidthToMask(kDescriptionBitWidth); +} + +uint32_t nn::hac::Result::getSubDescription() const +{ + return (mResult >> kSubDescriptionBitPos) & bitWidthToMask(kSubDescriptionBitWidth); +} From 1ef566eb80917bd51c4103279f6e306686631337 Mon Sep 17 00:00:00 2001 From: jakcron Date: Thu, 13 Sep 2018 19:06:48 +0800 Subject: [PATCH 42/50] [nstool] Renamed 'nstool.h' to 'common.h' --- programs/nstool/source/AssetProcess.h | 2 +- programs/nstool/source/CnmtProcess.h | 2 +- programs/nstool/source/EsTikProcess.h | 2 +- programs/nstool/source/HashTreeWrappedIFile.cpp | 2 +- programs/nstool/source/NacpProcess.h | 2 +- programs/nstool/source/NcaProcess.h | 2 +- programs/nstool/source/NpdmProcess.h | 2 +- programs/nstool/source/NroProcess.h | 2 +- programs/nstool/source/NsoProcess.h | 2 +- programs/nstool/source/PfsProcess.h | 2 +- programs/nstool/source/PkiCertProcess.h | 2 +- programs/nstool/source/RoMetadataProcess.h | 2 +- programs/nstool/source/RomfsProcess.h | 2 +- programs/nstool/source/UserSettings.cpp | 14 +++++++------- programs/nstool/source/UserSettings.h | 2 +- programs/nstool/source/XciProcess.h | 2 +- programs/nstool/source/{nstool.h => common.h} | 0 programs/nstool/source/version.h | 2 ++ 18 files changed, 24 insertions(+), 22 deletions(-) rename programs/nstool/source/{nstool.h => common.h} (100%) diff --git a/programs/nstool/source/AssetProcess.h b/programs/nstool/source/AssetProcess.h index aae5177..64efbc7 100644 --- a/programs/nstool/source/AssetProcess.h +++ b/programs/nstool/source/AssetProcess.h @@ -6,7 +6,7 @@ #include "NacpProcess.h" #include "RomfsProcess.h" -#include "nstool.h" +#include "common.h" class AssetProcess { diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index 83535ba..2fbcd15 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -4,7 +4,7 @@ #include #include -#include "nstool.h" +#include "common.h" class CnmtProcess { diff --git a/programs/nstool/source/EsTikProcess.h b/programs/nstool/source/EsTikProcess.h index ae77ec3..94f5b05 100644 --- a/programs/nstool/source/EsTikProcess.h +++ b/programs/nstool/source/EsTikProcess.h @@ -7,7 +7,7 @@ #include #include #include "KeyConfiguration.h" -#include "nstool.h" +#include "common.h" class EsTikProcess { diff --git a/programs/nstool/source/HashTreeWrappedIFile.cpp b/programs/nstool/source/HashTreeWrappedIFile.cpp index 3b147e9..7ff7e7c 100644 --- a/programs/nstool/source/HashTreeWrappedIFile.cpp +++ b/programs/nstool/source/HashTreeWrappedIFile.cpp @@ -1,4 +1,4 @@ -#include "nstool.h" +#include "common.h" #include "HashTreeWrappedIFile.h" #include "OffsetAdjustedIFile.h" diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h index 8d6eb6e..0e6aed3 100644 --- a/programs/nstool/source/NacpProcess.h +++ b/programs/nstool/source/NacpProcess.h @@ -4,7 +4,7 @@ #include #include -#include "nstool.h" +#include "common.h" class NacpProcess { diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index b263278..f467945 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -7,7 +7,7 @@ #include "KeyConfiguration.h" -#include "nstool.h" +#include "common.h" class NcaProcess { diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index 68c3523..a203c0e 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -5,7 +5,7 @@ #include #include "KeyConfiguration.h" -#include "nstool.h" +#include "common.h" class NpdmProcess { diff --git a/programs/nstool/source/NroProcess.h b/programs/nstool/source/NroProcess.h index 12f1eb8..7d27553 100644 --- a/programs/nstool/source/NroProcess.h +++ b/programs/nstool/source/NroProcess.h @@ -7,7 +7,7 @@ #include #include "AssetProcess.h" -#include "nstool.h" +#include "common.h" #include "RoMetadataProcess.h" class NroProcess diff --git a/programs/nstool/source/NsoProcess.h b/programs/nstool/source/NsoProcess.h index 0cf57c0..a74beaf 100644 --- a/programs/nstool/source/NsoProcess.h +++ b/programs/nstool/source/NsoProcess.h @@ -6,7 +6,7 @@ #include #include -#include "nstool.h" +#include "common.h" #include "RoMetadataProcess.h" class NsoProcess diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h index 96c56aa..562dd21 100644 --- a/programs/nstool/source/PfsProcess.h +++ b/programs/nstool/source/PfsProcess.h @@ -4,7 +4,7 @@ #include #include -#include "nstool.h" +#include "common.h" class PfsProcess { diff --git a/programs/nstool/source/PkiCertProcess.h b/programs/nstool/source/PkiCertProcess.h index 964a70d..c281ae7 100644 --- a/programs/nstool/source/PkiCertProcess.h +++ b/programs/nstool/source/PkiCertProcess.h @@ -7,7 +7,7 @@ #include #include #include "KeyConfiguration.h" -#include "nstool.h" +#include "common.h" class PkiCertProcess { diff --git a/programs/nstool/source/RoMetadataProcess.h b/programs/nstool/source/RoMetadataProcess.h index e1dbff2..664e06c 100644 --- a/programs/nstool/source/RoMetadataProcess.h +++ b/programs/nstool/source/RoMetadataProcess.h @@ -6,7 +6,7 @@ #include -#include "nstool.h" +#include "common.h" #include "SdkApiString.h" #include "ElfSymbolParser.h" diff --git a/programs/nstool/source/RomfsProcess.h b/programs/nstool/source/RomfsProcess.h index 475576c..7132bba 100644 --- a/programs/nstool/source/RomfsProcess.h +++ b/programs/nstool/source/RomfsProcess.h @@ -6,7 +6,7 @@ #include #include -#include "nstool.h" +#include "common.h" class RomfsProcess { diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index fd4cf97..bf97fb8 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -45,10 +45,10 @@ void UserSettings::parseCmdArgs(const std::vector& arg_list) void UserSettings::showHelp() { - printf("NSTool v%d.%d.%d (C) %s\n", VER_MAJOR, VER_MINOR, VER_PATCH, AUTHORS); + printf("%s v%d.%d.%d (C) %s\n", APP_NAME, VER_MAJOR, VER_MINOR, VER_PATCH, AUTHORS); printf("Built: %s %s\n\n", __TIME__, __DATE__); - printf("Usage: nstool [options... ] \n"); + printf("Usage: %s [options... ] \n", BIN_NAME); printf("\n General Options:\n"); printf(" -d, --dev Use devkit keyset.\n"); printf(" -k, --keyset Specify keyset file.\n"); @@ -59,18 +59,18 @@ void UserSettings::showHelp() printf(" --showlayout Show layout metadata.\n"); printf(" -v, --verbose Verbose output.\n"); printf("\n XCI (GameCard Image)\n"); - printf(" nstool [--listfs] [--update --logo --normal --secure ] <.xci file>\n"); + printf(" %s [--listfs] [--update --logo --normal --secure ] <.xci file>\n", BIN_NAME); printf(" --listfs Print file system in embedded partitions.\n"); printf(" --update Extract \"update\" partition to directory.\n"); printf(" --logo Extract \"logo\" partition to directory.\n"); printf(" --normal Extract \"normal\" partition to directory.\n"); printf(" --secure Extract \"secure\" partition to directory.\n"); printf("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n"); - printf(" nstool [--listfs] [--fsdir ] \n"); + printf(" %s [--listfs] [--fsdir ] \n", BIN_NAME); printf(" --listfs Print file system.\n"); printf(" --fsdir Extract file system to directory.\n"); printf("\n NCA (Nintendo Content Archive)\n"); - printf(" nstool [--listfs] [--bodykey --titlekey ] [--part0 ...] <.nca file>\n"); + printf(" %s [--listfs] [--bodykey --titlekey ] [--part0 ...] <.nca file>\n", BIN_NAME); printf(" --listfs Print file system in embedded partitions.\n"); printf(" --titlekey Specify title key extracted from ticket.\n"); printf(" --bodykey Specify body encryption key.\n"); @@ -81,12 +81,12 @@ void UserSettings::showHelp() printf(" --part2 Extract \"partition 2\" to directory.\n"); printf(" --part3 Extract \"partition 3\" to directory.\n"); printf("\n NSO (Nintendo Software Object), NRO (Nintendo Relocatable Object)\n"); - printf(" nstool [--listapi --listsym] [--insttype ] \n"); + printf(" %s [--listapi --listsym] [--insttype ] \n", BIN_NAME); printf(" --listapi Print SDK API List.\n"); printf(" --listsym Print Code Symbols.\n"); printf(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n"); printf("\n ASET (Homebrew Asset Blob)\n"); - printf(" nstool [--listfs] [--icon --nacp --fsdir ] \n"); + printf(" %s [--listfs] [--icon --nacp --fsdir ] \n", BIN_NAME); printf(" --listfs Print filesystem in embedded RomFS partition.\n"); printf(" --icon Extract icon partition to file.\n"); printf(" --nacp Extract NACP partition to file.\n"); diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index a3c61db..eeddd6f 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -7,7 +7,7 @@ #include #include #include -#include "nstool.h" +#include "common.h" #include "KeyConfiguration.h" class UserSettings diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index 0978b18..bb9009c 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -7,7 +7,7 @@ #include "KeyConfiguration.h" #include "PfsProcess.h" -#include "nstool.h" +#include "common.h" class XciProcess { diff --git a/programs/nstool/source/nstool.h b/programs/nstool/source/common.h similarity index 100% rename from programs/nstool/source/nstool.h rename to programs/nstool/source/common.h diff --git a/programs/nstool/source/version.h b/programs/nstool/source/version.h index 88311a6..184fe13 100644 --- a/programs/nstool/source/version.h +++ b/programs/nstool/source/version.h @@ -1,4 +1,6 @@ #pragma once +#define APP_NAME "NSTool" +#define BIN_NAME "nstool" #define VER_MAJOR 1 #define VER_MINOR 0 #define VER_PATCH 3 From b136d646d0046954fa6a55669dcbb82b715f9668 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 22 Sep 2018 22:22:56 +0800 Subject: [PATCH 43/50] [fnd] Add more macros to BitMath.h --- lib/libfnd/include/fnd/BitMath.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libfnd/include/fnd/BitMath.h b/lib/libfnd/include/fnd/BitMath.h index f3a4ceb..722036a 100644 --- a/lib/libfnd/include/fnd/BitMath.h +++ b/lib/libfnd/include/fnd/BitMath.h @@ -1,8 +1,6 @@ /* BitMath.h (c) 2018 Jakcron - -This is a 0x40 byte header to prepend to raw EXEFS .code binaries that provide enough data to be equivalent to an ELF. */ #pragma once @@ -12,3 +10,5 @@ This is a 0x40 byte header to prepend to raw EXEFS .code binaries that provide e // Bit math macros #define _BIT(n) BIT(n) #define _HAS_BIT(val, bit) (((val) & _BIT(bit)) != 0) +#define _SET_BIT(val, bit) ((val) |= _BIT(bit)) +#define _BITMASK(width) (_BIT(width)-1) \ No newline at end of file From 44e054fb6ab7f8fea2650878fad9f8209b2a504b Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 22 Sep 2018 22:39:37 +0800 Subject: [PATCH 44/50] Retarget projects to different VS sdk. --- lib/libes/libes.vcxproj | 2 +- lib/libfnd/libfnd.vcxproj | 2 +- lib/libhac/libhac.vcxproj | 2 +- lib/liblz4/liblz4.vcxproj.filters | 4 ++-- lib/libpolarssl/libpolarssl.vcxproj | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/libes/libes.vcxproj b/lib/libes/libes.vcxproj index 9c25a22..b1fe783 100644 --- a/lib/libes/libes.vcxproj +++ b/lib/libes/libes.vcxproj @@ -20,7 +20,7 @@ {7BE99936-0D40-410D-944B-4513C2EFF8DC} - 8.1 + 10.0.16299.0 diff --git a/lib/libfnd/libfnd.vcxproj b/lib/libfnd/libfnd.vcxproj index b7d30e7..82253b7 100644 --- a/lib/libfnd/libfnd.vcxproj +++ b/lib/libfnd/libfnd.vcxproj @@ -21,7 +21,7 @@ 15.0 {4D27EDB9-5110-44FE-8CE2-D46C5AD3C55B} - 10.0.15063.0 + 10.0.16299.0 diff --git a/lib/libhac/libhac.vcxproj b/lib/libhac/libhac.vcxproj index fa7d25c..db66da1 100644 --- a/lib/libhac/libhac.vcxproj +++ b/lib/libhac/libhac.vcxproj @@ -125,7 +125,7 @@ 15.0 {91BA9E79-8242-4F7D-B997-0DFEC95EA22B} hac - 10.0.15063.0 + 10.0.16299.0 libhac diff --git a/lib/liblz4/liblz4.vcxproj.filters b/lib/liblz4/liblz4.vcxproj.filters index 054e80b..20d2490 100644 --- a/lib/liblz4/liblz4.vcxproj.filters +++ b/lib/liblz4/liblz4.vcxproj.filters @@ -15,8 +15,8 @@ - - Source Files + + Header Files diff --git a/lib/libpolarssl/libpolarssl.vcxproj b/lib/libpolarssl/libpolarssl.vcxproj index da665c4..e392881 100644 --- a/lib/libpolarssl/libpolarssl.vcxproj +++ b/lib/libpolarssl/libpolarssl.vcxproj @@ -21,7 +21,7 @@ 15.0 {394EFC16-BD3A-4538-B33D-7BA1EDB8DAC1} - 10.0.15063.0 + 10.0.16299.0 From 3b4c16d7ca1d1e77cdf86520ece2c8e97d3f66e9 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 23 Sep 2018 11:27:42 +0800 Subject: [PATCH 45/50] [fnd] Add SharedPtr template class. --- lib/libfnd/include/fnd/SharedPtr.h | 141 +++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 lib/libfnd/include/fnd/SharedPtr.h diff --git a/lib/libfnd/include/fnd/SharedPtr.h b/lib/libfnd/include/fnd/SharedPtr.h new file mode 100644 index 0000000..e976d4e --- /dev/null +++ b/lib/libfnd/include/fnd/SharedPtr.h @@ -0,0 +1,141 @@ +#pragma once +#include +#include + +namespace fnd +{ + template + class SharedPtr + { + public: + SharedPtr(); + + // constructor for creating owner object + SharedPtr(T* ptr); + + // copy constructor + SharedPtr(const SharedPtr& other); + + // destructor + ~SharedPtr(); + + // own operator + void operator=(T* ptr); + + // copy operator + void operator=(const SharedPtr& other); + + // access ptr + const T* operator*() const; + T* operator*(); + + private: + T* mPtr; + size_t* mRefCnt; + + void deletePtr(); + }; + + template + inline SharedPtr::SharedPtr() : + mPtr(nullptr), + mRefCnt(new size_t) + { + *mRefCnt = 0; + } + + template + inline SharedPtr::SharedPtr(T* ptr) : + SharedPtr() + { + *this = ptr; + } + + template + inline SharedPtr::SharedPtr(const SharedPtr& other) : + SharedPtr() + { + *this = other; + } + + template + inline SharedPtr::~SharedPtr() + { + deletePtr(); + } + + template + inline void SharedPtr::operator=(T* ptr) + { + deletePtr(); + if (ptr != nullptr) + { + mPtr = ptr; + mRefCnt = new size_t; + *mRefCnt = 1; + } + else + { + mPtr = nullptr; + mRefCnt = new size_t; + *mRefCnt = 0; + } + + } + + template + inline void SharedPtr::operator=(const SharedPtr& other) + { + deletePtr(); + + mPtr = other.mPtr; + mRefCnt = other.mRefCnt; + *mRefCnt += 1; + } + + template + inline const T* SharedPtr::operator*() const + { + return mPtr; + } + + template + inline T* SharedPtr::operator*() + { + return mPtr; + } + + template + inline void SharedPtr::deletePtr() + { + // if this is not the last reference + if (*mRefCnt > 1) + { + // decrement reference count + *mRefCnt -= 1; + + // make ptrs null + mPtr = nullptr; + mRefCnt = nullptr; + } + // if this is the last refeference + else if (*mRefCnt == 1) + { + // delete memory + delete mPtr; + delete mRefCnt; + + // make ptrs null + mPtr = nullptr; + mRefCnt = nullptr; + } + // else if this is an empty refernce + else if (*mRefCnt == 0) + { + delete mRefCnt; + + mPtr = nullptr; + mRefCnt = nullptr; + } + } +} \ No newline at end of file From f93acfad07cba0fc336567aad8f9bbc400ca1230 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 23 Sep 2018 11:29:22 +0800 Subject: [PATCH 46/50] [nstool] Improve fnd::IFile ptr handling/sharing with fnd::SharedPtr --- programs/nstool/source/AesCtrWrappedIFile.cpp | 25 +++------- programs/nstool/source/AesCtrWrappedIFile.h | 7 ++- programs/nstool/source/AssetProcess.cpp | 35 +++++-------- programs/nstool/source/AssetProcess.h | 7 ++- programs/nstool/source/CnmtProcess.cpp | 20 ++------ programs/nstool/source/CnmtProcess.h | 7 ++- programs/nstool/source/EsTikProcess.cpp | 20 ++------ programs/nstool/source/EsTikProcess.h | 7 ++- .../nstool/source/HashTreeWrappedIFile.cpp | 28 ++++------- programs/nstool/source/HashTreeWrappedIFile.h | 9 ++-- programs/nstool/source/NacpProcess.cpp | 20 ++------ programs/nstool/source/NacpProcess.h | 7 ++- programs/nstool/source/NcaProcess.cpp | 50 +++++-------------- programs/nstool/source/NcaProcess.h | 11 ++-- programs/nstool/source/NpdmProcess.cpp | 20 ++------ programs/nstool/source/NpdmProcess.h | 7 ++- programs/nstool/source/NroProcess.cpp | 30 ++++------- programs/nstool/source/NroProcess.h | 8 ++- programs/nstool/source/NsoProcess.cpp | 32 ++++-------- programs/nstool/source/NsoProcess.h | 8 ++- .../nstool/source/OffsetAdjustedIFile.cpp | 20 ++------ programs/nstool/source/OffsetAdjustedIFile.h | 7 ++- programs/nstool/source/PfsProcess.cpp | 26 +++------- programs/nstool/source/PfsProcess.h | 7 ++- programs/nstool/source/PkiCertProcess.cpp | 20 ++------ programs/nstool/source/PkiCertProcess.h | 7 ++- programs/nstool/source/RomfsProcess.cpp | 26 +++------- programs/nstool/source/RomfsProcess.h | 7 ++- programs/nstool/source/XciProcess.cpp | 24 +++------ programs/nstool/source/XciProcess.h | 7 ++- programs/nstool/source/main.cpp | 27 +++++----- 31 files changed, 179 insertions(+), 357 deletions(-) diff --git a/programs/nstool/source/AesCtrWrappedIFile.cpp b/programs/nstool/source/AesCtrWrappedIFile.cpp index 06ea584..3acebd7 100644 --- a/programs/nstool/source/AesCtrWrappedIFile.cpp +++ b/programs/nstool/source/AesCtrWrappedIFile.cpp @@ -1,7 +1,6 @@ #include "AesCtrWrappedIFile.h" -AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr) : - mOwnIFile(ownIfile), +AesCtrWrappedIFile::AesCtrWrappedIFile(const fnd::SharedPtr& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr) : mFile(file), mKey(key), mBaseCtr(ctr), @@ -10,17 +9,9 @@ AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fn mCache.alloc(kCacheSizeAllocSize); } -AesCtrWrappedIFile::~AesCtrWrappedIFile() -{ - if (mOwnIFile) - { - delete mFile; - } -} - size_t AesCtrWrappedIFile::size() { - return mFile->size(); + return (*mFile)->size(); } void AesCtrWrappedIFile::seek(size_t offset) @@ -44,8 +35,8 @@ void AesCtrWrappedIFile::read(byte_t* out, size_t len) //printf("[%x] AesCtrWrappedIFile::read() CACHE READ: readlen=%" PRIx64 "\n", this, read_len); - mFile->seek(read_pos); - mFile->read(mCache.data(), kCacheSizeAllocSize); + (*mFile)->seek(read_pos); + (*mFile)->read(mCache.data(), kCacheSizeAllocSize); fnd::aes::AesIncrementCounter(mBaseCtr.iv, read_pos>>4, mCurrentCtr.iv); fnd::aes::AesCtr(mCache.data(), kCacheSizeAllocSize, mKey.key, mCurrentCtr.iv, mCache.data()); @@ -81,8 +72,8 @@ void AesCtrWrappedIFile::write(const byte_t* in, size_t len) fnd::aes::AesIncrementCounter(mBaseCtr.iv, write_pos>>4, mCurrentCtr.iv); fnd::aes::AesCtr(mCache.data(), kCacheSizeAllocSize, mKey.key, mCurrentCtr.iv, mCache.data()); - mFile->seek(write_pos); - mFile->write(mCache.data(), kCacheSizeAllocSize); + (*mFile)->seek(write_pos); + (*mFile)->write(mCache.data(), kCacheSizeAllocSize); } seek(mFileOffset + len); @@ -92,7 +83,7 @@ void AesCtrWrappedIFile::write(const byte_t* in, size_t len) { memcpy(mScratch.data() + mBlockOffset, out + (i * kAesCtrScratchSize), kAesCtrScratchSize); fnd::aes::AesCtr(mScratch.data(), kAesCtrScratchAllocSize, mKey.key, mCurrentCtr.iv, mScratch.data()); - mFile->write(mScratch.data() + mBlockOffset, kAesCtrScratchSize); + (*mFile)->write(mScratch.data() + mBlockOffset, kAesCtrScratchSize); } if (len % kAesCtrScratchSize) @@ -101,7 +92,7 @@ void AesCtrWrappedIFile::write(const byte_t* in, size_t len) size_t write_pos = ((len / kAesCtrScratchSize) * kAesCtrScratchSize); memcpy(mScratch.data() + mBlockOffset, out + write_pos, write_len); fnd::aes::AesCtr(mScratch.data(), kAesCtrScratchAllocSize, mKey.key, mCurrentCtr.iv, mScratch.data()); - mFile->write(mScratch.data() + mBlockOffset, write_len); + (*mFile)->write(mScratch.data() + mBlockOffset, write_len); } */ seek(mFileOffset + len); diff --git a/programs/nstool/source/AesCtrWrappedIFile.h b/programs/nstool/source/AesCtrWrappedIFile.h index 1703bc8..0404cca 100644 --- a/programs/nstool/source/AesCtrWrappedIFile.h +++ b/programs/nstool/source/AesCtrWrappedIFile.h @@ -1,12 +1,12 @@ #include +#include #include #include class AesCtrWrappedIFile : public fnd::IFile { public: - AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr); - ~AesCtrWrappedIFile(); + AesCtrWrappedIFile(const fnd::SharedPtr& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr); size_t size(); void seek(size_t offset); @@ -19,8 +19,7 @@ private: static const size_t kCacheSize = 0x10000; static const size_t kCacheSizeAllocSize = kCacheSize + fnd::aes::kAesBlockSize; - bool mOwnIFile; - fnd::IFile* mFile; + fnd::SharedPtr mFile; fnd::aes::sAes128Key mKey; fnd::aes::sAesIvCtr mBaseCtr, mCurrentCtr; size_t mFileOffset; diff --git a/programs/nstool/source/AssetProcess.cpp b/programs/nstool/source/AssetProcess.cpp index 0128ee1..a218f20 100644 --- a/programs/nstool/source/AssetProcess.cpp +++ b/programs/nstool/source/AssetProcess.cpp @@ -7,20 +7,10 @@ AssetProcess::AssetProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { - -} - -AssetProcess::~AssetProcess() -{ - if (mOwnIFile) - { - delete mFile; - } } void AssetProcess::process() @@ -31,10 +21,9 @@ void AssetProcess::process() processSections(); } -void AssetProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void AssetProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void AssetProcess::setCliOutputMode(CliOutputMode type) @@ -72,18 +61,18 @@ void AssetProcess::importHeader() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - if (mFile->size() < sizeof(nn::hac::sAssetHeader)) + if ((*mFile)->size() < sizeof(nn::hac::sAssetHeader)) { throw fnd::Exception(kModuleName, "Corrupt ASET: file too small"); } scratch.alloc(sizeof(nn::hac::sAssetHeader)); - mFile->read(scratch.data(), 0, scratch.size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size()); } @@ -92,21 +81,21 @@ void AssetProcess::processSections() { if (mHdr.getIconInfo().size > 0 && mIconExtractPath.isSet) { - if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > mFile->size()) + if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > (*mFile)->size()) throw fnd::Exception(kModuleName, "ASET geometry for icon beyond file size"); fnd::SimpleFile outfile(mIconExtractPath.var, fnd::SimpleFile::Create); fnd::Vec cache; cache.alloc(mHdr.getIconInfo().size); - mFile->read(cache.data(), mHdr.getIconInfo().offset, cache.size()); + (*mFile)->read(cache.data(), mHdr.getIconInfo().offset, cache.size()); outfile.write(cache.data(), cache.size()); outfile.close(); } if (mHdr.getNacpInfo().size > 0) { - if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > mFile->size()) + if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > (*mFile)->size()) throw fnd::Exception(kModuleName, "ASET geometry for nacp beyond file size"); if (mNacpExtractPath.isSet) @@ -115,12 +104,12 @@ void AssetProcess::processSections() fnd::Vec cache; cache.alloc(mHdr.getNacpInfo().size); - mFile->read(cache.data(), mHdr.getNacpInfo().offset, cache.size()); + (*mFile)->read(cache.data(), mHdr.getNacpInfo().offset, cache.size()); outfile.write(cache.data(), cache.size()); outfile.close(); } - mNacp.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size), true); + mNacp.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size)); mNacp.setCliOutputMode(mCliOutputMode); mNacp.setVerifyMode(mVerify); @@ -129,10 +118,10 @@ void AssetProcess::processSections() if (mHdr.getRomfsInfo().size > 0) { - if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > mFile->size()) + if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > (*mFile)->size()) throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size"); - mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size), true); + mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size)); mRomfs.setCliOutputMode(mCliOutputMode); mRomfs.setVerifyMode(mVerify); diff --git a/programs/nstool/source/AssetProcess.h b/programs/nstool/source/AssetProcess.h index 64efbc7..7364d15 100644 --- a/programs/nstool/source/AssetProcess.h +++ b/programs/nstool/source/AssetProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "NacpProcess.h" #include "RomfsProcess.h" @@ -12,11 +13,10 @@ class AssetProcess { public: AssetProcess(); - ~AssetProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -30,8 +30,7 @@ public: private: const std::string kModuleName = "AssetProcess"; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index 29caeb4..8abc73d 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -5,21 +5,12 @@ #include "CnmtProcess.h" CnmtProcess::CnmtProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -CnmtProcess::~CnmtProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void CnmtProcess::process() { importCnmt(); @@ -28,10 +19,9 @@ void CnmtProcess::process() displayCnmt(); } -void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void CnmtProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void CnmtProcess::setCliOutputMode(CliOutputMode type) @@ -53,13 +43,13 @@ void CnmtProcess::importCnmt() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); + scratch.alloc((*mFile)->size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mCnmt.fromBytes(scratch.data(), scratch.size()); } diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index 2fbcd15..4fa561c 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "common.h" @@ -10,11 +11,10 @@ class CnmtProcess { public: CnmtProcess(); - ~CnmtProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -23,8 +23,7 @@ public: private: const std::string kModuleName = "CnmtProcess"; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp index 4832276..b3d1c73 100644 --- a/programs/nstool/source/EsTikProcess.cpp +++ b/programs/nstool/source/EsTikProcess.cpp @@ -9,21 +9,12 @@ EsTikProcess::EsTikProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -EsTikProcess::~EsTikProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void EsTikProcess::process() { importTicket(); @@ -35,10 +26,9 @@ void EsTikProcess::process() displayTicket(); } -void EsTikProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void EsTikProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg) @@ -66,13 +56,13 @@ void EsTikProcess::importTicket() fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); + scratch.alloc((*mFile)->size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mTik.fromBytes(scratch.data(), scratch.size()); } diff --git a/programs/nstool/source/EsTikProcess.h b/programs/nstool/source/EsTikProcess.h index 94f5b05..cf3e36e 100644 --- a/programs/nstool/source/EsTikProcess.h +++ b/programs/nstool/source/EsTikProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -13,11 +14,10 @@ class EsTikProcess { public: EsTikProcess(); - ~EsTikProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setKeyCfg(const KeyConfiguration& keycfg); void setCertificateChain(const fnd::List>& certs); void setCliOutputMode(CliOutputMode mode); @@ -26,8 +26,7 @@ public: private: const std::string kModuleName = "EsTikProcess"; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/HashTreeWrappedIFile.cpp b/programs/nstool/source/HashTreeWrappedIFile.cpp index 7ff7e7c..a69acb2 100644 --- a/programs/nstool/source/HashTreeWrappedIFile.cpp +++ b/programs/nstool/source/HashTreeWrappedIFile.cpp @@ -2,8 +2,7 @@ #include "HashTreeWrappedIFile.h" #include "OffsetAdjustedIFile.h" -HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr) : - mOwnIFile(ownIFile), +HashTreeWrappedIFile::HashTreeWrappedIFile(const fnd::SharedPtr& file, const HashTreeMeta& hdr) : mFile(file), mData(nullptr), mDataHashLayer(), @@ -12,18 +11,9 @@ HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, cons initialiseDataLayer(hdr); } -HashTreeWrappedIFile::~HashTreeWrappedIFile() -{ - if (mOwnIFile) - { - delete mFile; - } - delete mData; -} - size_t HashTreeWrappedIFile::size() { - return mData->size(); + return (*mData)->size(); } void HashTreeWrappedIFile::seek(size_t offset) @@ -118,7 +108,7 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr) cur.alloc(align(layer.size, layer.block_size)); // read layer - mFile->read(cur.data(), layer.offset, layer.size); + (*mFile)->read(cur.data(), layer.offset, layer.size); // validate blocks size_t validate_size; @@ -145,7 +135,7 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr) } // generate reader for data layer - mData = new OffsetAdjustedIFile(mFile, SHARED_IFILE, hdr.getDataLayer().offset, hdr.getDataLayer().size); + mData = new OffsetAdjustedIFile(mFile, hdr.getDataLayer().offset, hdr.getDataLayer().size); mDataOffset = 0; mDataBlockSize = hdr.getDataLayer().block_size; @@ -160,17 +150,17 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr) void HashTreeWrappedIFile::readData(size_t block_offset, size_t block_num) { - mData->seek(block_offset * mDataBlockSize); + (*mData)->seek(block_offset * mDataBlockSize); fnd::sha::sSha256Hash hash; // determine read size size_t read_len = 0; - if ((block_offset + block_num) == getBlockNum(mData->size())) + if ((block_offset + block_num) == getBlockNum((*mData)->size())) { - read_len = (block_num-1) * mDataBlockSize + getRemanderBlockReadSize(mData->size()); + read_len = (block_num-1) * mDataBlockSize + getRemanderBlockReadSize((*mData)->size()); memset(mCache.data(), 0, block_num * mDataBlockSize); } - else if ((block_offset + block_num) < getBlockNum(mData->size())) + else if ((block_offset + block_num) < getBlockNum((*mData)->size())) { read_len = block_num * mDataBlockSize; } @@ -180,7 +170,7 @@ void HashTreeWrappedIFile::readData(size_t block_offset, size_t block_num) } // read - mData->read(mCache.data(), block_offset * mDataBlockSize, read_len); + (*mData)->read(mCache.data(), block_offset * mDataBlockSize, read_len); if (block_num > mCacheBlockNum) { diff --git a/programs/nstool/source/HashTreeWrappedIFile.h b/programs/nstool/source/HashTreeWrappedIFile.h index 6e97181..dd3f70c 100644 --- a/programs/nstool/source/HashTreeWrappedIFile.h +++ b/programs/nstool/source/HashTreeWrappedIFile.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include "HashTreeMeta.h" @@ -9,8 +10,7 @@ class HashTreeWrappedIFile : public fnd::IFile { public: - HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr); - ~HashTreeWrappedIFile(); + HashTreeWrappedIFile(const fnd::SharedPtr& file, const HashTreeMeta& hdr); size_t size(); void seek(size_t offset); @@ -23,11 +23,10 @@ private: static const size_t kDefaultCacheSize = 0x10000; std::stringstream mErrorSs; - bool mOwnIFile; - fnd::IFile* mFile; + fnd::SharedPtr mFile; // data file - fnd::IFile* mData; + fnd::SharedPtr mData; size_t mDataOffset; size_t mDataBlockSize; fnd::List mDataHashLayer; diff --git a/programs/nstool/source/NacpProcess.cpp b/programs/nstool/source/NacpProcess.cpp index fb6d5bf..2d3b02f 100644 --- a/programs/nstool/source/NacpProcess.cpp +++ b/programs/nstool/source/NacpProcess.cpp @@ -6,21 +6,12 @@ #include "NacpProcess.h" NacpProcess::NacpProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -NacpProcess::~NacpProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void NacpProcess::process() { importNacp(); @@ -29,10 +20,9 @@ void NacpProcess::process() displayNacp(); } -void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void NacpProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void NacpProcess::setCliOutputMode(CliOutputMode type) @@ -54,13 +44,13 @@ void NacpProcess::importNacp() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); + scratch.alloc((*mFile)->size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mNacp.fromBytes(scratch.data(), scratch.size()); } diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h index 0e6aed3..8a5064c 100644 --- a/programs/nstool/source/NacpProcess.h +++ b/programs/nstool/source/NacpProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "common.h" @@ -10,11 +11,10 @@ class NacpProcess { public: NacpProcess(); - ~NacpProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -23,8 +23,7 @@ public: private: const std::string kModuleName = "NacpProcess"; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index f637e17..aa4f504 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -13,8 +13,7 @@ #include "HashTreeWrappedIFile.h" NcaProcess::NcaProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mListFs(false) @@ -22,23 +21,6 @@ NcaProcess::NcaProcess() : for (size_t i = 0; i < nn::hac::nca::kPartitionNum; i++) { mPartitionPath[i].doExtract = false; - mPartitions[i].reader = nullptr; - } -} - -NcaProcess::~NcaProcess() -{ - if (mOwnIFile) - { - delete mFile; - } - - for (size_t i = 0; i < nn::hac::nca::kPartitionNum; i++) - { - if (mPartitions[i].reader != nullptr) - { - delete mPartitions[i].reader; - } } } @@ -65,10 +47,9 @@ void NcaProcess::process() processPartitions(); } -void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void NcaProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg) @@ -117,13 +98,13 @@ void NcaProcess::setListFs(bool list_fs) void NcaProcess::importHeader() { - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } // read header block - mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); + (*mFile)->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); // decrypt header block fnd::aes::sAesXts128Key header_key; @@ -299,13 +280,13 @@ void NcaProcess::generatePartitionConfiguration() // create reader based on encryption type0 if (info.enc_type == nn::hac::nca::CRYPT_NONE) { - info.reader = new OffsetAdjustedIFile(mFile, SHARED_IFILE, info.offset, info.size); + info.reader = new OffsetAdjustedIFile(mFile, info.offset, info.size); } else if (info.enc_type == nn::hac::nca::CRYPT_AESCTR) { if (mContentKey.aes_ctr.isSet == false) throw fnd::Exception(kModuleName, "AES-CTR Key was not determined"); - info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, SHARED_IFILE, mContentKey.aes_ctr.var, info.aes_ctr), OWN_IFILE, info.offset, info.size); + info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, mContentKey.aes_ctr.var, info.aes_ctr), info.offset, info.size); } else if (info.enc_type == nn::hac::nca::CRYPT_AESXTS || info.enc_type == nn::hac::nca::CRYPT_AESCTREX) { @@ -323,9 +304,7 @@ void NcaProcess::generatePartitionConfiguration() // filter out unrecognised hash types, and hash based readers if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256 || info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY) { - fnd::IFile* tmp = info.reader; - info.reader = nullptr; - info.reader = new HashTreeWrappedIFile(tmp, OWN_IFILE, info.hash_tree_meta); + info.reader = new HashTreeWrappedIFile(info.reader, info.hash_tree_meta); } else if (info.hash_type != nn::hac::nca::HASH_NONE) { @@ -337,9 +316,6 @@ void NcaProcess::generatePartitionConfiguration() catch (const fnd::Exception& e) { info.fail_reason = std::string(e.error()); - if (info.reader != nullptr) - delete info.reader; - info.reader = nullptr; } } } @@ -359,10 +335,10 @@ void NcaProcess::validateNcaSignatures() { if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FORMAT_PFS0) { - if (mPartitions[nn::hac::nca::PARTITION_CODE].reader != nullptr) + if (*mPartitions[nn::hac::nca::PARTITION_CODE].reader != nullptr) { PfsProcess exefs; - exefs.setInputFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, SHARED_IFILE); + exefs.setInputFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader); exefs.setCliOutputMode(0); exefs.process(); @@ -372,7 +348,7 @@ void NcaProcess::validateNcaSignatures() const nn::hac::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList().getElement(kNpdmExefsPath); NpdmProcess npdm; - npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE); + npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, file.offset, file.size)); npdm.setCliOutputMode(0); npdm.process(); @@ -513,7 +489,7 @@ void NcaProcess::processPartitions() struct sPartitionInfo& partition = mPartitions[index]; // if the reader is null, skip - if (partition.reader == nullptr) + if (*partition.reader == nullptr) { std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable."; if (partition.fail_reason.empty() == false) @@ -527,7 +503,7 @@ void NcaProcess::processPartitions() if (partition.format_type == nn::hac::nca::FORMAT_PFS0) { PfsProcess pfs; - pfs.setInputFile(partition.reader, SHARED_IFILE); + pfs.setInputFile(partition.reader); pfs.setCliOutputMode(mCliOutputMode); pfs.setListFs(mListFs); if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM) @@ -546,7 +522,7 @@ void NcaProcess::processPartitions() else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS) { RomfsProcess romfs; - romfs.setInputFile(partition.reader, SHARED_IFILE); + romfs.setInputFile(partition.reader); romfs.setCliOutputMode(mCliOutputMode); romfs.setListFs(mListFs); if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM) diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index f467945..c5b0429 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -1,7 +1,8 @@ #pragma once #include #include -#include +#include +#include #include #include "HashTreeMeta.h" #include "KeyConfiguration.h" @@ -13,12 +14,11 @@ class NcaProcess { public: NcaProcess(); - ~NcaProcess(); void process(); // generic - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -35,8 +35,7 @@ private: const std::string kNpdmExefsPath = "main.npdm"; // user options - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; @@ -92,7 +91,7 @@ private: struct sPartitionInfo { - fnd::IFile* reader; + fnd::SharedPtr reader; std::string fail_reason; size_t offset; size_t size; diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index 71b9f14..c397b2e 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -3,21 +3,12 @@ #include "NpdmProcess.h" NpdmProcess::NpdmProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -NpdmProcess::~NpdmProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void NpdmProcess::process() { importNpdm(); @@ -50,10 +41,9 @@ void NpdmProcess::process() } } -void NpdmProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void NpdmProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void NpdmProcess::setKeyCfg(const KeyConfiguration& keycfg) @@ -80,13 +70,13 @@ void NpdmProcess::importNpdm() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); + scratch.alloc((*mFile)->size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mNpdm.fromBytes(scratch.data(), scratch.size()); } diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index a203c0e..b4868bd 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "KeyConfiguration.h" @@ -11,11 +12,10 @@ class NpdmProcess { public: NpdmProcess(); - ~NpdmProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -25,8 +25,7 @@ public: private: const std::string kModuleName = "NpdmProcess"; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp index 577cc95..83c1edb 100644 --- a/programs/nstool/source/NroProcess.cpp +++ b/programs/nstool/source/NroProcess.cpp @@ -8,21 +8,12 @@ #include "NroProcess.h" NroProcess::NroProcess(): - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -NroProcess::~NroProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void NroProcess::process() { importHeader(); @@ -37,10 +28,9 @@ void NroProcess::process() mAssetProc.process(); } -void NroProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void NroProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void NroProcess::setCliOutputMode(CliOutputMode type) @@ -97,27 +87,27 @@ void NroProcess::importHeader() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - if (mFile->size() < sizeof(nn::hac::sNroHeader)) + if ((*mFile)->size() < sizeof(nn::hac::sNroHeader)) { throw fnd::Exception(kModuleName, "Corrupt NRO: file too small"); } scratch.alloc(sizeof(nn::hac::sNroHeader)); - mFile->read(scratch.data(), 0, scratch.size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size()); // setup homebrew extension nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data(); - if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && mFile->size() > mHdr.getNroSize()) + if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && (*mFile)->size() > mHdr.getNroSize()) { mIsHomebrewNro = true; - mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true); + mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getNroSize(), (*mFile)->size() - mHdr.getNroSize())); mAssetProc.setCliOutputMode(mCliOutputMode); mAssetProc.setVerifyMode(mVerify); } @@ -128,11 +118,11 @@ void NroProcess::importHeader() void NroProcess::importCodeSegments() { mTextBlob.alloc(mHdr.getTextInfo().size); - mFile->read(mTextBlob.data(), mHdr.getTextInfo().memory_offset, mTextBlob.size()); + (*mFile)->read(mTextBlob.data(), mHdr.getTextInfo().memory_offset, mTextBlob.size()); mRoBlob.alloc(mHdr.getRoInfo().size); - mFile->read(mRoBlob.data(), mHdr.getRoInfo().memory_offset, mRoBlob.size()); + (*mFile)->read(mRoBlob.data(), mHdr.getRoInfo().memory_offset, mRoBlob.size()); mDataBlob.alloc(mHdr.getDataInfo().size); - mFile->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size()); + (*mFile)->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size()); } void NroProcess::displayHeader() diff --git a/programs/nstool/source/NroProcess.h b/programs/nstool/source/NroProcess.h index 7d27553..4ddd1eb 100644 --- a/programs/nstool/source/NroProcess.h +++ b/programs/nstool/source/NroProcess.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "AssetProcess.h" @@ -14,11 +15,10 @@ class NroProcess { public: NroProcess(); - ~NroProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -36,9 +36,7 @@ public: private: const std::string kModuleName = "NroProcess"; - fnd::IFile* mFile; - bool mOwnIFile; - + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index c99cd78..11261c6 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -7,21 +7,12 @@ #include "NsoProcess.h" NsoProcess::NsoProcess(): - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -NsoProcess::~NsoProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void NsoProcess::process() { importHeader(); @@ -32,10 +23,9 @@ void NsoProcess::process() processRoMeta(); } -void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void NsoProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void NsoProcess::setCliOutputMode(CliOutputMode type) @@ -72,18 +62,18 @@ void NsoProcess::importHeader() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - if (mFile->size() < sizeof(nn::hac::sNsoHeader)) + if ((*mFile)->size() < sizeof(nn::hac::sNsoHeader)) { throw fnd::Exception(kModuleName, "Corrupt NSO: file too small"); } scratch.alloc(sizeof(nn::hac::sNsoHeader)); - mFile->read(scratch.data(), 0, scratch.size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mHdr.fromBytes(scratch.data(), scratch.size()); } @@ -98,7 +88,7 @@ void NsoProcess::importCodeSegments() if (mHdr.getTextSegmentInfo().is_compressed) { scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size); - mFile->read(scratch.data(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.size()); + (*mFile)->read(scratch.data(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.size()); mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len); if (decompressed_len != mTextBlob.size()) @@ -109,7 +99,7 @@ void NsoProcess::importCodeSegments() else { mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size); - mFile->read(mTextBlob.data(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.size()); + (*mFile)->read(mTextBlob.data(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.size()); } if (mHdr.getTextSegmentInfo().is_hashed) { @@ -124,7 +114,7 @@ void NsoProcess::importCodeSegments() if (mHdr.getRoSegmentInfo().is_compressed) { scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size); - mFile->read(scratch.data(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.size()); + (*mFile)->read(scratch.data(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.size()); mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len); if (decompressed_len != mRoBlob.size()) @@ -135,7 +125,7 @@ void NsoProcess::importCodeSegments() else { mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size); - mFile->read(mRoBlob.data(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.size()); + (*mFile)->read(mRoBlob.data(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.size()); } if (mHdr.getRoSegmentInfo().is_hashed) { @@ -150,7 +140,7 @@ void NsoProcess::importCodeSegments() if (mHdr.getDataSegmentInfo().is_compressed) { scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size); - mFile->read(scratch.data(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.size()); + (*mFile)->read(scratch.data(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.size()); mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size); fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len); if (decompressed_len != mDataBlob.size()) @@ -161,7 +151,7 @@ void NsoProcess::importCodeSegments() else { mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size); - mFile->read(mDataBlob.data(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.size()); + (*mFile)->read(mDataBlob.data(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.size()); } if (mHdr.getDataSegmentInfo().is_hashed) { diff --git a/programs/nstool/source/NsoProcess.h b/programs/nstool/source/NsoProcess.h index a74beaf..88170ae 100644 --- a/programs/nstool/source/NsoProcess.h +++ b/programs/nstool/source/NsoProcess.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -13,11 +14,10 @@ class NsoProcess { public: NsoProcess(); - ~NsoProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -29,9 +29,7 @@ public: private: const std::string kModuleName = "NsoProcess"; - fnd::IFile* mFile; - bool mOwnIFile; - + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; nn::hac::npdm::InstructionType mInstructionType; diff --git a/programs/nstool/source/OffsetAdjustedIFile.cpp b/programs/nstool/source/OffsetAdjustedIFile.cpp index ad127f1..4891b39 100644 --- a/programs/nstool/source/OffsetAdjustedIFile.cpp +++ b/programs/nstool/source/OffsetAdjustedIFile.cpp @@ -1,21 +1,11 @@ #include "OffsetAdjustedIFile.h" -OffsetAdjustedIFile::OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size) : - mOwnIFile(ownIFile), +OffsetAdjustedIFile::OffsetAdjustedIFile(const fnd::SharedPtr& file, size_t offset, size_t size) : mFile(file), mBaseOffset(offset), mCurrentOffset(0), mSize(size) { - -} - -OffsetAdjustedIFile::~OffsetAdjustedIFile() -{ - if (mOwnIFile) - { - delete mFile; - } } size_t OffsetAdjustedIFile::size() @@ -31,8 +21,8 @@ void OffsetAdjustedIFile::seek(size_t offset) void OffsetAdjustedIFile::read(byte_t* out, size_t len) { // assert proper position in file - mFile->seek(mCurrentOffset + mBaseOffset); - mFile->read(out, len); + (*mFile)->seek(mCurrentOffset + mBaseOffset); + (*mFile)->read(out, len); seek(mCurrentOffset + len); } @@ -45,8 +35,8 @@ void OffsetAdjustedIFile::read(byte_t* out, size_t offset, size_t len) void OffsetAdjustedIFile::write(const byte_t* out, size_t len) { // assert proper position in file - mFile->seek(mCurrentOffset + mBaseOffset); - mFile->write(out, len); + (*mFile)->seek(mCurrentOffset + mBaseOffset); + (*mFile)->write(out, len); seek(mCurrentOffset + len); } diff --git a/programs/nstool/source/OffsetAdjustedIFile.h b/programs/nstool/source/OffsetAdjustedIFile.h index 4c68558..be3f582 100644 --- a/programs/nstool/source/OffsetAdjustedIFile.h +++ b/programs/nstool/source/OffsetAdjustedIFile.h @@ -1,10 +1,10 @@ #include +#include class OffsetAdjustedIFile : public fnd::IFile { public: - OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size); - ~OffsetAdjustedIFile(); + OffsetAdjustedIFile(const fnd::SharedPtr& file, size_t offset, size_t size); size_t size(); void seek(size_t offset); @@ -13,8 +13,7 @@ public: void write(const byte_t* out, size_t len); void write(const byte_t* out, size_t offset, size_t len); private: - bool mOwnIFile; - fnd::IFile* mFile; + fnd::SharedPtr mFile; size_t mBaseOffset, mCurrentOffset; size_t mSize; }; \ No newline at end of file diff --git a/programs/nstool/source/PfsProcess.cpp b/programs/nstool/source/PfsProcess.cpp index f878a4f..999b487 100644 --- a/programs/nstool/source/PfsProcess.cpp +++ b/programs/nstool/source/PfsProcess.cpp @@ -5,8 +5,7 @@ #include "PfsProcess.h" PfsProcess::PfsProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mExtractPath(), @@ -17,14 +16,6 @@ PfsProcess::PfsProcess() : { } -PfsProcess::~PfsProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void PfsProcess::process() { importHeader(); @@ -41,10 +32,9 @@ void PfsProcess::process() extractFs(); } -void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void PfsProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void PfsProcess::setCliOutputMode(CliOutputMode type) @@ -82,14 +72,14 @@ void PfsProcess::importHeader() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } // open minimum header to get full header size scratch.alloc(sizeof(nn::hac::sPfsHeader)); - mFile->read(scratch.data(), 0, scratch.size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false) { throw fnd::Exception(kModuleName, "Corrupt Header"); @@ -98,7 +88,7 @@ void PfsProcess::importHeader() // open minimum header to get full header size scratch.alloc(pfsHeaderSize); - mFile->read(scratch.data(), 0, scratch.size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); mPfs.fromBytes(scratch.data(), scratch.size()); } @@ -162,7 +152,7 @@ void PfsProcess::validateHfs() for (size_t i = 0; i < file.size(); i++) { mCache.alloc(file[i].hash_protected_size); - mFile->read(mCache.data(), file[i].offset, file[i].hash_protected_size); + (*mFile)->read(mCache.data(), file[i].offset, file[i].hash_protected_size); fnd::sha::Sha256(mCache.data(), file[i].hash_protected_size, hash.bytes); if (hash != file[i].hash) { @@ -193,10 +183,10 @@ void PfsProcess::extractFs() printf("extract=[%s]\n", file_path.c_str()); outFile.open(file_path, outFile.Create); - mFile->seek(file[i].offset); + (*mFile)->seek(file[i].offset); for (size_t j = 0; j < ((file[i].size / kCacheSize) + ((file[i].size % kCacheSize) != 0)); j++) { - mFile->read(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize)); + (*mFile)->read(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize)); outFile.write(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize)); } outFile.close(); diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h index 562dd21..bf9d61c 100644 --- a/programs/nstool/source/PfsProcess.h +++ b/programs/nstool/source/PfsProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "common.h" @@ -10,12 +11,11 @@ class PfsProcess { public: PfsProcess(); - ~PfsProcess(); void process(); // generic - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -30,8 +30,7 @@ private: const std::string kModuleName = "PfsProcess"; static const size_t kCacheSize = 0x10000; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/PkiCertProcess.cpp b/programs/nstool/source/PkiCertProcess.cpp index f9912a3..b3610f0 100644 --- a/programs/nstool/source/PkiCertProcess.cpp +++ b/programs/nstool/source/PkiCertProcess.cpp @@ -7,21 +7,12 @@ #include "PkiValidator.h" PkiCertProcess::PkiCertProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } -PkiCertProcess::~PkiCertProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void PkiCertProcess::process() { importCerts(); @@ -33,10 +24,9 @@ void PkiCertProcess::process() displayCerts(); } -void PkiCertProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void PkiCertProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg) @@ -58,13 +48,13 @@ void PkiCertProcess::importCerts() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } - scratch.alloc(mFile->size()); - mFile->read(scratch.data(), 0, scratch.size()); + scratch.alloc((*mFile)->size()); + (*mFile)->read(scratch.data(), 0, scratch.size()); nn::pki::SignedData cert; for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size()) diff --git a/programs/nstool/source/PkiCertProcess.h b/programs/nstool/source/PkiCertProcess.h index c281ae7..88ed54d 100644 --- a/programs/nstool/source/PkiCertProcess.h +++ b/programs/nstool/source/PkiCertProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -13,11 +14,10 @@ class PkiCertProcess { public: PkiCertProcess(); - ~PkiCertProcess(); void process(); - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -26,8 +26,7 @@ private: const std::string kModuleName = "PkiCertProcess"; static const size_t kSmallHexDumpLen = 0x10; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/RomfsProcess.cpp b/programs/nstool/source/RomfsProcess.cpp index cf68257..aba23fe 100644 --- a/programs/nstool/source/RomfsProcess.cpp +++ b/programs/nstool/source/RomfsProcess.cpp @@ -6,8 +6,7 @@ #include "RomfsProcess.h" RomfsProcess::RomfsProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mExtractPath(), @@ -22,14 +21,6 @@ RomfsProcess::RomfsProcess() : mRootDir.file_list.clear(); } -RomfsProcess::~RomfsProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void RomfsProcess::process() { resolveRomfs(); @@ -45,10 +36,9 @@ void RomfsProcess::process() extractFs(); } -void RomfsProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void RomfsProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void RomfsProcess::setCliOutputMode(CliOutputMode type) @@ -163,10 +153,10 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) std::cout << "extract=[" << file_path << "]" << std::endl; outFile.open(file_path, outFile.Create); - mFile->seek(dir.file_list[i].offset); + (*mFile)->seek(dir.file_list[i].offset); for (size_t j = 0; j < ((dir.file_list[i].size / kCacheSize) + ((dir.file_list[i].size % kCacheSize) != 0)); j++) { - mFile->read(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize)); + (*mFile)->read(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize)); outFile.write(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize)); } outFile.close(); @@ -258,13 +248,13 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) void RomfsProcess::resolveRomfs() { - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } // read header - mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader)); + (*mFile)->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader)); // logic check on the header layout if (validateHeaderLayout(&mHdr) == false) @@ -274,13 +264,13 @@ void RomfsProcess::resolveRomfs() // read directory nodes mDirNodes.alloc(mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].size.get()); - mFile->read(mDirNodes.data(), mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.size()); + (*mFile)->read(mDirNodes.data(), mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.size()); //printf("[RAW DIR NODES]\n"); //fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.data(), mDirNodes.size()); // read file nodes mFileNodes.alloc(mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].size.get()); - mFile->read(mFileNodes.data(), mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.size()); + (*mFile)->read(mFileNodes.data(), mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.size()); //printf("[RAW FILE NODES]\n"); //fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.data(), mFileNodes.size()); diff --git a/programs/nstool/source/RomfsProcess.h b/programs/nstool/source/RomfsProcess.h index 7132bba..9edb32c 100644 --- a/programs/nstool/source/RomfsProcess.h +++ b/programs/nstool/source/RomfsProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -77,12 +78,11 @@ public: }; RomfsProcess(); - ~RomfsProcess(); void process(); // generic - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -96,8 +96,7 @@ private: const std::string kModuleName = "RomfsProcess"; static const size_t kCacheSize = 0x10000; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index b68b32b..7fed532 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -6,8 +6,7 @@ #include "XciProcess.h" XciProcess::XciProcess() : - mFile(nullptr), - mOwnIFile(false), + mFile(), mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mListFs(false), @@ -16,14 +15,6 @@ XciProcess::XciProcess() : { } -XciProcess::~XciProcess() -{ - if (mOwnIFile) - { - delete mFile; - } -} - void XciProcess::process() { importHeader(); @@ -43,10 +34,9 @@ void XciProcess::process() processPartitionPfs(); } -void XciProcess::setInputFile(fnd::IFile* file, bool ownIFile) +void XciProcess::setInputFile(const fnd::SharedPtr& file) { mFile = file; - mOwnIFile = ownIFile; } void XciProcess::setKeyCfg(const KeyConfiguration& keycfg) @@ -78,13 +68,13 @@ void XciProcess::importHeader() { fnd::Vec scratch; - if (mFile == nullptr) + if (*mFile == nullptr) { throw fnd::Exception(kModuleName, "No file reader set."); } // read header page - mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage)); + (*mFile)->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage)); // allocate memory for and decrypt sXciHeader scratch.alloc(sizeof(nn::hac::sXciHeader)); @@ -193,7 +183,7 @@ bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* t fnd::Vec scratch; fnd::sha::sSha256Hash calc_hash; scratch.alloc(len); - mFile->read(scratch.data(), offset, scratch.size()); + (*mFile)->read(scratch.data(), offset, scratch.size()); fnd::sha::Sha256(scratch.data(), scratch.size(), calc_hash.bytes); return calc_hash.compare(test_hash); } @@ -216,7 +206,7 @@ void XciProcess::processRootPfs() { std::cout << "[WARNING] XCI Root HFS0: FAIL (bad hash)" << std::endl; } - mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE); + mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize())); mRootPfs.setListFs(mListFs); mRootPfs.setVerifyMode(false); mRootPfs.setCliOutputMode(mCliOutputMode); @@ -236,7 +226,7 @@ void XciProcess::processPartitionPfs() } PfsProcess tmp; - tmp.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size), OWN_IFILE); + tmp.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size)); tmp.setListFs(mListFs); tmp.setVerifyMode(mVerify); tmp.setCliOutputMode(mCliOutputMode); diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index bb9009c..6e034e7 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "KeyConfiguration.h" @@ -13,12 +14,11 @@ class XciProcess { public: XciProcess(); - ~XciProcess(); void process(); // generic - void setInputFile(fnd::IFile* file, bool ownIFile); + void setInputFile(const fnd::SharedPtr& file); void setKeyCfg(const KeyConfiguration& keycfg); void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); @@ -31,8 +31,7 @@ private: const std::string kModuleName = "XciProcess"; const std::string kXciMountPointName = "gamecard:/"; - fnd::IFile* mFile; - bool mOwnIFile; + fnd::SharedPtr mFile; KeyConfiguration mKeyCfg; CliOutputMode mCliOutputMode; bool mVerify; diff --git a/programs/nstool/source/main.cpp b/programs/nstool/source/main.cpp index 9659241..0e087c0 100644 --- a/programs/nstool/source/main.cpp +++ b/programs/nstool/source/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "UserSettings.h" #include "XciProcess.h" @@ -35,11 +36,13 @@ int main(int argc, char** argv) try { user_set.parseCmdArgs(args); + fnd::SharedPtr inputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read)); + if (user_set.getFileType() == FILE_XCI) { XciProcess xci; - xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + xci.setInputFile(inputFile); xci.setKeyCfg(user_set.getKeyCfg()); xci.setCliOutputMode(user_set.getCliOutputMode()); @@ -61,7 +64,7 @@ int main(int argc, char** argv) { PfsProcess pfs; - pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + pfs.setInputFile(inputFile); pfs.setCliOutputMode(user_set.getCliOutputMode()); pfs.setVerifyMode(user_set.isVerifyFile()); @@ -75,7 +78,7 @@ int main(int argc, char** argv) { RomfsProcess romfs; - romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + romfs.setInputFile(inputFile); romfs.setCliOutputMode(user_set.getCliOutputMode()); romfs.setVerifyMode(user_set.isVerifyFile()); @@ -89,7 +92,7 @@ int main(int argc, char** argv) { NcaProcess nca; - nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + nca.setInputFile(inputFile); nca.setKeyCfg(user_set.getKeyCfg()); nca.setCliOutputMode(user_set.getCliOutputMode()); nca.setVerifyMode(user_set.isVerifyFile()); @@ -111,7 +114,7 @@ int main(int argc, char** argv) { NpdmProcess npdm; - npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + npdm.setInputFile(inputFile); npdm.setKeyCfg(user_set.getKeyCfg()); npdm.setCliOutputMode(user_set.getCliOutputMode()); npdm.setVerifyMode(user_set.isVerifyFile()); @@ -122,7 +125,7 @@ int main(int argc, char** argv) { CnmtProcess cnmt; - cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + cnmt.setInputFile(inputFile); cnmt.setCliOutputMode(user_set.getCliOutputMode()); cnmt.setVerifyMode(user_set.isVerifyFile()); @@ -132,7 +135,7 @@ int main(int argc, char** argv) { NsoProcess obj; - obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + obj.setInputFile(inputFile); obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setVerifyMode(user_set.isVerifyFile()); @@ -146,7 +149,7 @@ int main(int argc, char** argv) { NroProcess obj; - obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + obj.setInputFile(inputFile); obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setVerifyMode(user_set.isVerifyFile()); @@ -169,7 +172,7 @@ int main(int argc, char** argv) { NacpProcess nacp; - nacp.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + nacp.setInputFile(inputFile); nacp.setCliOutputMode(user_set.getCliOutputMode()); nacp.setVerifyMode(user_set.isVerifyFile()); @@ -179,7 +182,7 @@ int main(int argc, char** argv) { PkiCertProcess cert; - cert.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + cert.setInputFile(inputFile); cert.setKeyCfg(user_set.getKeyCfg()); cert.setCliOutputMode(user_set.getCliOutputMode()); cert.setVerifyMode(user_set.isVerifyFile()); @@ -190,7 +193,7 @@ int main(int argc, char** argv) { EsTikProcess tik; - tik.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + tik.setInputFile(inputFile); tik.setKeyCfg(user_set.getKeyCfg()); tik.setCertificateChain(user_set.getCertificateChain()); tik.setCliOutputMode(user_set.getCliOutputMode()); @@ -202,7 +205,7 @@ int main(int argc, char** argv) { AssetProcess obj; - obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); + obj.setInputFile(inputFile); obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setVerifyMode(user_set.isVerifyFile()); From 2edc0d1f807e6f6301e949af4233b6f91f6b82d9 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 23 Sep 2018 11:32:22 +0800 Subject: [PATCH 47/50] [fnd] Update VS project files. --- lib/libfnd/libfnd.vcxproj | 1 + lib/libfnd/libfnd.vcxproj.filters | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/libfnd/libfnd.vcxproj b/lib/libfnd/libfnd.vcxproj index 82253b7..8be0a87 100644 --- a/lib/libfnd/libfnd.vcxproj +++ b/lib/libfnd/libfnd.vcxproj @@ -136,6 +136,7 @@ + diff --git a/lib/libfnd/libfnd.vcxproj.filters b/lib/libfnd/libfnd.vcxproj.filters index d13edab..1619016 100644 --- a/lib/libfnd/libfnd.vcxproj.filters +++ b/lib/libfnd/libfnd.vcxproj.filters @@ -63,6 +63,9 @@ Header Files + + Header Files + Header Files From 2e742ab4f03046a397821f9c64a6ef758410cb48 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 23 Sep 2018 11:39:27 +0800 Subject: [PATCH 48/50] [hac] Fixed bug with processing strings in NpdmBinary. --- lib/libhac/source/NpdmBinary.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/libhac/source/NpdmBinary.cpp b/lib/libhac/source/NpdmBinary.cpp index 716cc08..fe26c3a 100644 --- a/lib/libhac/source/NpdmBinary.cpp +++ b/lib/libhac/source/NpdmBinary.cpp @@ -132,16 +132,8 @@ void nn::hac::NpdmBinary::fromBytes(const byte_t* data, size_t len) mMainThreadCpuId = hdr.main_thread_cpu_id; mVersion = hdr.version.get(); mMainThreadStackSize = hdr.main_thread_stack_size.get(); - mName = std::string(hdr.name, npdm::kNameMaxLen); - if (mName[0] == '\0') - { - mName.clear(); - } - mProductCode = std::string(hdr.product_code, npdm::kProductCodeMaxLen); - if (mProductCode[0] == '\0') - { - mProductCode.clear(); - } + mName = std::string(hdr.name, _MIN(strlen(hdr.name), npdm::kNameMaxLen)); + mProductCode = std::string(hdr.product_code, _MIN(strlen(hdr.product_code), npdm::kProductCodeMaxLen)); // total size size_t total_size = _MAX(_MAX(hdr.acid.offset.get() + hdr.acid.size.get(), hdr.aci.offset.get() + hdr.aci.size.get()), sizeof(sNpdmHeader)); From 30e4b19b9939fbbc16f0097f2455fc93fab09138 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 23 Sep 2018 12:46:50 +0800 Subject: [PATCH 49/50] [nstool] Update VS project files. --- programs/nstool/nstool.vcxproj | 2 +- programs/nstool/nstool.vcxproj.filters | 6 +++--- programs/nstool/source/common.h | 6 ------ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/programs/nstool/nstool.vcxproj b/programs/nstool/nstool.vcxproj index b72bf95..d0605d4 100644 --- a/programs/nstool/nstool.vcxproj +++ b/programs/nstool/nstool.vcxproj @@ -181,6 +181,7 @@ + @@ -191,7 +192,6 @@ - diff --git a/programs/nstool/nstool.vcxproj.filters b/programs/nstool/nstool.vcxproj.filters index e9e9105..2cf288a 100644 --- a/programs/nstool/nstool.vcxproj.filters +++ b/programs/nstool/nstool.vcxproj.filters @@ -58,9 +58,6 @@ Header Files - - Header Files - Header Files @@ -91,6 +88,9 @@ Header Files + + Header Files + diff --git a/programs/nstool/source/common.h b/programs/nstool/source/common.h index 883ee44..555e040 100644 --- a/programs/nstool/source/common.h +++ b/programs/nstool/source/common.h @@ -8,12 +8,6 @@ static const size_t kMasterKeyNum = 0x20; static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum; -enum IFileOwnershipMode -{ - SHARED_IFILE = false, - OWN_IFILE = true -}; - enum FileType { FILE_XCI, From e99a294bd10ae851f0e1bfc63e4241e1b7966c64 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sun, 23 Sep 2018 12:48:00 +0800 Subject: [PATCH 50/50] [nstool] Bump version to v1.0.4 --- programs/nstool/source/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/nstool/source/version.h b/programs/nstool/source/version.h index 184fe13..24fccdf 100644 --- a/programs/nstool/source/version.h +++ b/programs/nstool/source/version.h @@ -3,5 +3,5 @@ #define BIN_NAME "nstool" #define VER_MAJOR 1 #define VER_MINOR 0 -#define VER_PATCH 3 +#define VER_PATCH 4 #define AUTHORS "jakcron" \ No newline at end of file