mirror of
https://github.com/jakcron/nstool
synced 2024-12-24 13:41:12 +00:00
[nstool] Add inital NCA support. Reads header and decrypts key area.
This commit is contained in:
parent
10655e828e
commit
bf1273e5ba
3 changed files with 189 additions and 11 deletions
172
programs/nstool/source/NcaProcess.cpp
Normal file
172
programs/nstool/source/NcaProcess.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
#include "NcaProcess.h"
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <nx/NcaUtils.h>
|
||||
|
||||
std::string kFormatVersionStr[]
|
||||
{
|
||||
"NCA2",
|
||||
"NCA3"
|
||||
};
|
||||
|
||||
std::string kDistributionTypeStr[]
|
||||
{
|
||||
"Download",
|
||||
"Game Card"
|
||||
};
|
||||
|
||||
std::string kContentTypeStr[]
|
||||
{
|
||||
"Program",
|
||||
"Meta",
|
||||
"Control",
|
||||
"Manual",
|
||||
"Data"
|
||||
};
|
||||
|
||||
std::string kEncryptionTypeStr[]
|
||||
{
|
||||
"Auto",
|
||||
"None",
|
||||
"AesXts",
|
||||
"AesCtr",
|
||||
"AesCtrEx"
|
||||
};
|
||||
|
||||
std::string kHashTypeStr[]
|
||||
{
|
||||
"Auto",
|
||||
"UNKNOWN_1",
|
||||
"HierarchicalSha256",
|
||||
"HierarchicalIntegrity"
|
||||
};
|
||||
|
||||
std::string kFormatTypeStr[]
|
||||
{
|
||||
"RomFs",
|
||||
"PartitionFs"
|
||||
};
|
||||
|
||||
std::string kKaekIndexStr[]
|
||||
{
|
||||
"Application",
|
||||
"Ocean",
|
||||
"System"
|
||||
};
|
||||
|
||||
void NcaProcess::displayHeader()
|
||||
{
|
||||
crypto::aes::sAes128Key zero_key;
|
||||
memset(zero_key.key, 0, sizeof(zero_key));
|
||||
|
||||
printf("[NCA Header]\n");
|
||||
printf(" Format Type: %s\n", kFormatVersionStr[mHdr.getFormatVersion()].c_str());
|
||||
printf(" Dist. Type: %s\n", kDistributionTypeStr[mHdr.getDistributionType()].c_str());
|
||||
printf(" Content Type: %s\n", kContentTypeStr[mHdr.getContentType()].c_str());
|
||||
printf(" Key Generation: %d\n", mHdr.getKeyGeneration());
|
||||
printf(" Kaek Index: %s (%d)\n", kKaekIndexStr[mHdr.getKaekIndex()].c_str(), mHdr.getKaekIndex());
|
||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getContentSize());
|
||||
printf(" ProgID: 0x%016" PRIx64 "\n", mHdr.getProgramId());
|
||||
printf(" Content Index: %" PRIu32 "\n", mHdr.getContentIndex());
|
||||
uint32_t ver = mHdr.getSdkAddonVersion();
|
||||
printf(" SdkAddon Ver.: v%d.%d.%d (v%" PRIu32 ")\n", (ver>>24 & 0xff),(ver>>16 & 0xff),(ver>>8 & 0xff), ver);
|
||||
printf(" RightsId: ");
|
||||
fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nx::nca::kRightsIdLen);
|
||||
printf(" Key Area Keys: (Encrypted)\n");
|
||||
for (size_t i = 0; i < mHdr.getEncAesKeys().getSize(); i++)
|
||||
{
|
||||
if (mHdr.getEncAesKeys()[i] != zero_key)
|
||||
{
|
||||
printf(" %2lu: ", i);
|
||||
fnd::SimpleTextOutput::hexDump(mHdr.getEncAesKeys()[i].key, crypto::aes::kAes128KeySize);
|
||||
}
|
||||
}
|
||||
|
||||
if (mBodyKeyList.getSize() > 0)
|
||||
{
|
||||
printf(" Key Area Keys:\n");
|
||||
for (size_t i = 0; i < mBodyKeyList.getSize(); i++)
|
||||
{
|
||||
printf(" %2lu: ", i);
|
||||
fnd::SimpleTextOutput::hexDump(mBodyKeyList[i].key, crypto::aes::kAes128KeySize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NcaProcess::decryptBodyKeyList()
|
||||
{
|
||||
crypto::aes::sAes128Key zero_key;
|
||||
memset(zero_key.key, 0, sizeof(zero_key));
|
||||
|
||||
byte_t masterkey_rev = nx::NcaUtils::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
|
||||
byte_t keak_index = mHdr.getKaekIndex();
|
||||
|
||||
crypto::aes::sAes128Key tmp_key;
|
||||
if (mKeyset->nca.key_area_key[keak_index][masterkey_rev] != zero_key)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
crypto::aes::AesEcbDecrypt(mHdr.getEncAesKeys()[i].key, 0x10, mKeyset->nca.key_area_key[keak_index][masterkey_rev].key, tmp_key.key);
|
||||
mBodyKeyList.addElement(tmp_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NcaProcess::NcaProcess() :
|
||||
mReader(nullptr),
|
||||
mOffset(0),
|
||||
mKeyset(nullptr),
|
||||
mCliOutputType(OUTPUT_NORMAL),
|
||||
mVerify(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NcaProcess::process()
|
||||
{
|
||||
fnd::MemoryBlob scratch;
|
||||
|
||||
if (mReader == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header block
|
||||
mReader->read((byte_t*)&mHdrBlock, mOffset, sizeof(nx::sNcaHeaderBlock));
|
||||
|
||||
// decrypt header block
|
||||
nx::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key);
|
||||
|
||||
// proccess main header
|
||||
mHdr.importBinary((byte_t*)&mHdrBlock.header, sizeof(nx::sNcaHeader));
|
||||
|
||||
// decrypt key area
|
||||
decryptBodyKeyList();
|
||||
|
||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||
displayHeader();
|
||||
}
|
||||
|
||||
void NcaProcess::setInputFile(fnd::IFile& reader)
|
||||
{
|
||||
mReader = &reader;
|
||||
}
|
||||
|
||||
void NcaProcess::setInputFileOffset(size_t offset)
|
||||
{
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
void NcaProcess::setKeyset(const sKeyset* keyset)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
}
|
||||
|
||||
void NcaProcess::setCliOutputMode(CliOutputType type)
|
||||
{
|
||||
mCliOutputType = type;
|
||||
}
|
||||
|
||||
void NcaProcess::setVerifyMode(bool verify)
|
||||
{
|
||||
mVerify = verify;
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <nx/nca.h>
|
||||
#include <nx/NcaHeader.h>
|
||||
|
||||
#include "nstool.h"
|
||||
|
@ -11,7 +10,6 @@ class NcaProcess
|
|||
{
|
||||
public:
|
||||
NcaProcess();
|
||||
~NcaProcess();
|
||||
|
||||
void process();
|
||||
|
||||
|
@ -27,7 +25,19 @@ public:
|
|||
private:
|
||||
const std::string kModuleName = "NcaProcess";
|
||||
|
||||
byte_t mRawHeader[nx::nca::kHeaderSize];
|
||||
std::string mPath;
|
||||
fnd::IFile* mReader;
|
||||
size_t mOffset;
|
||||
const sKeyset* mKeyset;
|
||||
CliOutputType mCliOutputType;
|
||||
bool mVerify;
|
||||
|
||||
nx::sNcaHeaderBlock mHdrBlock;
|
||||
nx::NcaHeader mHdr;
|
||||
|
||||
fnd::List<crypto::aes::sAes128Key> mBodyKeyList;
|
||||
|
||||
|
||||
void displayHeader();
|
||||
|
||||
void decryptBodyKeyList();
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
#include "XciProcess.h"
|
||||
#include "PfsProcess.h"
|
||||
#include "RomfsProcess.h"
|
||||
//#include "NcaProcess.h"
|
||||
#include "NcaProcess.h"
|
||||
#include "NpdmProcess.h"
|
||||
|
||||
|
||||
|
@ -54,7 +54,6 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else if (user_set.getFileType() == FILE_ROMFS)
|
||||
{
|
||||
|
||||
RomfsProcess romfs;
|
||||
|
||||
romfs.setInputFile(inputFile);
|
||||
|
@ -67,20 +66,17 @@ int main(int argc, char** argv)
|
|||
romfs.setListFs(user_set.isListFs());
|
||||
|
||||
romfs.process();
|
||||
|
||||
}
|
||||
else if (user_set.getFileType() == FILE_NCA)
|
||||
{
|
||||
/*
|
||||
NcaProcess nca;
|
||||
|
||||
nca.setNcaPath(user_set.getInputPath());
|
||||
nca.setKeyset(user_set.getKeyset());
|
||||
nca.setInputFile(inputFile);
|
||||
nca.setKeyset(&user_set.getKeyset());
|
||||
nca.setCliOutputMode(user_set.getCliOutputType());
|
||||
nca.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
nca.process();
|
||||
*/
|
||||
}
|
||||
else if (user_set.getFileType() == FILE_NPDM)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue