mirror of
https://github.com/jakcron/nstool
synced 2024-11-15 02:06:40 +00:00
Merge pull request #47 from jakcron/nstool-keyoutput
Implement NSTool KeyCfg Output on --showkeys
This commit is contained in:
commit
7831f5b291
7 changed files with 197 additions and 22 deletions
|
@ -75,8 +75,8 @@ private:
|
|||
const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" };
|
||||
const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" };
|
||||
const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" };
|
||||
const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_body_keak", "key_area_key", "nca_body_keak" };
|
||||
const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_body_keakhw", "key_area_hw_key", "nca_body_keakhw" };
|
||||
const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_key_area_key", "key_area_key", "nca_body_keak" };
|
||||
const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_key_area_key_hw", "key_area_hw_key", "nca_key_area_key_hw" };
|
||||
const std::string kKekGenBase[kNameVariantNum] = { "aes_kek_generation", "aes_kek_generation", "aes_kek_generation" };
|
||||
const std::string kKeyGenBase[kNameVariantNum] = { "aes_key_generation", "aes_key_generation", "aes_key_generation" };
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ void NcaProcess::generateNcaBodyEncryptionKeys()
|
|||
if (mContentKey.aes_ctr.isSet)
|
||||
{
|
||||
std::cout << "[NCA Content Key]" << std::endl;
|
||||
std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, "") << std::endl;
|
||||
std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,24 +421,24 @@ void NcaProcess::displayHeader()
|
|||
if (mContentKey.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
|
||||
{
|
||||
std::cout << " Key Area:" << std::endl;
|
||||
std::cout << " <--------------------------------------------------------------------------->" << std::endl;
|
||||
std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl;
|
||||
std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl;
|
||||
std::cout << " |-----|----------------------------------|----------------------------------|" << std::endl;
|
||||
std::cout << " |-----|-------------------------------------------------|-------------------------------------------------|" << std::endl;
|
||||
for (size_t i = 0; i < mContentKey.kak_list.size(); i++)
|
||||
{
|
||||
std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mContentKey.kak_list[i].index << " | ";
|
||||
|
||||
std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].enc.key, 16, false, "") << " | ";
|
||||
std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].enc.key, 16, true, ":") << " | ";
|
||||
|
||||
|
||||
if (mContentKey.kak_list[i].decrypted)
|
||||
std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].dec.key, 16, false, "");
|
||||
std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].dec.key, 16, true, ":");
|
||||
else
|
||||
std::cout << "<unable to decrypt> ";
|
||||
|
||||
std::cout << " |" << std::endl;
|
||||
}
|
||||
std::cout << " <--------------------------------------------------------------------------->" << std::endl;
|
||||
std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl;
|
||||
}
|
||||
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||
|
@ -459,7 +459,8 @@ void NcaProcess::displayHeader()
|
|||
{
|
||||
fnd::aes::sAesIvCtr ctr;
|
||||
fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
|
||||
std::cout << " AES-CTR: " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, "") << std::endl;
|
||||
std::cout << " AesCtr Counter:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, ":") << std::endl;
|
||||
}
|
||||
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
||||
{
|
||||
|
@ -479,14 +480,18 @@ void NcaProcess::displayHeader()
|
|||
std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl;
|
||||
for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++)
|
||||
{
|
||||
std::cout << " Master Hash " << std::dec << j << ": " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl;
|
||||
std::cout << " Master Hash " << std::dec << j << ":" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, 0x10, true, ":") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes+0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
||||
{
|
||||
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
||||
std::cout << " HierarchicalSha256 Header:" << std::endl;
|
||||
std::cout << " Master Hash: " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash), true, "") << std::endl;
|
||||
std::cout << " Master Hash:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, 0x10, true, ":") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes+0x10, 0x10, true, ":") << std::endl;
|
||||
std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl;
|
||||
std::cout << " Hash Layer:" << std::endl;
|
||||
std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <fnd/io.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
|
@ -38,6 +39,8 @@ void UserSettings::parseCmdArgs(const std::vector<std::string>& arg_list)
|
|||
populateCmdArgs(arg_list, args);
|
||||
populateKeyset(args);
|
||||
populateUserSettings(args);
|
||||
if (_HAS_BIT(mOutputMode, OUTPUT_KEY_DATA))
|
||||
dumpKeyConfig();
|
||||
}
|
||||
|
||||
void UserSettings::showHelp()
|
||||
|
@ -862,3 +865,164 @@ void UserSettings::getSwitchPath(std::string& path) const
|
|||
fnd::io::appendToPath(path, home);
|
||||
fnd::io::appendToPath(path, kHomeSwitchDirStr);
|
||||
}
|
||||
|
||||
void UserSettings::dumpKeyConfig() const
|
||||
{
|
||||
fnd::aes::sAes128Key aes_key;
|
||||
fnd::aes::sAesXts128Key aesxts_key;
|
||||
fnd::rsa::sRsa2048Key rsa2048_key;
|
||||
fnd::rsa::sRsa4096Key rsa4096_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"};
|
||||
|
||||
|
||||
std::cout << "[KeyConfiguration]" << std::endl;
|
||||
std::cout << " NCA Keys:" << std::endl;
|
||||
if (mKeyCfg.getNcaHeader0SignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "Header Signature[0] Key", 2);
|
||||
if (mKeyCfg.getNcaHeaderKey(aesxts_key) == true)
|
||||
dumpAesXtsKey(aesxts_key, "Header Encryption Key", 2);
|
||||
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,0, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKey-Application-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,1, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKey-Ocean-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,2, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKey-System-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,0, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Application-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,1, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Ocean-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,2, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-System-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
std::cout << " XCI Keys:" << std::endl;
|
||||
if (mKeyCfg.getXciHeaderSignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "Header Signature Key", 2);
|
||||
if (mKeyCfg.getXciHeaderKey(aes_key) == true)
|
||||
dumpAesKey(aes_key, "Extended Header Encryption Key", 2);
|
||||
|
||||
|
||||
if (mKeyCfg.getAcidSignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "ACID Signer Key", 1);
|
||||
|
||||
|
||||
std::cout << " Package1 Keys:" << std::endl;
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getPkg1Key(i, aes_key) == true)
|
||||
dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
std::cout << " Package2 Keys:" << std::endl;
|
||||
if (mKeyCfg.getPkg2SignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "Signature Key", 2);
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getPkg2Key(i, aes_key) == true)
|
||||
dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
std::cout << " ETicket Keys:" << std::endl;
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getETicketCommonKey(i, aes_key) == true)
|
||||
dumpAesKey(aes_key, "CommonKey-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
if (mKeyCfg.getPkiRootSignKey("Root", rsa4096_key) == true)
|
||||
dumpRsa4096Key(rsa4096_key, "NNPKI Root Key", 1);
|
||||
}
|
||||
|
||||
void UserSettings::dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Modulus:" << std::endl;
|
||||
for (size_t i = 0; i < 0x10; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Private Exponent:" << std::endl;
|
||||
for (size_t i = 0; i < 0x10; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserSettings::dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Modulus:" << std::endl;
|
||||
for (size_t i = 0; i < 0x20; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Private Exponent:" << std::endl;
|
||||
for (size_t i = 0; i < 0x20; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserSettings::dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
|
||||
void UserSettings::dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key[0], 0x20, true, ":") << std::endl;
|
||||
}
|
|
@ -45,8 +45,6 @@ public:
|
|||
const sOptional<std::string>& getAssetNacpPath() const;
|
||||
const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& getCertificateChain() const;
|
||||
|
||||
void dumpKeys() const;
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "UserSettings";
|
||||
|
||||
|
@ -127,4 +125,10 @@ private:
|
|||
nn::hac::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
|
||||
void getHomePath(std::string& path) const;
|
||||
void getSwitchPath(std::string& path) const;
|
||||
|
||||
void dumpKeyConfig() const;
|
||||
void dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const;
|
||||
void dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const;
|
||||
void dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const;
|
||||
void dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const;
|
||||
};
|
|
@ -123,13 +123,13 @@ void XciProcess::displayHeader()
|
|||
std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl;
|
||||
std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl;
|
||||
std::cout << " Hash:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, "") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, "") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, ":") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
std::cout << " Extended Header AES-IV:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, "") << std::endl;
|
||||
std::cout << " Extended Header AesCbc IV:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, ":") << std::endl;
|
||||
}
|
||||
std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl;
|
||||
std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl;
|
||||
|
@ -162,8 +162,8 @@ void XciProcess::displayHeader()
|
|||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
std::cout << " Hash:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, "") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, "") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, ":") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ void XciProcess::displayHeader()
|
|||
std::cout << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl;
|
||||
#undef _SPLIT_VER
|
||||
std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl;
|
||||
std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, "") << std::endl;
|
||||
std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ struct sOptional
|
|||
bool isSet;
|
||||
T var;
|
||||
inline sOptional() : isSet(false) {}
|
||||
inline sOptional(const T& other) : isSet(true), var(other) {}
|
||||
inline sOptional(const sOptional& other) : isSet(other.isSet), var(other.var) {}
|
||||
inline const T& operator=(const T& other) { isSet = true; var = other; return var; }
|
||||
inline const sOptional<T>& operator=(const sOptional<T>& other)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#define VER_MAJOR 1
|
||||
#define VER_MINOR 0
|
||||
#define VER_PATCH 1
|
||||
#define VER_PATCH 2
|
||||
#define AUTHORS "jakcron"
|
Loading…
Reference in a new issue