From 5275fd2789459c1c633b2436ddb0d352018650d7 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 10 Apr 2019 10:21:44 -0400 Subject: key_manager: Add equality operator for RSAKeyPair --- src/core/crypto/key_manager.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 22f268c65..589b25696 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -43,6 +43,13 @@ struct RSAKeyPair { std::array exponent; }; +template +bool operator==(const RSAKeyPair& lhs, + const RSAKeyPair& rhs) { + return std::tie(lhs.encryption_key, lhs.decryption_key, lhs.modulus, lhs.exponent) == + std::tie(rhs.encryption_key, rhs.decryption_key, rhs.modulus, rhs.exponent); +} + enum class KeyCategory : u8 { Standard, Title, -- cgit v1.2.3 From e35fac205406c6d485bd755c4260a69f312eeaf6 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 10 Apr 2019 10:22:04 -0400 Subject: key_manager: Add accessors/helpers for ticket management --- src/core/crypto/key_manager.cpp | 100 ++++++++++++++++++++++++++++++++++------ src/core/crypto/key_manager.h | 14 ++++++ 2 files changed, 100 insertions(+), 14 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 6dd633363..ef139902d 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -135,6 +135,28 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { } } +RSAKeyPair<2048> KeyManager::GetETicketRSAKey() { + if (eticket_extended_kek == std::array{} || !HasKey(S128KeyType::ETicketRSAKek)) + return {}; + + const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek); + + std::vector extended_iv(0x10); + std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); + std::array extended_dec{}; + AESCipher rsa_1(eticket_final, Mode::CTR); + rsa_1.SetIV(extended_iv); + rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, + extended_dec.data(), Op::Decrypt); + + RSAKeyPair<2048> rsa_key{}; + std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); + std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); + std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); + + return rsa_key; +} + Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) { AESCipher mac_cipher(keyblob_key, Mode::ECB); Key128 mac_key{}; @@ -450,6 +472,8 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); + } else if (out[0].compare(0, 20, "eticket_extended_kek") == 0) { + eticket_extended_kek = Common::HexStringToArray<576>(out[1]); } else { for (const auto& kv : KEYS_VARIABLE_LENGTH) { if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) @@ -862,20 +886,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { // Titlekeys data.DecryptProdInfo(GetBISKey(0)); - const auto eticket_extended_kek = data.GetETicketExtendedKek(); + eticket_extended_kek = data.GetETicketExtendedKek(); + WriteKeyToFile(KeyCategory::Console, "eticket_extended_kek", eticket_extended_kek); + PopulateTickets(); +} - std::vector extended_iv(0x10); - std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); - std::array extended_dec{}; - AESCipher rsa_1(eticket_final, Mode::CTR); - rsa_1.SetIV(extended_iv); - rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, - extended_dec.data(), Op::Decrypt); +void KeyManager::PopulateTickets() { + const auto rsa_key = GetETicketRSAKey(); - RSAKeyPair<2048> rsa_key{}; - std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); - std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); - std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); + if (rsa_key == RSAKeyPair<2048>{}) + return; + + if (!common_tickets.empty() && !personal_tickets.empty()) + return; const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/80000000000000e1", @@ -886,15 +909,24 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { const auto blob2 = GetTicketblob(save2); auto res = GetTicketblob(save1); + const auto idx = res.size(); res.insert(res.end(), blob2.begin(), blob2.end()); - for (const auto& raw : res) { - const auto pair = ParseTicket(raw, rsa_key); + for (std::size_t i = 0; i < res.size(); ++i) { + const auto common = i < idx; + const auto pair = ParseTicket(res[i], rsa_key); if (!pair) continue; const auto& [rid, key] = *pair; u128 rights_id; std::memcpy(rights_id.data(), rid.data(), rid.size()); + + if (common) { + common_tickets[rights_id] = res[i]; + } else { + personal_tickets[rights_id] = res[i]; + } + SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); } } @@ -997,6 +1029,46 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) { DeriveBase(); } +const std::map& KeyManager::GetCommonTickets() const { + return common_tickets; +} + +const std::map& KeyManager::GetPersonalizedTickets() const { + return personal_tickets; +} + +bool KeyManager::AddTicketCommon(TicketRaw raw) { + const auto rsa_key = GetETicketRSAKey(); + if (rsa_key == RSAKeyPair<2048>{}) + return false; + + const auto pair = ParseTicket(raw, rsa_key); + if (!pair) + return false; + const auto& [rid, key] = *pair; + u128 rights_id; + std::memcpy(rights_id.data(), rid.data(), rid.size()); + common_tickets[rights_id] = raw; + SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); + return true; +} + +bool KeyManager::AddTicketPersonalized(TicketRaw raw) { + const auto rsa_key = GetETicketRSAKey(); + if (rsa_key == RSAKeyPair<2048>{}) + return false; + + const auto pair = ParseTicket(raw, rsa_key); + if (!pair) + return false; + const auto& [rid, key] = *pair; + u128 rights_id; + std::memcpy(rights_id.data(), rid.data(), rid.size()); + common_tickets[rights_id] = raw; + SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); + return true; +} + const boost::container::flat_map> KeyManager::s128_file_id = { {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, {"eticket_rsa_kek_source", diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 589b25696..8a67b172d 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -165,15 +165,27 @@ public: bool BaseDeriveNecessary() const; void DeriveBase(); void DeriveETicket(PartitionDataManager& data); + void PopulateTickets(); void PopulateFromPartitionData(PartitionDataManager& data); + const std::map& GetCommonTickets() const; + const std::map& GetPersonalizedTickets() const; + + bool AddTicketCommon(TicketRaw raw); + bool AddTicketPersonalized(TicketRaw raw); + private: std::map, Key128> s128_keys; std::map, Key256> s256_keys; + // Map from rights ID to ticket + std::map common_tickets; + std::map personal_tickets; + std::array, 0x20> encrypted_keyblobs{}; std::array, 0x20> keyblobs{}; + std::array eticket_extended_kek{}; bool dev_mode; void LoadFromFile(const std::string& filename, bool is_title_keys); @@ -185,6 +197,8 @@ private: void DeriveGeneralPurposeKeys(std::size_t crypto_revision); + RSAKeyPair<2048> GetETicketRSAKey(); + void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); -- cgit v1.2.3 From f8718ae779bbdc6a3f514b5ce141515baa97e14f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Tue, 16 Apr 2019 09:12:04 -0400 Subject: key_manager: Add structure for Ticket parsing --- src/core/crypto/key_manager.cpp | 124 +++++++++++++++++++++++++++++++++------- src/core/crypto/key_manager.h | 96 ++++++++++++++++++++++++++----- 2 files changed, 185 insertions(+), 35 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index ef139902d..558790a49 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -37,6 +37,7 @@ namespace Core::Crypto { constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; +constexpr u64 FULL_TICKET_SIZE = 0x400; using namespace Common; @@ -55,6 +56,78 @@ const std::map, std::string> KEYS_VARIABLE_LENGTH{ {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, }; +u64 GetSignatureTypeDataSize(SignatureType type) { + switch (type) { + case SignatureType::RSA_4096_SHA1: + case SignatureType::RSA_4096_SHA256: + return 0x200; + case SignatureType::RSA_2048_SHA1: + case SignatureType::RSA_2048_SHA256: + return 0x100; + case SignatureType::ECDSA_SHA1: + case SignatureType::ECDSA_SHA256: + return 0x3C; + } + UNREACHABLE(); +} + +u64 GetSignatureTypePaddingSize(SignatureType type) { + switch (type) { + case SignatureType::RSA_4096_SHA1: + case SignatureType::RSA_4096_SHA256: + case SignatureType::RSA_2048_SHA1: + case SignatureType::RSA_2048_SHA256: + return 0x3C; + case SignatureType::ECDSA_SHA1: + case SignatureType::ECDSA_SHA256: + return 0x40; + } + UNREACHABLE(); +} + +TicketData& Ticket::GetData() { + switch (sig_type) { + case SignatureType::RSA_4096_SHA1: + case SignatureType::RSA_4096_SHA256: + return rsa_4096.data; + case SignatureType::RSA_2048_SHA1: + case SignatureType::RSA_2048_SHA256: + return rsa_2048.data; + case SignatureType::ECDSA_SHA1: + case SignatureType::ECDSA_SHA256: + return ecdsa.data; + } + UNREACHABLE(); +} + +const TicketData& Ticket::GetData() const { + switch (sig_type) { + case SignatureType::RSA_4096_SHA1: + case SignatureType::RSA_4096_SHA256: + return rsa_4096.data; + case SignatureType::RSA_2048_SHA1: + case SignatureType::RSA_2048_SHA256: + return rsa_2048.data; + case SignatureType::ECDSA_SHA1: + case SignatureType::ECDSA_SHA256: + return ecdsa.data; + } + UNREACHABLE(); +} + +u64 Ticket::GetSize() const { + return sizeof(SignatureType) + GetSignatureTypeDataSize(sig_type) + + GetSignatureTypePaddingSize(sig_type) + sizeof(TicketData); +} + +Ticket Ticket::SynthesizeCommon(Key128 title_key, std::array rights_id) { + Ticket out{}; + out.sig_type = SignatureType::RSA_2048_SHA256; + out.GetData().rights_id = rights_id; + out.GetData().title_key_common = title_key; + return out; +} + Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) { Key128 out{}; @@ -259,7 +332,7 @@ Loader::ResultStatus DeriveSDKeys(std::array& sd_keys, KeyManager& ke return Loader::ResultStatus::Success; } -std::vector GetTicketblob(const FileUtil::IOFile& ticket_save) { +std::vector GetTicketblob(const FileUtil::IOFile& ticket_save) { if (!ticket_save.IsOpen()) return {}; @@ -268,14 +341,14 @@ std::vector GetTicketblob(const FileUtil::IOFile& ticket_save) { return {}; } - std::vector out; + std::vector out; for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && buffer[offset + 3] == 0x0) { out.emplace_back(); auto& next = out.back(); - std::memcpy(&next, buffer.data() + offset, sizeof(TicketRaw)); - offset += next.size(); + std::memcpy(&next, buffer.data() + offset, sizeof(Ticket)); + offset += FULL_TICKET_SIZE; } } @@ -327,29 +400,25 @@ static std::optional FindTicketOffset(const std::array& data) { return offset; } -std::optional> ParseTicket(const TicketRaw& ticket, +std::optional> ParseTicket(const Ticket& ticket, const RSAKeyPair<2048>& key) { - u32 cert_authority; - std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); - if (cert_authority == 0) + const auto issuer = ticket.GetData().issuer; + if (issuer == std::array{}) return {}; - if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { + if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority {:08X}.", - cert_authority); + issuer); } - Key128 rights_id; - std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); + Key128 rights_id = ticket.GetData().rights_id; if (rights_id == Key128{}) return {}; - Key128 key_temp{}; - - if (!std::any_of(ticket.begin() + 0x190, ticket.begin() + 0x280, [](u8 b) { return b != 0; })) { - std::memcpy(key_temp.data(), ticket.data() + 0x180, key_temp.size()); - return std::make_pair(rights_id, key_temp); + if (!std::any_of(ticket.GetData().title_key_common_pad.begin(), + ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) { + return std::make_pair(rights_id, ticket.GetData().title_key_common); } mbedtls_mpi D; // RSA Private Exponent @@ -364,7 +433,7 @@ std::optional> ParseTicket(const TicketRaw& ticket, mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size()); mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size()); - mbedtls_mpi_read_binary(&S, ticket.data() + 0x180, 0x100); + mbedtls_mpi_read_binary(&S, ticket.GetData().title_key_block.data(), 0x100); mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr); @@ -388,6 +457,7 @@ std::optional> ParseTicket(const TicketRaw& ticket, return {}; ASSERT(*offset > 0); + Key128 key_temp{}; std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size()); return std::make_pair(rights_id, key_temp); @@ -411,6 +481,16 @@ KeyManager::KeyManager() { AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true); AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "console.keys", false); AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "console.keys_autogenerated", false); + + for (const auto& key : s128_keys) { + if (key.first.type == S128KeyType::Titlekey) { + u128 rights_id{key.first.field1, key.first.field2}; + Key128 rights_id_2; + std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); + const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); + common_tickets.insert_or_assign(rights_id, ticket); + } + } } static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { @@ -1029,15 +1109,15 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) { DeriveBase(); } -const std::map& KeyManager::GetCommonTickets() const { +const std::map& KeyManager::GetCommonTickets() const { return common_tickets; } -const std::map& KeyManager::GetPersonalizedTickets() const { +const std::map& KeyManager::GetPersonalizedTickets() const { return personal_tickets; } -bool KeyManager::AddTicketCommon(TicketRaw raw) { +bool KeyManager::AddTicketCommon(Ticket raw) { const auto rsa_key = GetETicketRSAKey(); if (rsa_key == RSAKeyPair<2048>{}) return false; @@ -1053,7 +1133,7 @@ bool KeyManager::AddTicketCommon(TicketRaw raw) { return true; } -bool KeyManager::AddTicketPersonalized(TicketRaw raw) { +bool KeyManager::AddTicketPersonalized(Ticket raw) { const auto rsa_key = GetETicketRSAKey(); if (rsa_key == RSAKeyPair<2048>{}) return false; diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 8a67b172d..ff6bd08e1 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -11,6 +11,7 @@ #include #include +#include "common/common_funcs.h" #include "common/common_types.h" #include "core/crypto/partition_data_manager.h" #include "core/file_sys/vfs_types.h" @@ -30,7 +31,76 @@ constexpr u64 TICKET_FILE_TITLEKEY_OFFSET = 0x180; using Key128 = std::array; using Key256 = std::array; using SHA256Hash = std::array; -using TicketRaw = std::array; + +enum class SignatureType { + RSA_4096_SHA1 = 0x10000, + RSA_2048_SHA1 = 0x10001, + ECDSA_SHA1 = 0x10002, + RSA_4096_SHA256 = 0x10003, + RSA_2048_SHA256 = 0x10004, + ECDSA_SHA256 = 0x10005, +}; + +u64 GetSignatureTypeDataSize(SignatureType type); +u64 GetSignatureTypePaddingSize(SignatureType type); + +enum class TitleKeyType : u8 { + Common = 0, + Personalized = 1, +}; + +struct TicketData { + std::array issuer; + union { + std::array title_key_block; + + struct { + Key128 title_key_common; + std::array title_key_common_pad; + }; + }; + + INSERT_PADDING_BYTES(0x1); + TitleKeyType type; + INSERT_PADDING_BYTES(0x3); + u8 revision; + INSERT_PADDING_BYTES(0xA); + u64 ticket_id; + u64 device_id; + std::array rights_id; + u32 account_id; + INSERT_PADDING_BYTES(0x14C); +}; +static_assert(sizeof(TicketData) == 0x2C0, "TicketData has incorrect size."); + +struct Ticket { + SignatureType sig_type; + union { + struct { + std::array sig_data; + INSERT_PADDING_BYTES(0x3C); + TicketData data; + } rsa_4096; + + struct { + std::array sig_data; + INSERT_PADDING_BYTES(0x3C); + TicketData data; + } rsa_2048; + + struct { + std::array sig_data; + INSERT_PADDING_BYTES(0x40); + TicketData data; + } ecdsa; + }; + + TicketData& GetData(); + const TicketData& GetData() const; + u64 GetSize() const; + + static Ticket SynthesizeCommon(Key128 title_key, std::array rights_id); +}; static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); static_assert(sizeof(Key256) == 32, "Key256 must be 256 bytes big."); @@ -158,8 +228,8 @@ public: static bool KeyFileExists(bool title); - // Call before using the sd seed to attempt to derive it if it dosen't exist. Needs system save - // 8*43 and the private file to exist. + // Call before using the sd seed to attempt to derive it if it dosen't exist. Needs system + // save 8*43 and the private file to exist. void DeriveSDSeedLazy(); bool BaseDeriveNecessary() const; @@ -169,19 +239,19 @@ public: void PopulateFromPartitionData(PartitionDataManager& data); - const std::map& GetCommonTickets() const; - const std::map& GetPersonalizedTickets() const; + const std::map& GetCommonTickets() const; + const std::map& GetPersonalizedTickets() const; - bool AddTicketCommon(TicketRaw raw); - bool AddTicketPersonalized(TicketRaw raw); + bool AddTicketCommon(Ticket raw); + bool AddTicketPersonalized(Ticket raw); private: std::map, Key128> s128_keys; std::map, Key256> s256_keys; // Map from rights ID to ticket - std::map common_tickets; - std::map personal_tickets; + std::map common_tickets; + std::map personal_tickets; std::array, 0x20> encrypted_keyblobs{}; std::array, 0x20> keyblobs{}; @@ -216,11 +286,11 @@ std::array DecryptKeyblob(const std::array& encrypted_keyblo std::optional DeriveSDSeed(); Loader::ResultStatus DeriveSDKeys(std::array& sd_keys, KeyManager& keys); -std::vector GetTicketblob(const FileUtil::IOFile& ticket_save); +std::vector GetTicketblob(const FileUtil::IOFile& ticket_save); -// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority (offset -// 0x140-0x144 is zero) -std::optional> ParseTicket(const TicketRaw& ticket, +// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority +// (offset 0x140-0x144 is zero) +std::optional> ParseTicket(const Ticket& ticket, const RSAKeyPair<2048>& eticket_extended_key); } // namespace Core::Crypto -- cgit v1.2.3 From d9ef20e5a53166fe3ecdca5ed225232eb7ad2f64 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 17 Apr 2019 11:29:21 -0400 Subject: es: Populate/synthesize tickets on construction --- src/core/crypto/key_manager.cpp | 26 +++++++++++++------------- src/core/crypto/key_manager.h | 1 + 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 558790a49..3c51e3dc2 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -406,9 +406,7 @@ std::optional> ParseTicket(const Ticket& ticket, if (issuer == std::array{}) return {}; if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { - LOG_INFO(Crypto, - "Attempting to parse ticket with non-standard certificate authority {:08X}.", - issuer); + LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); } Key128 rights_id = ticket.GetData().rights_id; @@ -481,16 +479,6 @@ KeyManager::KeyManager() { AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true); AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "console.keys", false); AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "console.keys_autogenerated", false); - - for (const auto& key : s128_keys) { - if (key.first.type == S128KeyType::Titlekey) { - u128 rights_id{key.first.field1, key.first.field2}; - Key128 rights_id_2; - std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); - const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); - common_tickets.insert_or_assign(rights_id, ticket); - } - } } static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { @@ -1011,6 +999,18 @@ void KeyManager::PopulateTickets() { } } +void KeyManager::SynthesizeTickets() { + for (const auto& key : s128_keys) { + if (key.first.type == S128KeyType::Titlekey) { + u128 rights_id{key.first.field1, key.first.field2}; + Key128 rights_id_2; + std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); + const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); + common_tickets.insert_or_assign(rights_id, ticket); + } + } +} + void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) { if (key == Key128{}) return; diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index ff6bd08e1..d4e89d35c 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -236,6 +236,7 @@ public: void DeriveBase(); void DeriveETicket(PartitionDataManager& data); void PopulateTickets(); + void SynthesizeTickets(); void PopulateFromPartitionData(PartitionDataManager& data); -- cgit v1.2.3 From 50d541407507edc2f29ad6a46f3f17724e52f7f7 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 26 May 2019 13:01:42 -0400 Subject: key_manager: Convert Ticket union to std::variant --- src/core/crypto/key_manager.cpp | 91 +++++++++++++++++++++++++---------------- src/core/crypto/key_manager.h | 50 +++++++++++++--------- 2 files changed, 86 insertions(+), 55 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 3c51e3dc2..46aceec3d 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -56,6 +56,13 @@ const std::map, std::string> KEYS_VARIABLE_LENGTH{ {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, }; +namespace { +template +bool IsAllZeroArray(const std::array& array) { + return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; }); +} +} // namespace + u64 GetSignatureTypeDataSize(SignatureType type) { switch (type) { case SignatureType::RSA_4096_SHA1: @@ -85,47 +92,61 @@ u64 GetSignatureTypePaddingSize(SignatureType type) { UNREACHABLE(); } +SignatureType Ticket::GetSignatureType() const { + if (auto ticket = std::get_if(&data)) { + return ticket->sig_type; + } + if (auto ticket = std::get_if(&data)) { + return ticket->sig_type; + } + if (auto ticket = std::get_if(&data)) { + return ticket->sig_type; + } + + UNREACHABLE(); +} + TicketData& Ticket::GetData() { - switch (sig_type) { - case SignatureType::RSA_4096_SHA1: - case SignatureType::RSA_4096_SHA256: - return rsa_4096.data; - case SignatureType::RSA_2048_SHA1: - case SignatureType::RSA_2048_SHA256: - return rsa_2048.data; - case SignatureType::ECDSA_SHA1: - case SignatureType::ECDSA_SHA256: - return ecdsa.data; + if (auto ticket = std::get_if(&data)) { + return ticket->data; } + if (auto ticket = std::get_if(&data)) { + return ticket->data; + } + if (auto ticket = std::get_if(&data)) { + return ticket->data; + } + UNREACHABLE(); } const TicketData& Ticket::GetData() const { - switch (sig_type) { - case SignatureType::RSA_4096_SHA1: - case SignatureType::RSA_4096_SHA256: - return rsa_4096.data; - case SignatureType::RSA_2048_SHA1: - case SignatureType::RSA_2048_SHA256: - return rsa_2048.data; - case SignatureType::ECDSA_SHA1: - case SignatureType::ECDSA_SHA256: - return ecdsa.data; + if (auto ticket = std::get_if(&data)) { + return ticket->data; + } + if (auto ticket = std::get_if(&data)) { + return ticket->data; } + if (auto ticket = std::get_if(&data)) { + return ticket->data; + } + UNREACHABLE(); } u64 Ticket::GetSize() const { + const auto sig_type = GetSignatureType(); + return sizeof(SignatureType) + GetSignatureTypeDataSize(sig_type) + GetSignatureTypePaddingSize(sig_type) + sizeof(TicketData); } -Ticket Ticket::SynthesizeCommon(Key128 title_key, std::array rights_id) { - Ticket out{}; +Ticket Ticket::SynthesizeCommon(Key128 title_key, const std::array& rights_id) { + RSA2048Ticket out{}; out.sig_type = SignatureType::RSA_2048_SHA256; - out.GetData().rights_id = rights_id; - out.GetData().title_key_common = title_key; - return out; + out.data.rights_id = rights_id; + out.data.title_key_common = title_key; + return Ticket{out}; } Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) { @@ -208,14 +229,13 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { } } -RSAKeyPair<2048> KeyManager::GetETicketRSAKey() { - if (eticket_extended_kek == std::array{} || !HasKey(S128KeyType::ETicketRSAKek)) +RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const { + if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) return {}; const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek); - std::vector extended_iv(0x10); - std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); + std::vector extended_iv(eticket_extended_kek.begin(), eticket_extended_kek.begin() + 0x10); std::array extended_dec{}; AESCipher rsa_1(eticket_final, Mode::CTR); rsa_1.SetIV(extended_iv); @@ -1001,13 +1021,14 @@ void KeyManager::PopulateTickets() { void KeyManager::SynthesizeTickets() { for (const auto& key : s128_keys) { - if (key.first.type == S128KeyType::Titlekey) { - u128 rights_id{key.first.field1, key.first.field2}; - Key128 rights_id_2; - std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); - const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); - common_tickets.insert_or_assign(rights_id, ticket); + if (key.first.type != S128KeyType::Titlekey) { + continue; } + u128 rights_id{key.first.field1, key.first.field2}; + Key128 rights_id_2; + std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); + const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); + common_tickets.insert_or_assign(rights_id, ticket); } } diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index d4e89d35c..7265c4171 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include "common/common_funcs.h" @@ -73,33 +74,36 @@ struct TicketData { }; static_assert(sizeof(TicketData) == 0x2C0, "TicketData has incorrect size."); -struct Ticket { +struct RSA4096Ticket { SignatureType sig_type; - union { - struct { - std::array sig_data; - INSERT_PADDING_BYTES(0x3C); - TicketData data; - } rsa_4096; + std::array sig_data; + INSERT_PADDING_BYTES(0x3C); + TicketData data; +}; - struct { - std::array sig_data; - INSERT_PADDING_BYTES(0x3C); - TicketData data; - } rsa_2048; +struct RSA2048Ticket { + SignatureType sig_type; + std::array sig_data; + INSERT_PADDING_BYTES(0x3C); + TicketData data; +}; - struct { - std::array sig_data; - INSERT_PADDING_BYTES(0x40); - TicketData data; - } ecdsa; - }; +struct ECDSATicket { + SignatureType sig_type; + std::array sig_data; + INSERT_PADDING_BYTES(0x40); + TicketData data; +}; + +struct Ticket { + std::variant data; + SignatureType GetSignatureType() const; TicketData& GetData(); const TicketData& GetData() const; u64 GetSize() const; - static Ticket SynthesizeCommon(Key128 title_key, std::array rights_id); + static Ticket SynthesizeCommon(Key128 title_key, const std::array& rights_id); }; static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); @@ -120,6 +124,12 @@ bool operator==(const RSAKeyPair& lhs, std::tie(rhs.encryption_key, rhs.decryption_key, rhs.modulus, rhs.exponent); } +template +bool operator!=(const RSAKeyPair& lhs, + const RSAKeyPair& rhs) { + return !(lhs == rhs); +} + enum class KeyCategory : u8 { Standard, Title, @@ -268,7 +278,7 @@ private: void DeriveGeneralPurposeKeys(std::size_t crypto_revision); - RSAKeyPair<2048> GetETicketRSAKey(); + RSAKeyPair<2048> GetETicketRSAKey() const; void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); -- cgit v1.2.3