mirror of
https://github.com/jakcron/nstool
synced 2024-12-27 15:11:12 +00:00
[nstool] Migrated from sKeyset to KeyConfiguration
This commit is contained in:
parent
67a13b9d34
commit
1fd8f59025
18 changed files with 149 additions and 140 deletions
|
@ -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<nn::pki::SignedData<nn::pki::CertificateBody>>& 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);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#include <nn/es/TicketBody_V2.h>
|
||||
#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<nn::pki::SignedData<nn::pki::CertificateBody>>& 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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <fnd/SimpleFile.h>
|
||||
#include <nn/hac/NcaHeader.h>
|
||||
#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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <nn/hac/NpdmBinary.h>
|
||||
#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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <fnd/Vec.h>
|
||||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#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;
|
||||
|
||||
|
|
|
@ -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<nn::pki::SignedData<nn::pki::CertificateBody>> 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
|
||||
{
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#include <string>
|
||||
#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<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
|
||||
void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert);
|
||||
void clearCertificates();
|
||||
|
@ -22,8 +23,7 @@ public:
|
|||
private:
|
||||
const std::string kModuleName = "NNPkiValidator";
|
||||
|
||||
|
||||
fnd::rsa::sRsa4096Key mRootKey;
|
||||
KeyConfiguration mKeyCfg;
|
||||
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank;
|
||||
|
||||
void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const;
|
||||
|
|
|
@ -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<std::string>& 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<byte_t>& 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
#include <fnd/IFile.h>
|
||||
#include <fnd/List.h>
|
||||
#include <nn/hac/XciHeader.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
const byte_t kDummyRightsIdForUserBodyKey[nn::hac::nca::kRightsIdLen] = {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
|
Loading…
Reference in a new issue