[nstool] First stage integrate KeyConfiguration

This commit is contained in:
jakcron 2018-08-20 19:56:28 +08:00
parent d4435b7559
commit 67a13b9d34
3 changed files with 90 additions and 225 deletions

View file

@ -1,6 +1,7 @@
#include "UserSettings.h" #include "UserSettings.h"
#include "version.h" #include "version.h"
#include "PkiValidator.h" #include "PkiValidator.h"
#include "KeyConfiguration.h"
#include <vector> #include <vector>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
@ -385,36 +386,25 @@ void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCm
void UserSettings::populateKeyset(sCmdArgs& args) 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)); memset((void*)&mKeyset, 0, sizeof(sKeyset));
fnd::ResourceFileReader res;
if (args.keyset_path.isSet) if (args.keyset_path.isSet)
{ {
res.processFile(*args.keyset_path); mKeyCfg.importHactoolGenericKeyfile(*args.keyset_path);
} }
else else
{ {
// open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set). // 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; std::string keyset_path;
fnd::io::appendToPath(keyset_path, home); getSwitchPath(keyset_path);
fnd::io::appendToPath(keyset_path, kHomeSwitchDirStr); if (keyset_path.empty())
fnd::io::appendToPath(keyset_path, kKeysetNameStr[args.devkit_keys.isSet ? *args.devkit_keys : 0]); return;
fnd::io::appendToPath(keyset_path, kGeneralKeyfileName[args.devkit_keys.isSet]);
try try
{ {
res.processFile(keyset_path); mKeyCfg.importHactoolGenericKeyfile(keyset_path);
} }
catch (const fnd::Exception&) catch (const fnd::Exception&)
{ {
@ -423,131 +413,43 @@ void UserSettings::populateKeyset(sCmdArgs& args)
} }
// suffix mKeyCfg.getPkiRootSignKey(nn::pki::sign::kRootIssuerStr, mKeyset.pki.root_sign_key);
const std::string kKeyStr = "key"; mKeyCfg.getAcidSignKey(mKeyset.acid_sign_key);
const std::string kKekStr = "kek"; mKeyCfg.getNcaHeader0SignKey(mKeyset.nca.header_sign_key);
const std::string kSourceStr = "source"; mKeyCfg.getNcaHeaderKey(mKeyset.nca.header_key);
const std::string kRsaKeySuffix[2] = {"sign_key_private", "sign_key_modulus"}; mKeyCfg.getXciHeaderSignKey(mKeyset.xci.header_sign_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"}; mKeyCfg.getXciHeaderKey(mKeyset.xci.header_key);
mKeyCfg.getPkg2SignKey(mKeyset.package2_sign_key);
// keyname bases for (size_t mkeyidx = 0; mkeyidx < 32; mkeyidx++)
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.getPkg1Key(mkeyidx, mKeyset.package1_key[mkeyidx]);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kMasterBase, kKeyStr, kKeyIndex[i]), master_key[i].key, 0x10); mKeyCfg.getPkg2Key(mkeyidx, mKeyset.package1_key[mkeyidx]);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage1Base, kKeyStr, kKeyIndex[i]), mKeyset.package1_key[i].key, 0x10); mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 0, mKeyset.nca.key_area_key[0][mkeyidx]);
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage2Base, kKeyStr, kKeyIndex[i]), mKeyset.package2_key[i].key, 0x10); mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 1, mKeyset.nca.key_area_key[1][mkeyidx]);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[0], kKeyIndex[i]), mKeyset.ticket.titlekey_kek[i].key, 0x10); mKeyCfg.getNcaKeyAreaEncryptionKey(mkeyidx, 2, mKeyset.nca.key_area_key[2][mkeyidx]);
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[1], kKeyIndex[i]), mKeyset.ticket.titlekey_kek[i].key, 0x10); mKeyCfg.getETicketCommonKey(mkeyidx, mKeyset.ticket.titlekey_kek[mkeyidx]);
_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);
} }
// 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.isSet)
{ {
if (args.nca_bodykey.var.length() == (sizeof(fnd::aes::sAes128Key)*2)) fnd::aes::sAes128Key tmp_key;
{ fnd::Vec<byte_t> tmp_raw;
decodeHexStringToBytes("--bodykey", args.nca_bodykey.var, mKeyset.nca.manual_body_key_aesctr.key, sizeof(fnd::aes::sAes128Key)); fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw);
} if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key))
else throw fnd::Exception(kModuleName, "Key: \"--bodykey\" has incorrect length");
{ memcpy(tmp_key.key, tmp_raw.data(), 16);
decodeHexStringToBytes("--bodykey", args.nca_bodykey.var, mKeyset.nca.manual_body_key_aesxts.key[0], sizeof(fnd::aes::sAesXts128Key)); mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserBodyKey, tmp_key);
}
} }
if (args.nca_titlekey.isSet) if (args.nca_titlekey.isSet)
{ {
if (args.nca_titlekey.var.length() == (sizeof(fnd::aes::sAes128Key)*2)) fnd::aes::sAes128Key tmp_key;
{ fnd::Vec<byte_t> tmp_raw;
decodeHexStringToBytes("--titlekey", args.nca_titlekey.var, mKeyset.nca.manual_title_key_aesctr.key, sizeof(fnd::aes::sAes128Key)); fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw);
} if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key))
else throw fnd::Exception(kModuleName, "Key: \"--titlekey\" has incorrect length");
{ memcpy(tmp_key.key, tmp_raw.data(), 16);
decodeHexStringToBytes("--titlekey", args.nca_titlekey.var, mKeyset.nca.manual_title_key_aesxts.key[0], sizeof(fnd::aes::sAesXts128Key)); mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key);
}
} }
// import certificate chain // import certificate chain
@ -615,7 +517,19 @@ void UserSettings::populateKeyset(sCmdArgs& args)
// extract title key // extract title key
if (tik.getBody().getTitleKeyEncType() == nn::es::ticket::AES128_CBC) 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 else
{ {
@ -623,67 +537,9 @@ void UserSettings::populateKeyset(sCmdArgs& args)
} }
} }
#undef _SAVE_KEYDATA // replicate keys into old keyset
#undef _CONCAT_3_STRINGS mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mKeyset.nca.manual_body_key_aesctr);
#undef _CONCAT_2_STRINGS mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, mKeyset.nca.manual_title_key_aesctr);
// 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);
}
}
*/
}
} }
void UserSettings::populateUserSettings(sCmdArgs& args) void UserSettings::populateUserSettings(sCmdArgs& args)
@ -747,21 +603,6 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
throw fnd::Exception(kModuleName, "Unknown file type."); 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) FileType UserSettings::getFileTypeFromString(const std::string& type_str)
{ {
std::string str = type_str; std::string str = type_str;
@ -1019,3 +860,25 @@ nn::hac::npdm::InstructionType UserSettings::getInstructionTypeFromString(const
return type; 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);
}

View file

@ -8,6 +8,7 @@
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include <nn/hac/npdm.h> #include <nn/hac/npdm.h>
#include "nstool.h" #include "nstool.h"
#include "KeyConfiguration.h"
class UserSettings class UserSettings
{ {
@ -19,6 +20,7 @@ public:
// generic options // generic options
const std::string getInputPath() const; const std::string getInputPath() const;
const KeyConfiguration& getKeyCfg() const;
const sKeyset& getKeyset() const; const sKeyset& getKeyset() const;
FileType getFileType() const; FileType getFileType() const;
bool isVerifyFile() const; bool isVerifyFile() const;
@ -44,9 +46,16 @@ public:
const sOptional<std::string>& getAssetNacpPath() const; const sOptional<std::string>& getAssetNacpPath() const;
const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& getCertificateChain() const; const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& getCertificateChain() const;
void dumpKeys() const;
private: private:
const std::string kModuleName = "UserSettings"; 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 struct sCmdArgs
{ {
sCmdArgs() {} sCmdArgs() {}
@ -82,6 +91,7 @@ private:
std::string mInputPath; std::string mInputPath;
FileType mFileType; FileType mFileType;
sKeyset mKeyset; sKeyset mKeyset;
KeyConfiguration mKeyCfg;
bool mVerifyFile; bool mVerifyFile;
CliOutputMode mOutputMode; CliOutputMode mOutputMode;
@ -109,7 +119,6 @@ private:
void populateCmdArgs(const std::vector<std::string>& arg_list, sCmdArgs& cmd_args); void populateCmdArgs(const std::vector<std::string>& arg_list, sCmdArgs& cmd_args);
void populateKeyset(sCmdArgs& args); void populateKeyset(sCmdArgs& args);
void populateUserSettings(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 getFileTypeFromString(const std::string& type_str);
FileType determineFileTypeFromFile(const std::string& path); FileType determineFileTypeFromFile(const std::string& path);
bool determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) const; bool determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) const;
@ -118,4 +127,6 @@ private:
bool determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const; bool determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const;
bool determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample) const; bool determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample) const;
nn::hac::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str); nn::hac::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
void getHomePath(std::string& path) const;
void getSwitchPath(std::string& path) const;
}; };

View file

@ -1,5 +1,4 @@
#pragma once #pragma once
#pragma once
#include <string> #include <string>
#include <fnd/types.h> #include <fnd/types.h>
#include <fnd/aes.h> #include <fnd/aes.h>
@ -61,6 +60,9 @@ struct sOptional
inline T& operator*() { return var; } 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 struct sKeyset
{ {
fnd::rsa::sRsa2048Key acid_sign_key; fnd::rsa::sRsa2048Key acid_sign_key;
@ -97,14 +99,3 @@ struct sKeyset
fnd::rsa::sRsa4096Key root_sign_key; fnd::rsa::sRsa4096Key root_sign_key;
} pki; } 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;
}