[nstool] Migrated from sKeyset to KeyConfiguration

This commit is contained in:
jakcron 2018-08-21 20:03:19 +08:00
parent 67a13b9d34
commit 1fd8f59025
18 changed files with 149 additions and 140 deletions

View file

@ -41,9 +41,9 @@ void EsTikProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = 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<nn::pki::SignedData<nn::pki::CertificateBody>>& certs) void EsTikProcess::setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
@ -95,7 +95,7 @@ void EsTikProcess::verifyTicket()
try try
{ {
pki_validator.setRootKey(mKeyset->pki.root_sign_key); pki_validator.setKeyCfg(mKeyCfg);
pki_validator.addCertificates(mCerts); pki_validator.addCertificates(mCerts);
pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash); pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash);
} }

View file

@ -6,6 +6,7 @@
#include <nn/pki/SignedData.h> #include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include <nn/es/TicketBody_V2.h> #include <nn/es/TicketBody_V2.h>
#include "KeyConfiguration.h"
#include "nstool.h" #include "nstool.h"
class EsTikProcess class EsTikProcess
@ -17,7 +18,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyCfg(const KeyConfiguration& keycfg);
void setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs); void setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void setCliOutputMode(CliOutputMode mode); void setCliOutputMode(CliOutputMode mode);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -27,7 +28,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;

View file

@ -10,6 +10,39 @@ KeyConfiguration::KeyConfiguration()
clearNcaExternalKeys(); 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) void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
{ {
clearGeneralKeyConfiguration(); clearGeneralKeyConfiguration();

View file

@ -13,6 +13,9 @@ class KeyConfiguration
{ {
public: public:
KeyConfiguration(); KeyConfiguration();
KeyConfiguration(const KeyConfiguration& other);
void operator=(const KeyConfiguration& other);
void importHactoolGenericKeyfile(const std::string& path); void importHactoolGenericKeyfile(const std::string& path);
//void importHactoolTitleKeyfile(const std::string& path); //void importHactoolTitleKeyfile(const std::string& path);

View file

@ -15,7 +15,6 @@
NcaProcess::NcaProcess() : NcaProcess::NcaProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mKeyset(nullptr),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mListFs(false) mListFs(false)
@ -72,9 +71,9 @@ void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void NcaProcess::setKeyset(const sKeyset* keyset) void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg)
{ {
mKeyset = keyset; mKeyCfg = keycfg;
} }
void NcaProcess::setCliOutputMode(CliOutputMode type) void NcaProcess::setCliOutputMode(CliOutputMode type)
@ -127,7 +126,9 @@ void NcaProcess::importHeader()
mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock)); mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock));
// decrypt header block // 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 // generate header hash
fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes); 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(); byte_t keak_index = mHdr.getKaekIndex();
// process key area // 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++) for (size_t i = 0; i < nn::hac::nca::kAesKeyNum; i++)
{ {
if (mHdr.getEncAesKeys()[i] != zero_aesctr_key) if (mHdr.getEncAesKeys()[i] != zero_aesctr_key)
{ {
keak.index = (byte_t)i; kak.index = (byte_t)i;
keak.enc = mHdr.getEncAesKeys()[i]; kak.enc = mHdr.getEncAesKeys()[i];
if (i < 4 && mKeyset->nca.key_area_key[keak_index][masterkey_rev] != zero_aesctr_key) // key[0-3]
if (i < 4 && mKeyCfg.getNcaKeyAreaEncryptionKey(masterkey_rev, keak_index, key_area_enc_key) == true)
{ {
keak.decrypted = true; kak.decrypted = true;
nn::hac::AesKeygen::generateKey(keak.dec.key, keak.enc.key, mKeyset->nca.key_area_key[keak_index][masterkey_rev].key); 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 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 this has a rights id, the key needs to be sourced from a ticket
if (mHdr.hasRightsId() == true) if (mHdr.hasRightsId() == true)
{ {
// if the titlekey_kek is available fnd::aes::sAes128Key tmp_key;
if (mKeyset->ticket.titlekey_kek[masterkey_rev] != zero_aesctr_key) if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true)
{ {
// the title key is provided (sourced from ticket) mBodyKeys.aes_ctr = tmp_key;
if (mKeyset->nca.manual_title_key_aesctr != zero_aesctr_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); nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.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;
} }
mBodyKeys.aes_ctr = tmp_key;
} }
} }
// otherwise decrypt key area // 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 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 (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mBodyKeys.aes_ctr.var) == true)
} mBodyKeys.aes_ctr.isSet = true;
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 (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
{ {
if (mBodyKeys.aes_ctr.isSet) if (mBodyKeys.aes_ctr.isSet)
@ -365,7 +370,9 @@ void NcaProcess::generatePartitionConfiguration()
void NcaProcess::validateNcaSignatures() void NcaProcess::validateNcaSignatures()
{ {
// validate signature[0] // 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; std::cout << "[WARNING] NCA Header Main Signature: FAIL" << std::endl;
} }

View file

@ -4,6 +4,7 @@
#include <fnd/SimpleFile.h> #include <fnd/SimpleFile.h>
#include <nn/hac/NcaHeader.h> #include <nn/hac/NcaHeader.h>
#include "HashTreeMeta.h" #include "HashTreeMeta.h"
#include "KeyConfiguration.h"
#include "nstool.h" #include "nstool.h"
@ -18,7 +19,7 @@ public:
// generic // generic
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -36,7 +37,7 @@ private:
// user options // user options
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;

View file

@ -5,7 +5,6 @@
NpdmProcess::NpdmProcess() : NpdmProcess::NpdmProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mKeyset(nullptr),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false) mVerify(false)
{ {
@ -57,9 +56,9 @@ void NpdmProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void NpdmProcess::setKeyset(const sKeyset* keyset) void NpdmProcess::setKeyCfg(const KeyConfiguration& keycfg)
{ {
mKeyset = keyset; mKeyCfg = keycfg;
} }
void NpdmProcess::setCliOutputMode(CliOutputMode type) void NpdmProcess::setCliOutputMode(CliOutputMode type)
@ -95,7 +94,11 @@ void NpdmProcess::importNpdm()
void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid) void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid)
{ {
try { 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 (...) { catch (...) {
std::cout << "[WARNING] ACID Signature: FAIL" << std::endl; std::cout << "[WARNING] ACID Signature: FAIL" << std::endl;

View file

@ -3,6 +3,7 @@
#include <fnd/types.h> #include <fnd/types.h>
#include <fnd/IFile.h> #include <fnd/IFile.h>
#include <nn/hac/NpdmBinary.h> #include <nn/hac/NpdmBinary.h>
#include "KeyConfiguration.h"
#include "nstool.h" #include "nstool.h"
@ -15,7 +16,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -26,7 +27,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;

View file

@ -39,9 +39,9 @@ void PkiCertProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void PkiCertProcess::setKeyset(const sKeyset* keyset) void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg)
{ {
mKeyset = keyset; mKeyCfg = keycfg;
} }
void PkiCertProcess::setCliOutputMode(CliOutputMode mode) void PkiCertProcess::setCliOutputMode(CliOutputMode mode)
@ -80,7 +80,7 @@ void PkiCertProcess::validateCerts()
try try
{ {
pki.setRootKey(mKeyset->pki.root_sign_key); pki.setKeyCfg(mKeyCfg);
pki.addCertificates(mCert); pki.addCertificates(mCert);
} }
catch (const fnd::Exception& e) catch (const fnd::Exception& e)

View file

@ -6,6 +6,7 @@
#include <fnd/Vec.h> #include <fnd/Vec.h>
#include <nn/pki/SignedData.h> #include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include "KeyConfiguration.h"
#include "nstool.h" #include "nstool.h"
class PkiCertProcess class PkiCertProcess
@ -17,7 +18,7 @@ public:
void process(); void process();
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -27,7 +28,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;

View file

@ -9,7 +9,7 @@ PkiValidator::PkiValidator()
clearCertificates(); clearCertificates();
} }
void PkiValidator::setRootKey(const fnd::rsa::sRsa4096Key& root_key) void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg)
{ {
// save a copy of the certificate bank // save a copy of the certificate bank
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> old_certs = mCertificateBank; fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> old_certs = mCertificateBank;
@ -18,7 +18,7 @@ void PkiValidator::setRootKey(const fnd::rsa::sRsa4096Key& root_key)
mCertificateBank.clear(); mCertificateBank.clear();
// overwrite the root key // 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 there were certificates before, reimport them (so they are checked against the new root key)
if (old_certs.size() > 0) 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; int sig_validate_res = -1;
// special case if signed by Root // 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 else
{ {

View file

@ -6,13 +6,14 @@
#include <nn/pki/SignedData.h> #include <nn/pki/SignedData.h>
#include <nn/pki/CertificateBody.h> #include <nn/pki/CertificateBody.h>
#include <string> #include <string>
#include "KeyConfiguration.h"
class PkiValidator class PkiValidator
{ {
public: public:
PkiValidator(); PkiValidator();
void setRootKey(const fnd::rsa::sRsa4096Key& root_key); void setKeyCfg(const KeyConfiguration& keycfg);
void addCertificates(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs); void addCertificates(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert); void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert);
void clearCertificates(); void clearCertificates();
@ -22,8 +23,7 @@ public:
private: private:
const std::string kModuleName = "NNPkiValidator"; const std::string kModuleName = "NNPkiValidator";
KeyConfiguration mKeyCfg;
fnd::rsa::sRsa4096Key mRootKey;
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank; fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank;
void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const; void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const;

View file

@ -96,9 +96,9 @@ const std::string UserSettings::getInputPath() const
return mInputPath; return mInputPath;
} }
const sKeyset& UserSettings::getKeyset() const const KeyConfiguration& UserSettings::getKeyCfg() const
{ {
return mKeyset; return mKeyCfg;
} }
FileType UserSettings::getFileType() const FileType UserSettings::getFileType() const
@ -386,8 +386,6 @@ void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCm
void UserSettings::populateKeyset(sCmdArgs& args) void UserSettings::populateKeyset(sCmdArgs& args)
{ {
memset((void*)&mKeyset, 0, sizeof(sKeyset));
if (args.keyset_path.isSet) if (args.keyset_path.isSet)
{ {
mKeyCfg.importHactoolGenericKeyfile(*args.keyset_path); 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) if (args.nca_bodykey.isSet)
{ {
@ -503,7 +486,7 @@ void UserSettings::populateKeyset(sCmdArgs& args)
try try
{ {
pki_validator.setRootKey(mKeyset.pki.root_sign_key); pki_validator.setKeyCfg(mKeyCfg);
pki_validator.addCertificates(mCertChain); pki_validator.addCertificates(mCertChain);
pki_validator.validateSignature(tik.getBody().getIssuer(), tik.getSignature().getSignType(), tik.getSignature().getSignature(), tik_hash); 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; fnd::aes::sAes128Key enc_title_key;
memcpy(enc_title_key.key, tik.getBody().getEncTitleKey(), 16); memcpy(enc_title_key.key, tik.getBody().getEncTitleKey(), 16);
mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, enc_title_key);
fnd::aes::sAes128Key common_key, external_content_key; fnd::aes::sAes128Key common_key, external_content_key;
if (mKeyCfg.getETicketCommonKey(nn::hac::NcaUtils::getMasterKeyRevisionFromKeyGeneration(tik.getBody().getCommonKeyId()), common_key) == true) 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; 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) void UserSettings::populateUserSettings(sCmdArgs& args)
@ -721,7 +699,9 @@ bool UserSettings::determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) c
if (sample.size() < nn::hac::nca::kHeaderSize) if (sample.size() < nn::hac::nca::kHeaderSize)
return false; 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) if (nca_header->st_magic.get() != nn::hac::nca::kNca2StructMagic && nca_header->st_magic.get() != nn::hac::nca::kNca3StructMagic)
return false; return false;

View file

@ -21,7 +21,6 @@ public:
// generic options // generic options
const std::string getInputPath() const; const std::string getInputPath() const;
const KeyConfiguration& getKeyCfg() const; const KeyConfiguration& getKeyCfg() const;
const sKeyset& getKeyset() const;
FileType getFileType() const; FileType getFileType() const;
bool isVerifyFile() const; bool isVerifyFile() const;
CliOutputMode getCliOutputMode() const; CliOutputMode getCliOutputMode() const;
@ -90,7 +89,6 @@ private:
std::string mInputPath; std::string mInputPath;
FileType mFileType; FileType mFileType;
sKeyset mKeyset;
KeyConfiguration mKeyCfg; KeyConfiguration mKeyCfg;
bool mVerifyFile; bool mVerifyFile;
CliOutputMode mOutputMode; CliOutputMode mOutputMode;

View file

@ -8,7 +8,6 @@
XciProcess::XciProcess() : XciProcess::XciProcess() :
mFile(nullptr), mFile(nullptr),
mOwnIFile(false), mOwnIFile(false),
mKeyset(nullptr),
mCliOutputMode(_BIT(OUTPUT_BASIC)), mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false), mVerify(false),
mListFs(false), mListFs(false),
@ -50,9 +49,9 @@ void XciProcess::setInputFile(fnd::IFile* file, bool ownIFile)
mOwnIFile = ownIFile; mOwnIFile = ownIFile;
} }
void XciProcess::setKeyset(const sKeyset* keyset) void XciProcess::setKeyCfg(const KeyConfiguration& keycfg)
{ {
mKeyset = keyset; mKeyCfg = keycfg;
} }
void XciProcess::setCliOutputMode(CliOutputMode type) void XciProcess::setCliOutputMode(CliOutputMode type)
@ -89,7 +88,10 @@ void XciProcess::importHeader()
// allocate memory for and decrypt sXciHeader // allocate memory for and decrypt sXciHeader
scratch.alloc(sizeof(nn::hac::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 // deserialise header
mHdr.fromBytes(scratch.data(), scratch.size()); 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() void XciProcess::validateXciSignature()
{ {
fnd::rsa::sRsa2048Key header_sign_key;
fnd::sha::sSha256Hash calc_hash; fnd::sha::sSha256Hash calc_hash;
fnd::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nn::hac::sXciHeader), calc_hash.bytes); 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; std::cout << "[WARNING] XCI Header Signature: FAIL" << std::endl;
} }

View file

@ -4,11 +4,10 @@
#include <fnd/IFile.h> #include <fnd/IFile.h>
#include <fnd/List.h> #include <fnd/List.h>
#include <nn/hac/XciHeader.h> #include <nn/hac/XciHeader.h>
#include "KeyConfiguration.h"
#include "nstool.h"
#include "PfsProcess.h" #include "PfsProcess.h"
#include "nstool.h"
class XciProcess class XciProcess
{ {
@ -20,7 +19,7 @@ public:
// generic // generic
void setInputFile(fnd::IFile* file, bool ownIFile); void setInputFile(fnd::IFile* file, bool ownIFile);
void setKeyset(const sKeyset* keyset); void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type); void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify); void setVerifyMode(bool verify);
@ -34,7 +33,7 @@ private:
fnd::IFile* mFile; fnd::IFile* mFile;
bool mOwnIFile; bool mOwnIFile;
const sKeyset* mKeyset; KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode; CliOutputMode mCliOutputMode;
bool mVerify; bool mVerify;

View file

@ -41,7 +41,7 @@ int main(int argc, char** argv)
xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.setCliOutputMode(user_set.getCliOutputMode());
xci.setVerifyMode(user_set.isVerifyFile()); xci.setVerifyMode(user_set.isVerifyFile());
@ -90,7 +90,7 @@ int main(int argc, char** argv)
NcaProcess nca; NcaProcess nca;
nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.setCliOutputMode(user_set.getCliOutputMode());
nca.setVerifyMode(user_set.isVerifyFile()); nca.setVerifyMode(user_set.isVerifyFile());
@ -112,7 +112,7 @@ int main(int argc, char** argv)
NpdmProcess npdm; NpdmProcess npdm;
npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.setCliOutputMode(user_set.getCliOutputMode());
npdm.setVerifyMode(user_set.isVerifyFile()); npdm.setVerifyMode(user_set.isVerifyFile());
@ -180,7 +180,7 @@ int main(int argc, char** argv)
PkiCertProcess cert; PkiCertProcess cert;
cert.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.setCliOutputMode(user_set.getCliOutputMode());
cert.setVerifyMode(user_set.isVerifyFile()); cert.setVerifyMode(user_set.isVerifyFile());
@ -191,7 +191,7 @@ int main(int argc, char** argv)
EsTikProcess tik; EsTikProcess tik;
tik.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); 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.setCertificateChain(user_set.getCertificateChain());
tik.setCliOutputMode(user_set.getCliOutputMode()); tik.setCliOutputMode(user_set.getCliOutputMode());
tik.setVerifyMode(user_set.isVerifyFile()); tik.setVerifyMode(user_set.isVerifyFile());

View file

@ -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 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}; 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;
};