diff --git a/lib/nx/ISerialiseableBinary.h b/lib/fnd/ISerialiseableBinary.h similarity index 65% rename from lib/nx/ISerialiseableBinary.h rename to lib/fnd/ISerialiseableBinary.h index 1160464..ae4b339 100644 --- a/lib/nx/ISerialiseableBinary.h +++ b/lib/fnd/ISerialiseableBinary.h @@ -1,14 +1,11 @@ #pragma once #include -namespace nx +namespace fnd { class ISerialiseableBinary { public: - //virtual bool operator==(const ISerialiseableBinary& other) = 0; - //virtual void operator=(const ISerialiseableBinary& other) = 0; - virtual const u8* getBytes() const = 0; virtual size_t getSize() const = 0; @@ -17,5 +14,4 @@ namespace nx virtual void clear() = 0; }; -} - +} \ No newline at end of file diff --git a/lib/fnd/fnd.vcxproj b/lib/fnd/fnd.vcxproj index 3cae9da..858c981 100644 --- a/lib/fnd/fnd.vcxproj +++ b/lib/fnd/fnd.vcxproj @@ -118,6 +118,7 @@ + diff --git a/lib/fnd/fnd.vcxproj.filters b/lib/fnd/fnd.vcxproj.filters index 4f99952..e73663b 100644 --- a/lib/fnd/fnd.vcxproj.filters +++ b/lib/fnd/fnd.vcxproj.filters @@ -36,6 +36,9 @@ Header Files + + Header Files + diff --git a/lib/makefile b/lib/makefile index e7177c2..cc5fbcb 100644 --- a/lib/makefile +++ b/lib/makefile @@ -1,4 +1,4 @@ -LIBS = fnd crypto nx +LIBS = fnd crypto es nx main: build rebuild: clean build diff --git a/lib/nx/AciBinary.h b/lib/nx/AciBinary.h index 90c4d63..3b7810a 100644 --- a/lib/nx/AciBinary.h +++ b/lib/nx/AciBinary.h @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/nx/AciHeader.cpp b/lib/nx/AciHeader.cpp index 38ec15a..e743747 100644 --- a/lib/nx/AciHeader.cpp +++ b/lib/nx/AciHeader.cpp @@ -105,39 +105,23 @@ void AciHeader::exportBinary() hdr->kc().set_offset(mKc.offset); hdr->kc().set_size(mKc.size); - hdr->set_version(mFormatVersion); + u32 flags = 0; + if (mIsProduction) + flags |= BIT(0); + + hdr->set_flags(flags); if (mType == TYPE_ACI0) { // set program hdr->set_program_id(mProgramId); - switch (mFormatVersion) - { - case(0): - break; - default: - throw fnd::Exception(kModuleName, "Unsupported ACI0 version"); - } } else if (mType == TYPE_ACID) { - - switch (mFormatVersion) - { - case(0): - mAcidSize = getAciSize(); - hdr->set_size(mAcidSize); - hdr->set_program_id_min(0); - hdr->set_program_id_max(0); - break; - case(1): - hdr->set_size(0); - hdr->set_program_id_min(mProgramIdMin); - hdr->set_program_id_max(mProgramIdMax); - break; - default: - throw fnd::Exception(kModuleName, "Unsupported ACID version"); - } + mAcidSize = getAciSize(); + hdr->set_size(mAcidSize); + hdr->set_program_id_min(mProgramIdMin); + hdr->set_program_id_max(mProgramIdMax); } } @@ -172,38 +156,18 @@ void AciHeader::importBinary(const u8 * bytes, size_t len) if (mType == TYPE_ACI0) { mProgramId = hdr->program_id(); - mFormatVersion = hdr->version(); + mIsProduction = false; mAcidSize = 0; mProgramIdMin = 0; mProgramIdMax = 0; - - switch (mFormatVersion) - { - case(0): - break; - default: - throw fnd::Exception(kModuleName, "Unsupported ACI0 version"); - } } else if (mType == TYPE_ACID) { mProgramId = 0; - mFormatVersion = hdr->version(); - switch (mFormatVersion) - { - case(0): - mAcidSize = hdr->size(); - mProgramIdMin = 0; - mProgramIdMax = 0; - break; - case(1): - mAcidSize = 0; - mProgramIdMin = hdr->program_id_min(); - mProgramIdMax = hdr->program_id_max(); - break; - default: - throw fnd::Exception(kModuleName, "Unsupported ACID version"); - } + mIsProduction = (hdr->flags() & BIT(0)) == BIT(0); + mAcidSize = hdr->size(); + mProgramIdMin = hdr->program_id_min(); + mProgramIdMax = hdr->program_id_max(); } // the header offset is the MIN(sac.offset, fac.offset, kc.offset) - sizeof(sHeader) @@ -219,9 +183,14 @@ void AciHeader::importBinary(const u8 * bytes, size_t len) void nx::AciHeader::clear() { + mBinaryBlob.clear(); mHeaderOffset = 0; mType = TYPE_ACI0; mProgramId = 0; + mProgramIdMin = 0; + mProgramIdMax = 0; + mAcidSize = 0; + mIsProduction = false; mFac.offset = 0; mFac.size = 0; mSac.offset = 0; @@ -235,16 +204,6 @@ size_t nx::AciHeader::getAciSize() const return MAX(MAX(MAX(mSac.offset + mSac.size, mKc.offset + mKc.size), mFac.offset + mFac.size), sizeof(sAciHeader)); } -u32 nx::AciHeader::getFormatVersion() const -{ - return mFormatVersion; -} - -void nx::AciHeader::setFormatVersion(u32 version) -{ - mFormatVersion = version; -} - size_t nx::AciHeader::getAcidSize() const { return mAcidSize; @@ -292,6 +251,16 @@ void AciHeader::setAciType(AciType type) mType = type; } +bool nx::AciHeader::isProduction() const +{ + return mIsProduction; +} + +void nx::AciHeader::setIsProduction(bool isProduction) +{ + mIsProduction = isProduction; +} + u64 AciHeader::getProgramId() const { return mProgramId; diff --git a/lib/nx/AciHeader.h b/lib/nx/AciHeader.h index 2dad344..f45694a 100644 --- a/lib/nx/AciHeader.h +++ b/lib/nx/AciHeader.h @@ -2,11 +2,12 @@ #include #include #include -#include +#include namespace nx { - class AciHeader : public ISerialiseableBinary + class AciHeader : + public fnd::ISerialiseableBinary { public: enum AciType @@ -74,8 +75,8 @@ namespace nx void setHeaderOffset(size_t offset); AciType getAciType() const; void setAciType(AciType type); - u32 getFormatVersion() const; - void setFormatVersion(u32 version); + bool isProduction() const; + void setIsProduction(bool isProduction); const sSection& getFacPos() const; void setFacSize(size_t size); const sSection& getSacPos() const; @@ -94,9 +95,9 @@ namespace nx { private: u8 signature_[4]; - u32 size_; // includes prefacing signature, set only in ACID since it is signed + u32 size_; // includes prefacing signature, set only in ACID made by SDK (it enables easy resigning) u8 reserved_0[4]; - u32 version_; // set in ACID only, v0 has size, but no pid range, v1 has no size by pid range + u32 flags_; // set in ACID only u64 program_id_; // set only in ACI0 (since ACID is generic) u64 program_id_max_; struct sAciSection @@ -118,8 +119,8 @@ namespace nx u32 size() const { return le_word(size_); } void set_size(u32 size) { size_ = le_word(size); } - u32 version() const { return le_word(version_); } - void set_version(u32 version) { version_ = le_word(version); } + u32 flags() const { return le_word(flags_); } + void set_flags(u32 flags) { flags_ = le_word(flags); } u64 program_id() const { return le_dword(program_id_); } void set_program_id(u64 program_id) { program_id_ = le_dword(program_id); } @@ -155,8 +156,9 @@ namespace nx // ACI(D) variables size_t mHeaderOffset; AciType mType; - u32 mFormatVersion; + bool mIsProduction; sSection mFac, mSac, mKc; + void calculateSectionOffsets(); bool isEqual(const AciHeader& other) const; void copyFrom(const AciHeader& other); diff --git a/lib/nx/AcidBinary.h b/lib/nx/AcidBinary.h index 795ee7c..4f27159 100644 --- a/lib/nx/AcidBinary.h +++ b/lib/nx/AcidBinary.h @@ -1,7 +1,6 @@ #pragma once #include #include -#include #include #include diff --git a/lib/nx/FacBinary.h b/lib/nx/FacBinary.h index a1ee9dd..4b9d4e6 100644 --- a/lib/nx/FacBinary.h +++ b/lib/nx/FacBinary.h @@ -2,7 +2,6 @@ #include #include #include -#include #include diff --git a/lib/nx/FacHeader.h b/lib/nx/FacHeader.h index 1795b8c..10e1773 100644 --- a/lib/nx/FacHeader.h +++ b/lib/nx/FacHeader.h @@ -2,12 +2,12 @@ #include #include #include -#include +#include namespace nx { class FacHeader : - public ISerialiseableBinary + public fnd::ISerialiseableBinary { public: enum FsAccessFlag diff --git a/lib/nx/KcBinary.h b/lib/nx/KcBinary.h index 6f9147d..a339d27 100644 --- a/lib/nx/KcBinary.h +++ b/lib/nx/KcBinary.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -16,7 +16,7 @@ namespace nx { class KcBinary : - public ISerialiseableBinary + public fnd::ISerialiseableBinary { public: KcBinary(); diff --git a/lib/nx/NXCrypto.h b/lib/nx/NXCrypto.h index 4fdc9aa..76c781b 100644 --- a/lib/nx/NXCrypto.h +++ b/lib/nx/NXCrypto.h @@ -46,32 +46,43 @@ namespace crypto TitleKeyGenarateKey }; - u8 titlekey_generate_key[0x20] = { 39, 111, 56, 188, 68, 106, 241, 86, 31, 44, 90, 111, 116, 32, 93, 197, 25, 181, 59, 188, 178, 159, 211, 175, 212, 178, 162, 4, 28, 152, 117, 126 }; - - // aes128-cbc keys - u8 xci_header_key[16] = { 0x01, 0xc5, 0x8f, 0xe7, 0x2d, 0x13, 0x5a, 0xb2, 0x9a, 0x3f, 0x69, 0x33, 0x95, 0x74, 0xb1 }; - u8 eticket_common_key[16] = { 0x55, 0xA3, 0xF8, 0x72, 0xBD, 0xC8, 0x0C, 0x55, 0x5A, 0x65, 0x43, 0x81, 0x13, 0x9E, 0x15, 0x3B }; // lol this 3ds dev common key - - // aes128-xts keys (seem to use 512 block sizes, aka 0x200 blocks) - u8 nca_body_key[2][16] = + namespace dev { - { 0xE5, 0x64, 0xDB, 0xFE, 0x52, 0x93, 0x3A, 0x65, 0x3C, 0x8B, 0x5E, 0xF8, 0x2C, 0x9D, 0xF4, 0xB5 }, - { 0x60, 0x7B, 0x77, 0x3E, 0x31, 0xE9, 0x6A, 0x8F, 0x8E, 0x44, 0x5C, 0x98, 0x71, 0xC0, 0x57, 0xDB }, - }; + // aes128-xts keys (seem to use 512 block sizes, aka 0x200 blocks) + u8 nca_body_key[2][16] = + { + { 0xE5, 0x64, 0xDB, 0xFE, 0x52, 0x93, 0x3A, 0x65, 0x3C, 0x8B, 0x5E, 0xF8, 0x2C, 0x9D, 0xF4, 0xB5 }, + { 0x60, 0x7B, 0x77, 0x3E, 0x31, 0xE9, 0x6A, 0x8F, 0x8E, 0x44, 0x5C, 0x98, 0x71, 0xC0, 0x57, 0xDB }, + }; - u8 nca_header_key[2][16] = - { - { 0xCB, 0x9A, 0x93, 0x9F, 0x82, 0x72, 0x54, 0x4A, 0x74, 0x5D, 0x28, 0x46, 0x9D, 0xCC, 0x38, 0x12 }, - { 0x06, 0x31, 0x27, 0x06, 0xAE, 0x62, 0x56, 0x8C, 0x5B, 0x7E, 0xE6, 0x9F, 0x7E, 0x01, 0x02, 0x24 }, - }; + u8 nca_header_key[2][16] = + { + { 0xCB, 0x9A, 0x93, 0x9F, 0x82, 0x72, 0x54, 0x4A, 0x74, 0x5D, 0x28, 0x46, 0x9D, 0xCC, 0x38, 0x12 }, + { 0x06, 0x31, 0x27, 0x06, 0xAE, 0x62, 0x56, 0x8C, 0x5B, 0x7E, 0xE6, 0x9F, 0x7E, 0x01, 0x02, 0x24 }, + }; - u8 nca_otherkey[2][16] = + // aeskey, related to m_KeyAreaEncryptionKeyList (first in list?) + u8 key_area_encryption_key_0[0x10] = { 0x3A, 0x7C, 0x3E, 0x38, 0x4A, 0x8F, 0x22, 0xFF, 0x4B, 0x21, 0x57, 0x19, 0xB7, 0x81, 0xAD, 0x0C }; + + u8 titlekey_generate_key[0x20] = { 39, 111, 56, 188, 68, 106, 241, 86, 31, 44, 90, 111, 116, 32, 93, 197, 25, 181, 59, 188, 178, 159, 211, 175, 212, 178, 162, 4, 28, 152, 117, 126 }; + + // aes128-cbc keys + u8 xci_header_key[16] = { 0x01, 0xc5, 0x8f, 0xe7, 0x2d, 0x13, 0x5a, 0xb2, 0x9a, 0x3f, 0x69, 0x33, 0x95, 0x74, 0xb1 }; + u8 eticket_common_key[16] = { 0x55, 0xA3, 0xF8, 0x72, 0xBD, 0xC8, 0x0C, 0x55, 0x5A, 0x65, 0x43, 0x81, 0x13, 0x9E, 0x15, 0x3B }; // lol this 3ds dev common key + } + + namespace prod { - { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0 }, - { 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2 } - }; - // aeskey, related to m_KeyAreaEncryptionKeyList (first in list?) - u8 key_area_encryption_key_0[0x10] = { 0x3A, 0x7C, 0x3E, 0x38, 0x4A, 0x8F, 0x22, 0xFF, 0x4B, 0x21, 0x57, 0x19, 0xB7, 0x81, 0xAD, 0x0C }; + // encrypted with ProdNcaHeaderEncryptionKek + u8 nca_enc_header_key[2][16] = + { + { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0 }, + { 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2 } + }; + } + + + } } diff --git a/lib/nx/NcaHeader.h b/lib/nx/NcaHeader.h index 33c4ffd..0484a13 100644 --- a/lib/nx/NcaHeader.h +++ b/lib/nx/NcaHeader.h @@ -5,11 +5,12 @@ #include #include #include -#include +#include namespace nx { - class NcaHeader : public ISerialiseableBinary + class NcaHeader : + public fnd::ISerialiseableBinary { public: enum DistributionType diff --git a/lib/nx/NpdmBinary.h b/lib/nx/NpdmBinary.h index 9358455..d61466f 100644 --- a/lib/nx/NpdmBinary.h +++ b/lib/nx/NpdmBinary.h @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/nx/NpdmHeader.h b/lib/nx/NpdmHeader.h index ad630b5..ddb11ef 100644 --- a/lib/nx/NpdmHeader.h +++ b/lib/nx/NpdmHeader.h @@ -2,12 +2,12 @@ #include #include #include -#include +#include namespace nx { class NpdmHeader : - public nx::ISerialiseableBinary + public fnd::ISerialiseableBinary { public: enum InstructionType diff --git a/lib/nx/PfsHeader.h b/lib/nx/PfsHeader.h index fbd8a57..d1e7d39 100644 --- a/lib/nx/PfsHeader.h +++ b/lib/nx/PfsHeader.h @@ -3,13 +3,13 @@ #include #include #include -#include +#include namespace nx { class PfsHeader : - public ISerialiseableBinary + public fnd::ISerialiseableBinary { public: struct sFile diff --git a/lib/nx/SacBinary.h b/lib/nx/SacBinary.h index f19b6e6..6b5fd7c 100644 --- a/lib/nx/SacBinary.h +++ b/lib/nx/SacBinary.h @@ -3,13 +3,13 @@ #include #include #include -#include +#include #include namespace nx { class SacBinary : - public ISerialiseableBinary + public fnd::ISerialiseableBinary { public: SacBinary(); diff --git a/lib/nx/SacEntry.h b/lib/nx/SacEntry.h index d50c706..55dbf3f 100644 --- a/lib/nx/SacEntry.h +++ b/lib/nx/SacEntry.h @@ -2,11 +2,12 @@ #include #include #include -#include +#include namespace nx { - class SacEntry : public ISerialiseableBinary + class SacEntry : + public fnd::ISerialiseableBinary { public: SacEntry(); diff --git a/lib/nx/XciHeader.h b/lib/nx/XciHeader.h index 1370a4e..e707413 100644 --- a/lib/nx/XciHeader.h +++ b/lib/nx/XciHeader.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include namespace nx { diff --git a/lib/nx/nx.vcxproj b/lib/nx/nx.vcxproj index b8ee91b..9a92938 100644 --- a/lib/nx/nx.vcxproj +++ b/lib/nx/nx.vcxproj @@ -29,7 +29,6 @@ - @@ -161,6 +160,7 @@ true true true + ..\ true diff --git a/lib/nx/nx.vcxproj.filters b/lib/nx/nx.vcxproj.filters index c3e4800..db662da 100644 --- a/lib/nx/nx.vcxproj.filters +++ b/lib/nx/nx.vcxproj.filters @@ -27,9 +27,6 @@ Header Files - - Header Files - Header Files diff --git a/programs/ncatool/main.cpp b/programs/ncatool/main.cpp index ca13323..bc985a6 100644 --- a/programs/ncatool/main.cpp +++ b/programs/ncatool/main.cpp @@ -138,7 +138,7 @@ int main(int argc, char** argv) // nca test if (argc == 2 || argc == 3) { - decryptNcaSectorXts(nca, sector, 1, crypto::aes::nx::nca_header_key[0], crypto::aes::nx::nca_header_key[1]); + decryptNcaSectorXts(nca, sector, 1, crypto::aes::nx::dev::nca_header_key[0], crypto::aes::nx::dev::nca_header_key[1]); nx::NcaHeader hdr; hdr.importBinary(sector, kNcaSectorSize); @@ -193,6 +193,19 @@ int main(int argc, char** argv) } } } + if (argc == 4) + { + printf("encrypt test\n"); + u8 sect[kNcaSectorSize] = { 0 }; + u8 enc_sect[kNcaSectorSize * 6]; + u8 tweak[crypto::aes::kAesBlockSize]; + for (size_t i = 0; i < 6; i++) + { + crypto::aes::AesXtsMakeTweak(tweak, i); + crypto::aes::AesXtsEncryptSector(sect, kNcaSectorSize, crypto::aes::nx::dev::nca_header_key[0], crypto::aes::nx::dev::nca_header_key[1], tweak, enc_sect + i*kNcaSectorSize); + } + fnd::io::writeFile("testenc.bin", enc_sect, kNcaSectorSize * 6); + } } catch (const fnd::Exception& e) { diff --git a/programs/npdmtool/main.cpp b/programs/npdmtool/main.cpp index 8827c3b..7d418ce 100644 --- a/programs/npdmtool/main.cpp +++ b/programs/npdmtool/main.cpp @@ -212,6 +212,8 @@ const std::string kSysCall[0x80] = const std::string kMemMapPerm[2] = { "RW", "RO" }; const std::string kMemMapType[2] = { "Io", "Static" }; +const std::string kAcidTarget[2] = { "Development", "Production" }; + void displayNpdmHeader(const nx::NpdmHeader& hdr) { printf("[NPDM HEADER]\n"); @@ -241,17 +243,12 @@ void displayAciHdr(const nx::AciHeader& aci) } else if (aci.getAciType() == nx::AciBinary::TYPE_ACID) { - switch (aci.getFormatVersion()) - { - case (0): - printf(" ACID Size: %" PRIx64 "\n", aci.getAcidSize()); - break; - case (1): - printf(" ProgramID Restriction\n"); - printf(" Min: %016" PRIx64 "\n", aci.getProgramIdMin()); - printf(" Max: %016" PRIx64 "\n", aci.getProgramIdMax()); - break; - } + + printf(" ACID Size: %" PRIx64 "\n", aci.getAcidSize()); + printf(" Target: %s\n", kAcidTarget[aci.isProduction()].c_str()); + printf(" ProgramID Restriction\n"); + printf(" Min: %016" PRIx64 "\n", aci.getProgramIdMin()); + printf(" Max: %016" PRIx64 "\n", aci.getProgramIdMax()); } }