mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-04 16:49:05 +00:00
Add proper support for CIA title keys
1. Support for `ticket.db` 2. Support for `gm9/support/encTitleKeys.bin` 3. Set the title key and common key index when building standard CIA
This commit is contained in:
@@ -4,9 +4,12 @@
|
||||
|
||||
#include <cryptopp/sha.h>
|
||||
#include "common/alignment.h"
|
||||
#include "core/importer.h"
|
||||
#include "core/ncch/cia_builder.h"
|
||||
#include "core/ncch/ticket.h"
|
||||
#include "core/ncch/title_metadata.h"
|
||||
#include "core/title_db.h"
|
||||
#include "core/title_keys_bin.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -43,9 +46,8 @@ private:
|
||||
CIABuilder::CIABuilder() = default;
|
||||
CIABuilder::~CIABuilder() = default;
|
||||
|
||||
bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_,
|
||||
const std::string& certs_db_path, std::size_t total_size_,
|
||||
const Common::ProgressCallback& callback_) {
|
||||
bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_, const Config& config,
|
||||
std::size_t total_size_, const Common::ProgressCallback& callback_) {
|
||||
|
||||
header = {};
|
||||
meta = {};
|
||||
@@ -69,7 +71,7 @@ bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_,
|
||||
// Cert
|
||||
cert_offset = Common::AlignUp(header.header_size, CIA_ALIGNMENT);
|
||||
header.cert_size = CIA_CERT_SIZE;
|
||||
if (!WriteCert(certs_db_path)) {
|
||||
if (!WriteCert(config.certs_db_path)) {
|
||||
LOG_ERROR(Core, "Could not write cert to file {}", destination);
|
||||
file.reset();
|
||||
return false;
|
||||
@@ -77,13 +79,7 @@ bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_,
|
||||
|
||||
// Ticket
|
||||
ticket_offset = Common::AlignUp(cert_offset + header.cert_size, CIA_ALIGNMENT);
|
||||
|
||||
const auto fake_ticket = BuildFakeTicket(tmd.GetTitleID()).GetData();
|
||||
header.tik_size = fake_ticket.size();
|
||||
|
||||
file->Seek(ticket_offset, SEEK_SET);
|
||||
if (file->WriteBytes(fake_ticket.data(), fake_ticket.size()) != fake_ticket.size()) {
|
||||
LOG_ERROR(Core, "Could not write ticket to file {}", destination);
|
||||
if (!WriteTicket(config.ticket_db_path, config.enc_title_keys_bin_path)) {
|
||||
file.reset();
|
||||
return false;
|
||||
}
|
||||
@@ -144,6 +140,42 @@ bool CIABuilder::WriteCert(const std::string& certs_db_path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIABuilder::WriteTicket(const std::string& ticket_db_path,
|
||||
const std::string& enc_title_keys_bin_path) {
|
||||
const auto title_id = tmd.GetTitleID();
|
||||
Ticket ticket = BuildFakeTicket(title_id);
|
||||
|
||||
// Fill in common_key_index and title_key from either ticket.db (installed tickets)
|
||||
// or GM9 support files (encTitleKeys.bin) found on the SD card
|
||||
if (TicketDB ticket_db(ticket_db_path);
|
||||
ticket_db.IsGood() && ticket_db.tickets.count(title_id)) { // ticket.db
|
||||
|
||||
const auto& legit_ticket = ticket_db.tickets.at(title_id);
|
||||
ticket.body.common_key_index = legit_ticket.body.common_key_index;
|
||||
ticket.body.title_key = legit_ticket.body.title_key;
|
||||
|
||||
} else if (TitleKeysBin enc_title_keys(enc_title_keys_bin_path);
|
||||
enc_title_keys.IsGood() && enc_title_keys.entries.count(title_id)) { // support files
|
||||
|
||||
const auto& entry = enc_title_keys.entries.at(title_id);
|
||||
ticket.body.common_key_index = entry.common_key_index;
|
||||
ticket.body.title_key = entry.title_key;
|
||||
} else {
|
||||
LOG_WARNING(Core, "Could not find title key for {:016x}", title_id);
|
||||
}
|
||||
|
||||
const auto ticket_data = ticket.GetData();
|
||||
header.tik_size = ticket_data.size();
|
||||
|
||||
file->Seek(ticket_offset, SEEK_SET);
|
||||
if (file->WriteBytes(ticket_data.data(), ticket_data.size()) != ticket_data.size()) {
|
||||
LOG_ERROR(Core, "Could not write ticket");
|
||||
file.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIABuilder::AddContent(u16 content_id, NCCHContainer& ncch) {
|
||||
file->Seek(written, SEEK_SET); // To enforce alignment
|
||||
file->SetHashEnabled(true);
|
||||
|
||||
@@ -22,6 +22,7 @@ constexpr std::size_t CIA_HEADER_SIZE = 0x2020;
|
||||
constexpr std::size_t CIA_CERT_SIZE = 0xA00;
|
||||
constexpr std::size_t CIA_METADATA_SIZE = 0x3AC0;
|
||||
|
||||
class Config;
|
||||
class HashedFile;
|
||||
|
||||
class CIABuilder {
|
||||
@@ -33,7 +34,7 @@ public:
|
||||
* Initializes the building of the CIA.
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool Init(const std::string& destination, TitleMetadata tmd, const std::string& certs_db_path,
|
||||
bool Init(const std::string& destination, TitleMetadata tmd, const Config& config,
|
||||
std::size_t total_size, const Common::ProgressCallback& callback);
|
||||
|
||||
/**
|
||||
@@ -90,6 +91,7 @@ private:
|
||||
static_assert(sizeof(Metadata) == CIA_METADATA_SIZE, "CIA Metadata structure size is wrong");
|
||||
|
||||
bool WriteCert(const std::string& certs_db_path);
|
||||
bool WriteTicket(const std::string& ticket_db_path, const std::string& enc_title_keys_bin_path);
|
||||
|
||||
Header header{};
|
||||
Metadata meta{};
|
||||
|
||||
@@ -69,6 +69,7 @@ Ticket BuildFakeTicket(u64 title_id) {
|
||||
Ticket ticket{};
|
||||
ticket.signature_type = 0x10004; // RSA_2048 SHA256
|
||||
|
||||
ticket.signature.resize(GetSignatureSize(ticket.signature_type));
|
||||
std::memset(ticket.signature.data(), 0xFF, ticket.signature.size());
|
||||
|
||||
auto& body = ticket.body;
|
||||
@@ -80,18 +81,8 @@ Ticket BuildFakeTicket(u64 title_id) {
|
||||
body.common_key_index = 0x00;
|
||||
body.audit = 0x01;
|
||||
std::memcpy(body.content_index.data(), TicketContentIndex.data(), TicketContentIndex.size());
|
||||
// GodMode9 by default sets all remaining 0x80 bytes to 0xFF, but legit tickets only set 0x20
|
||||
std::memset(body.content_index.data() + TicketContentIndex.size(), 0xFF, 0x20);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
Ticket BuildStandardTicket(u64 title_id, Ticket legit_ticket) {
|
||||
Ticket ticket = BuildFakeTicket(title_id);
|
||||
|
||||
// Put in the title key from the legit ticket
|
||||
ticket.body.title_key.swap(legit_ticket.body.title_key);
|
||||
ticket.body.common_key_index = legit_ticket.body.common_key_index;
|
||||
|
||||
// GodMode9 by default sets all remaining 0x80 bytes to 0xFF
|
||||
std::memset(body.content_index.data() + TicketContentIndex.size(), 0xFF, 0x80);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,5 @@ public:
|
||||
};
|
||||
|
||||
Ticket BuildFakeTicket(u64 title_id);
|
||||
Ticket BuildStandardTicket(u64 title_id, Ticket legit_ticket);
|
||||
|
||||
} // namespace Core
|
||||
|
||||
Reference in New Issue
Block a user