From 6d821de2b9803e2a4993ae4e6b38a4b8126a61fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 26 Jun 2017 23:38:58 +0200 Subject: [PATCH 1/2] IOS: Use a std::array for the title key instead of vector The title key is always 16 bytes, so it doesn't make sense to make it a std::vector. --- Source/Core/Core/IOS/ES/ES.h | 2 +- Source/Core/Core/IOS/ES/Formats.cpp | 4 ++-- Source/Core/Core/IOS/ES/Formats.h | 2 +- Source/Core/DiscIO/NANDContentLoader.cpp | 2 +- Source/Core/DiscIO/VolumeWii.cpp | 5 ++--- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index b53a8780f5..747fa0a942 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -80,7 +80,7 @@ public: bool valid = false; IOS::ES::TMDReader tmd; - std::vector title_key; + std::array title_key; std::map contents; }; diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 2a303b5d7f..04210090f9 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -380,7 +380,7 @@ u64 TicketReader::GetTitleId() const return Common::swap64(m_bytes.data() + offsetof(Ticket, title_id)); } -std::vector TicketReader::GetTitleKey() const +std::array TicketReader::GetTitleKey() const { u8 iv[16] = {}; std::copy_n(&m_bytes[offsetof(Ticket, title_id)], sizeof(Ticket::title_id), iv); @@ -398,7 +398,7 @@ std::vector TicketReader::GetTitleKey() const const HLE::IOSC::ConsoleType console_type = is_rvt ? HLE::IOSC::ConsoleType::RVT : HLE::IOSC::ConsoleType::Retail; - std::vector key(16); + std::array key; HLE::IOSC iosc(console_type); iosc.Decrypt(common_key_handle, iv, &m_bytes[offsetof(Ticket, title_key)], 16, key.data(), HLE::PID_ES); diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index dd1352b367..ac710fe660 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -222,7 +222,7 @@ public: u32 GetDeviceId() const; u64 GetTitleId() const; - std::vector GetTitleKey() const; + std::array GetTitleKey() const; // Deletes a ticket with the given ticket ID from the internal buffer. void DeleteTicket(u64 ticket_id); diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index fe5d77d15e..0178c3c14e 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -186,7 +186,7 @@ void NANDContentLoader::InitializeContentEntries(const std::vector& data_app m_Content.resize(contents.size()); u32 data_app_offset = 0; - const std::vector title_key = m_ticket.GetTitleKey(); + const std::array title_key = m_ticket.GetTitleKey(); IOS::ES::SharedContentMap shared_content{m_root}; for (size_t i = 0; i < contents.size(); ++i) diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp index b8215527a6..8ccca04409 100644 --- a/Source/Core/DiscIO/VolumeWii.cpp +++ b/Source/Core/DiscIO/VolumeWii.cpp @@ -5,6 +5,7 @@ #include "DiscIO/VolumeWii.h" #include +#include #include #include #include @@ -97,9 +98,7 @@ VolumeWii::VolumeWii(std::unique_ptr reader) IOS::ES::TMDReader tmd{std::move(tmd_buffer)}; // Get the decryption key - const std::vector key = ticket.GetTitleKey(); - if (key.size() != 16) - continue; + const std::array key = ticket.GetTitleKey(); std::unique_ptr aes_context = std::make_unique(); mbedtls_aes_setkey_dec(aes_context.get(), key.data(), 128); From 9f08534a47b7da028ff3c027b935b073a94fcbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 26 Jun 2017 23:56:04 +0200 Subject: [PATCH 2/2] IOS: Reuse IOSC instance when possible Changes ESFormats to take an IOSC instance instead of creating its own temporary instance unnecessarily. --- Source/Core/Core/IOS/ES/Formats.cpp | 21 ++++++++++++--------- Source/Core/Core/IOS/ES/Formats.h | 6 +++++- Source/Core/Core/IOS/ES/TitleManagement.cpp | 10 +++++----- Source/Core/Core/IOS/WFS/WFSI.cpp | 2 +- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 04210090f9..b7e1e9c106 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -380,7 +380,7 @@ u64 TicketReader::GetTitleId() const return Common::swap64(m_bytes.data() + offsetof(Ticket, title_id)); } -std::array TicketReader::GetTitleKey() const +std::array TicketReader::GetTitleKey(const HLE::IOSC& iosc) const { u8 iv[16] = {}; std::copy_n(&m_bytes[offsetof(Ticket, title_id)], sizeof(Ticket::title_id), iv); @@ -394,17 +394,20 @@ std::array TicketReader::GetTitleKey() const GetTitleId(), index); } - const bool is_rvt = (GetIssuer() == "Root-CA00000002-XS00000006"); - const HLE::IOSC::ConsoleType console_type = - is_rvt ? HLE::IOSC::ConsoleType::RVT : HLE::IOSC::ConsoleType::Retail; - std::array key; - HLE::IOSC iosc(console_type); iosc.Decrypt(common_key_handle, iv, &m_bytes[offsetof(Ticket, title_key)], 16, key.data(), HLE::PID_ES); return key; } +std::array TicketReader::GetTitleKey() const +{ + const bool is_rvt = (GetIssuer() == "Root-CA00000002-XS00000006"); + const HLE::IOSC::ConsoleType console_type = + is_rvt ? HLE::IOSC::ConsoleType::RVT : HLE::IOSC::ConsoleType::Retail; + return GetTitleKey(HLE::IOSC{console_type}); +} + void TicketReader::DeleteTicket(u64 ticket_id_to_delete) { std::vector new_ticket; @@ -420,16 +423,16 @@ void TicketReader::DeleteTicket(u64 ticket_id_to_delete) m_bytes = std::move(new_ticket); } -s32 TicketReader::Unpersonalise() +HLE::ReturnCode TicketReader::Unpersonalise(HLE::IOSC& iosc) { const auto ticket_begin = m_bytes.begin(); // IOS uses IOSC to compute an AES key from the peer public key and the device's private ECC key, // which is used the decrypt the title key. The IV is the ticket ID (8 bytes), zero extended. using namespace HLE; - IOSC iosc; IOSC::Handle public_handle; - s32 ret = iosc.CreateObject(&public_handle, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES); + ReturnCode ret = + iosc.CreateObject(&public_handle, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES); if (ret != IPC_SUCCESS) return ret; diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index ac710fe660..3998076cbe 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -222,6 +222,10 @@ public: u32 GetDeviceId() const; u64 GetTitleId() const; + // Get the decrypted title key. + std::array GetTitleKey(const HLE::IOSC& iosc) const; + // Same as the above version, but guesses the console type depending on the issuer + // and constructs a temporary IOSC instance. std::array GetTitleKey() const; // Deletes a ticket with the given ticket ID from the internal buffer. @@ -229,7 +233,7 @@ public: // Decrypts the title key field for a "personalised" ticket -- one that is device-specific // and has a title key that must be decrypted first. - s32 Unpersonalise(); + HLE::ReturnCode Unpersonalise(HLE::IOSC& iosc); }; class SharedContentMap final diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 58f55b84e5..3654f90d85 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -60,7 +60,7 @@ ReturnCode ES::ImportTicket(const std::vector& ticket_bytes, const std::vect WARN_LOG(IOS_ES, "Device ID mismatch: ticket %08x, device %08x", ticket_device_id, device_id); return ES_DEVICE_ID_MISMATCH; } - const ReturnCode ret = static_cast(ticket.Unpersonalise()); + const ReturnCode ret = ticket.Unpersonalise(m_ios.GetIOSC()); if (ret < 0) { ERROR_LOG(IOS_ES, "ImportTicket: Failed to unpersonalise ticket for %016" PRIx64 " (%d)", @@ -294,9 +294,9 @@ ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd) u8 iv[16] = {0}; iv[0] = (content_info.index >> 8) & 0xFF; iv[1] = content_info.index & 0xFF; - std::vector decrypted_data = Common::AES::Decrypt(ticket.GetTitleKey().data(), iv, - context.title_import.content_buffer.data(), - context.title_import.content_buffer.size()); + std::vector decrypted_data = Common::AES::Decrypt( + ticket.GetTitleKey(m_ios.GetIOSC()).data(), iv, context.title_import.content_buffer.data(), + context.title_import.content_buffer.size()); if (!CheckIfContentHashMatches(decrypted_data, content_info)) { ERROR_LOG(IOS_ES, "ImportContentEnd: Hash for content %08x doesn't match", content_info.id); @@ -570,7 +570,7 @@ ReturnCode ES::ExportTitleInit(Context& context, u64 title_id, u8* tmd_bytes, u3 if (ticket.GetTitleId() != context.title_export.tmd.GetTitleId()) return ES_EINVAL; - context.title_export.title_key = ticket.GetTitleKey(); + context.title_export.title_key = ticket.GetTitleKey(m_ios.GetIOSC()); const std::vector& raw_tmd = context.title_export.tmd.GetBytes(); if (tmd_size != raw_tmd.size()) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 905e7629e8..c35eeec0e9 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -117,7 +117,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } - memcpy(m_aes_key, ticket.GetTitleKey().data(), sizeof(m_aes_key)); + memcpy(m_aes_key, ticket.GetTitleKey(m_ios.GetIOSC()).data(), sizeof(m_aes_key)); mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128); break;