diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index a11b1658d5..0dedb770bb 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -348,7 +348,7 @@ bool CBoot::EmulatedBS2_Wii() std::vector tmd = DVDInterface::GetVolume().GetTMD(); - IOS::HLE::TMDReader tmd_reader{std::move(tmd)}; + ES::TMDReader tmd_reader{std::move(tmd)}; if (!SetupWiiMemory(tmd_reader.GetIOSId())) return false; diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index d0b2c43298..5e6a06d278 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -2,35 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -// ======================================================= -// File description -// ------------- -/* Here we handle /dev/es requests. We have cases for these functions, the exact - DevKitPro/libogc name is in parenthesis: - - 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes) - 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes) - - 0x1b DiGetTicketView (Input: none, Output: 216 bytes) - 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers - - 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes) - 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore, - it used to come after 0x12 - - but only the first two are correctly supported. For the other four we ignore any potential - input and only write zero to the out buffer. However, most games only use first two, - but some Nintendo developed games use the other ones to: - - 0x1b: Mario Galaxy, Mario Kart, SSBB - 0x16: Mario Galaxy, Mario Kart, SSBB - 0x12: Mario Kart - 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question, - and instead answer for example 1 will this question appear. - -*/ -// ============= - #include #include #include @@ -347,7 +318,8 @@ IPCCommandResult ES::AddTicket(const IOCtlVRequest& request) INFO_LOG(IOS_ES, "IOCTL_ES_ADDTICKET"); std::vector ticket(request.in_vectors[0].size); Memory::CopyFromEmu(ticket.data(), request.in_vectors[0].address, request.in_vectors[0].size); - DiscIO::AddTicket(ticket); + + DiscIO::AddTicket(::ES::TicketReader{std::move(ticket)}); return GetDefaultReply(IPC_SUCCESS); } @@ -441,18 +413,18 @@ IPCCommandResult ES::AddContentFinish(const IOCtlVRequest& request) INFO_LOG(IOS_ES, "IOCTL_ES_ADDCONTENTFINISH: content fd %08x", content_fd); // Try to find the title key from a pre-installed ticket. - std::vector ticket = DiscIO::FindSignedTicket(m_addtitle_tmd.GetTitleId()); - if (ticket.size() == 0) + ::ES::TicketReader ticket = DiscIO::FindSignedTicket(m_addtitle_tmd.GetTitleId()); + if (!ticket.IsValid()) { return GetDefaultReply(ES_NO_TICKET_INSTALLED); } mbedtls_aes_context aes_ctx; - mbedtls_aes_setkey_dec(&aes_ctx, DiscIO::GetKeyFromTicket(ticket).data(), 128); + mbedtls_aes_setkey_dec(&aes_ctx, ticket.GetTitleKey().data(), 128); // The IV for title content decryption is the lower two bytes of the // content index, zero extended. - TMDReader::Content content_info; + ::ES::TMDReader::Content content_info; if (!m_addtitle_tmd.FindContentById(m_addtitle_content_id, &content_info)) { return GetDefaultReply(ES_INVALID_TMD); @@ -777,46 +749,24 @@ IPCCommandResult ES::GetViewCount(const IOCtlVRequest& request) u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); - u32 retVal = 0; const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - u32 ViewCount = - static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE; - if (!ViewCount) + size_t view_count = 0; + if (TitleID >> 32 == 0x00000001 && TitleID != TITLEID_SYSMENU) { - std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT); - if (File::Exists(TicketFilename)) - { - u32 FileSize = (u32)File::GetSize(TicketFilename); - _dbg_assert_msg_(IOS_ES, (FileSize % DiscIO::CNANDContentLoader::TICKET_SIZE) == 0, - "IOCTL_ES_GETVIEWCNT ticket file size seems to be wrong"); - - ViewCount = FileSize / DiscIO::CNANDContentLoader::TICKET_SIZE; - _dbg_assert_msg_(IOS_ES, (ViewCount > 0) && (ViewCount <= 4), - "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong"); - } - else if (TitleID >> 32 == 0x00000001) - { - // Fake a ticket view to make IOS reload work. - ViewCount = 1; - } - else - { - ViewCount = 0; - if (TitleID == TITLEID_SYSMENU) - { - PanicAlertT("There must be a ticket for 00000001/00000002. Your NAND dump is probably " - "incomplete."); - } - // retVal = ES_NO_TICKET_INSTALLED; - } + // Fake a ticket view to make IOS reload work. + view_count = 1; + } + else if (Loader.IsValid() && Loader.GetTicket().IsValid()) + { + view_count = Loader.GetTicket().GetNumberOfTickets(); } - INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)", - (u32)(TitleID >> 32), (u32)TitleID, ViewCount); + INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %zu)", + static_cast(TitleID >> 32), static_cast(TitleID), view_count); - Memory::Write_U32(ViewCount, request.io_vectors[0].address); - return GetDefaultReply(retVal); + Memory::Write_U32(static_cast(view_count), request.io_vectors[0].address); + return GetDefaultReply(IPC_SUCCESS); } IPCCommandResult ES::GetViews(const IOCtlVRequest& request) @@ -826,68 +776,37 @@ IPCCommandResult ES::GetViews(const IOCtlVRequest& request) u64 TitleID = Memory::Read_U64(request.in_vectors[0].address); u32 maxViews = Memory::Read_U32(request.in_vectors[1].address); - u32 retVal = 0; const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - const std::vector& ticket = Loader.GetTicket(); - - if (ticket.empty()) + if (TitleID >> 32 == 0x00000001 && TitleID != TITLEID_SYSMENU) { - std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT); - if (File::Exists(TicketFilename)) - { - File::IOFile pFile(TicketFilename, "rb"); - if (pFile) - { - u8 FileTicket[DiscIO::CNANDContentLoader::TICKET_SIZE]; - for (unsigned int View = 0; - View != maxViews && - pFile.ReadBytes(FileTicket, DiscIO::CNANDContentLoader::TICKET_SIZE); - ++View) - { - Memory::Write_U32(View, request.io_vectors[0].address + View * 0xD8); - Memory::CopyToEmu(request.io_vectors[0].address + 4 + View * 0xD8, FileTicket + 0x1D0, - 212); - } - } - } - else if (TitleID >> 32 == 0x00000001) - { - // For IOS titles, the ticket view isn't normally parsed by either the - // SDK or libogc, just passed to LaunchTitle, so this - // shouldn't matter at all. Just fill out some fields just - // to be on the safe side. - u32 Address = request.io_vectors[0].address; - Memory::Memset(Address, 0, 0xD8); - Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID - Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown - Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask - Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions - } - else - { - // retVal = ES_NO_TICKET_INSTALLED; - PanicAlertT("IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x", - (u32)(TitleID >> 32), (u32)TitleID); - } + // For IOS titles, the ticket view isn't normally parsed by either the + // SDK or libogc, just passed to LaunchTitle, so this + // shouldn't matter at all. Just fill out some fields just + // to be on the safe side. + u32 Address = request.io_vectors[0].address; + Memory::Memset(Address, 0, 0xD8); + Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID + Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown + Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask + Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions } - else + else if (Loader.IsValid() && Loader.GetTicket().IsValid()) { - u32 view_count = - static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE; - for (unsigned int view = 0; view != maxViews && view < view_count; ++view) + u32 number_of_views = std::min(maxViews, Loader.GetTicket().GetNumberOfTickets()); + for (u32 view = 0; view < number_of_views; ++view) { - Memory::Write_U32(view, request.io_vectors[0].address + view * 0xD8); - Memory::CopyToEmu(request.io_vectors[0].address + 4 + view * 0xD8, - &ticket[0x1D0 + (view * DiscIO::CNANDContentLoader::TICKET_SIZE)], 212); + const std::vector ticket_view = Loader.GetTicket().GetRawTicketView(view); + Memory::CopyToEmu(request.io_vectors[0].address + view * sizeof(::ES::TicketView), + ticket_view.data(), ticket_view.size()); } } INFO_LOG(IOS_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", (u32)(TitleID >> 32), (u32)TitleID, maxViews); - return GetDefaultReply(retVal); + return GetDefaultReply(IPC_SUCCESS); } IPCCommandResult ES::GetTMDViewCount(const IOCtlVRequest& request) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 86f447e9a0..aa934100f2 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -203,7 +203,7 @@ private: u32 m_AccessIdentID = 0; // For title installation (ioctls IOCTL_ES_ADDTITLE*). - TMDReader m_addtitle_tmd; + ::ES::TMDReader m_addtitle_tmd; u32 m_addtitle_content_id = 0xFFFFFFFF; std::vector m_addtitle_content_buffer; }; diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 6a9053fbee..1eaf375070 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -5,17 +5,30 @@ #include "Core/IOS/ES/Formats.h" #include +#include +#include #include #include +#include + #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -namespace IOS +namespace ES { -namespace HLE +std::vector AESDecode(const u8* key, u8* iv, const u8* src, u32 size) { + mbedtls_aes_context aes_ctx; + std::vector buffer(size); + + mbedtls_aes_setkey_dec(&aes_ctx, key, 128); + mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data()); + + return buffer; +} + TMDReader::TMDReader(const std::vector& bytes) : m_bytes(bytes) { } @@ -103,5 +116,92 @@ void TMDReader::DoState(PointerWrap& p) { p.Do(m_bytes); } -} // namespace HLE -} // namespace IOS + +TicketReader::TicketReader(const std::vector& bytes) : m_bytes(bytes) +{ +} + +TicketReader::TicketReader(std::vector&& bytes) : m_bytes(std::move(bytes)) +{ +} + +void TicketReader::SetBytes(const std::vector& bytes) +{ + m_bytes = bytes; +} + +void TicketReader::SetBytes(std::vector&& bytes) +{ + m_bytes = std::move(bytes); +} + +bool TicketReader::IsValid() const +{ + // Too small for the signature type. + if (m_bytes.size() < sizeof(u32)) + return false; + + u32 ticket_offset = GetOffset(); + if (ticket_offset == 0) + return false; + + // Too small for the ticket itself. + if (m_bytes.size() < ticket_offset + sizeof(Ticket)) + return false; + + return true; +} + +u32 TicketReader::GetNumberOfTickets() const +{ + return static_cast(m_bytes.size() / (GetOffset() + sizeof(Ticket))); +} + +u32 TicketReader::GetOffset() const +{ + u32 signature_type = Common::swap32(m_bytes.data()); + if (signature_type == 0x10000) // RSA4096 + return 576; + if (signature_type == 0x10001) // RSA2048 + return 320; + if (signature_type == 0x10002) // ECDSA + return 128; + + ERROR_LOG(COMMON, "Invalid ticket signature type: %08x", signature_type); + return 0; +} + +const std::vector& TicketReader::GetRawTicket() const +{ + return m_bytes; +} + +std::vector TicketReader::GetRawTicketView(u32 ticket_num) const +{ + // A ticket view is composed of a view ID + part of a ticket starting from the ticket_id field. + std::vector view{sizeof(TicketView)}; + + u32 view_id = Common::swap32(ticket_num); + std::memcpy(view.data(), &view_id, sizeof(view_id)); + + const size_t ticket_start = (GetOffset() + sizeof(Ticket)) * ticket_num; + const size_t view_start = ticket_start + offsetof(Ticket, ticket_id); + std::memcpy(view.data() + sizeof(view_id), &m_bytes[view_start], sizeof(view) - sizeof(view_id)); + + return view; +} + +u64 TicketReader::GetTitleId() const +{ + return Common::swap64(m_bytes.data() + GetOffset() + offsetof(Ticket, title_id)); +} + +std::vector TicketReader::GetTitleKey() const +{ + const u8 common_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, + 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7}; + u8 iv[16] = {}; + std::copy_n(&m_bytes[GetOffset() + offsetof(Ticket, title_id)], sizeof(Ticket::title_id), iv); + return AESDecode(common_key, iv, &m_bytes[GetOffset() + offsetof(Ticket, title_key)], 16); +} +} // namespace ES diff --git a/Source/Core/Core/IOS/ES/Formats.h b/Source/Core/Core/IOS/ES/Formats.h index 775f602451..f161d1974a 100644 --- a/Source/Core/Core/IOS/ES/Formats.h +++ b/Source/Core/Core/IOS/ES/Formats.h @@ -13,10 +13,10 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -namespace IOS -{ -namespace HLE +namespace ES { +std::vector AESDecode(const u8* key, u8* iv, const u8* src, u32 size); + class TMDReader final { public: @@ -49,5 +49,79 @@ public: private: std::vector m_bytes; }; -} // namespace HLE -} // namespace IOS + +#pragma pack(push, 4) +struct TimeLimit +{ + u32 enabled; + u32 seconds; +}; + +struct TicketView +{ + u32 view; + u64 ticket_id; + u32 device_id; + u64 title_id; + u16 access_mask; + u32 permitted_title_id; + u32 permitted_title_mask; + u8 title_export_allowed; + u8 common_key_index; + u8 unknown2[0x30]; + u8 content_access_permissions[0x40]; + TimeLimit time_limits[8]; +}; +static_assert(sizeof(TicketView) == 0xd8, "TicketView has the wrong size"); + +struct Ticket +{ + u8 signature_issuer[0x40]; + u8 ecdh_key[0x3c]; + u8 unknown[0x03]; + u8 title_key[0x10]; + u64 ticket_id; + u32 device_id; + u64 title_id; + u16 access_mask; + u16 ticket_version; + u32 permitted_title_id; + u32 permitted_title_mask; + u8 title_export_allowed; + u8 common_key_index; + u8 unknown2[0x30]; + u8 content_access_permissions[0x40]; + TimeLimit time_limits[8]; +}; +static_assert(sizeof(Ticket) == 356, "Ticket has the wrong size"); +#pragma pack(pop) + +class TicketReader final +{ +public: + TicketReader() = default; + explicit TicketReader(const std::vector& bytes); + explicit TicketReader(std::vector&& bytes); + + void SetBytes(const std::vector& bytes); + void SetBytes(std::vector&& bytes); + + bool IsValid() const; + + const std::vector& GetRawTicket() const; + u32 GetNumberOfTickets() const; + u32 GetOffset() const; + + // Returns a "raw" ticket view, without byte swapping. Intended for use from ES. + // Theoretically, a ticket file can contain one or more tickets. In practice, most (all?) + // official titles only have one ticket, but IOS *does* have code to handle ticket files with + // more than just one ticket and generate ticket views for them, so we implement it too. + std::vector GetRawTicketView(u32 ticket_num) const; + + u64 GetTitleId() const; + std::vector GetTitleKey() const; + +private: + std::vector m_bytes; +}; +} // namespace ES diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 5ca881bb28..4c885fee72 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -109,14 +109,14 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) Memory::CopyFromEmu(tmd_bytes.data(), tmd_addr, tmd_size); m_tmd.SetBytes(std::move(tmd_bytes)); - std::vector ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId()); - if (ticket.size() == 0) + ES::TicketReader ticket = DiscIO::FindSignedTicket(m_tmd.GetTitleId()); + if (!ticket.IsValid()) { return_error_code = -11028; break; } - memcpy(m_aes_key, DiscIO::GetKeyFromTicket(ticket).data(), sizeof(m_aes_key)); + memcpy(m_aes_key, ticket.GetTitleKey().data(), sizeof(m_aes_key)); mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128); break; @@ -134,7 +134,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) // Initializes the IV from the index of the content in the TMD contents. u32 content_id = Memory::Read_U32(request.buffer_in + 8); - TMDReader::Content content_info; + ES::TMDReader::Content content_info; if (!m_tmd.FindContentById(content_id, &content_info)) { WARN_LOG(IOS, "%s: Content id %08x not found", ioctl_name, content_id); diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 0c1973184e..6388121680 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -50,7 +50,7 @@ private: u8 m_aes_key[0x10] = {}; u8 m_aes_iv[0x10] = {}; - TMDReader m_tmd; + ::ES::TMDReader m_tmd; std::string m_base_extract_path; ARCUnpacker m_arc_unpacker; diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index fc1f600aa1..dcd875388a 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -29,50 +28,6 @@ namespace DiscIO { -namespace -{ -// Strips the signature part of a ticket, which has variable size based on -// signature type. Returns a new vector which has only the ticket structure -// itself. -std::vector SignedTicketToTicket(const std::vector& signed_ticket) -{ - u32 signature_type = Common::swap32(signed_ticket.data()); - u32 entry_offset; - if (signature_type == 0x10000) // RSA4096 - { - entry_offset = 576; - } - else if (signature_type == 0x10001) // RSA2048 - { - entry_offset = 320; - } - else if (signature_type == 0x10002) // ECDSA - { - entry_offset = 128; - } - else - { - ERROR_LOG(DISCIO, "Invalid ticket signature type: %08x", signature_type); - return std::vector(); - } - - std::vector ticket(signed_ticket.size() - entry_offset); - std::copy(signed_ticket.begin() + entry_offset, signed_ticket.end(), ticket.begin()); - return ticket; -} - -std::vector AESDecode(const u8* key, u8* iv, const u8* src, u32 size) -{ - mbedtls_aes_context aes_ctx; - std::vector buffer(size); - - mbedtls_aes_setkey_dec(&aes_ctx, key, 128); - mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data()); - - return buffer; -} -} - CNANDContentData::~CNANDContentData() = default; CSharedContent::CSharedContent(Common::FromWhichRoot root) : m_root(root) @@ -222,13 +177,11 @@ bool CNANDContentLoader::Initialize(const std::string& name) WiiWAD wad(name); std::vector data_app; std::vector tmd; - std::vector decrypted_title_key; if (wad.IsValid()) { m_IsWAD = true; - m_Ticket = wad.GetTicket(); - decrypted_title_key = GetKeyFromTicket(m_Ticket); + m_ticket = wad.GetTicket(); tmd = wad.GetTMD(); data_app = wad.GetDataApp(); } @@ -265,12 +218,14 @@ bool CNANDContentLoader::Initialize(const std::string& name) if (m_Country == 2) // SYSMENU m_Country = GetSysMenuRegion(m_TitleVersion); - InitializeContentEntries(tmd, decrypted_title_key, data_app); + if (!m_IsWAD) + m_ticket = FindSignedTicket(m_TitleID); + + InitializeContentEntries(tmd, data_app); return true; } void CNANDContentLoader::InitializeContentEntries(const std::vector& tmd, - const std::vector& decrypted_title_key, const std::vector& data_app) { m_Content.resize(m_NumEntries); @@ -305,8 +260,8 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector& tmd, iv.fill(0); std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin()); - content.m_Data = std::make_unique(AESDecode( - decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size)); + content.m_Data = std::make_unique(ES::AESDecode( + m_ticket.GetTitleKey().data(), iv.data(), &data_app[data_app_offset], rounded_size)); data_app_offset += rounded_size; continue; @@ -533,14 +488,14 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) return title_id; } -bool AddTicket(const std::vector& signed_ticket) +bool AddTicket(const ES::TicketReader& signed_ticket) { - std::vector ticket = SignedTicketToTicket(signed_ticket); - if (ticket.empty()) + if (!signed_ticket.IsValid()) { return false; } - u64 title_id = Common::swap64(ticket.data() + 0x9c); + + u64 title_id = signed_ticket.GetTitleId(); std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT); File::CreateFullPath(ticket_filename); @@ -549,46 +504,25 @@ bool AddTicket(const std::vector& signed_ticket) if (!ticket_file) return false; - return ticket_file.WriteBytes(signed_ticket.data(), signed_ticket.size()); + const std::vector& raw_ticket = signed_ticket.GetRawTicket(); + return ticket_file.WriteBytes(raw_ticket.data(), raw_ticket.size()); } -std::vector FindSignedTicket(u64 title_id) +ES::TicketReader FindSignedTicket(u64 title_id) { std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT); File::IOFile ticket_file(ticket_filename, "rb"); if (!ticket_file) { - return std::vector(); + return ES::TicketReader{}; } std::vector signed_ticket(ticket_file.GetSize()); if (!ticket_file.ReadBytes(signed_ticket.data(), signed_ticket.size())) { - return std::vector(); + return ES::TicketReader{}; } - return signed_ticket; + return ES::TicketReader{std::move(signed_ticket)}; } - -std::vector FindTicket(u64 title_id) -{ - std::vector signed_ticket = FindSignedTicket(title_id); - if (signed_ticket.empty()) - { - return std::vector(); - } - - return SignedTicketToTicket(signed_ticket); -} - -std::vector GetKeyFromTicket(const std::vector& signed_ticket) -{ - const u8 common_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, - 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7}; - u8 iv[16] = {}; - - std::copy(&signed_ticket[0x01DC], &signed_ticket[0x01DC + 8], iv); - return AESDecode(common_key, iv, &signed_ticket[0x01BF], 16); -} - } // namespace end diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h index 632ac0ef3e..654a123b5d 100644 --- a/Source/Core/DiscIO/NANDContentLoader.h +++ b/Source/Core/DiscIO/NANDContentLoader.h @@ -12,6 +12,7 @@ #include "Common/CommonTypes.h" #include "Common/NandPaths.h" +#include "Core/IOS/ES/Formats.h" namespace File { @@ -22,10 +23,8 @@ namespace DiscIO { enum class Region; -bool AddTicket(const std::vector& signed_ticket); -std::vector FindSignedTicket(u64 title_id); -std::vector FindTicket(u64 title_id); -std::vector GetKeyFromTicket(const std::vector& ticket); +bool AddTicket(const ES::TicketReader& signed_ticket); +ES::TicketReader FindSignedTicket(u64 title_id); class CNANDContentData { @@ -93,7 +92,7 @@ public: const SNANDContent* GetContentByIndex(int index) const; const u8* GetTMDView() const { return m_TMDView; } const u8* GetTMDHeader() const { return m_TMDHeader; } - const std::vector& GetTicket() const { return m_Ticket; } + const ES::TicketReader& GetTicket() const { return m_ticket; } const std::vector& GetContent() const { return m_Content; } u16 GetTitleVersion() const { return m_TitleVersion; } u16 GetNumEntries() const { return m_NumEntries; } @@ -104,14 +103,11 @@ public: TMD_VIEW_SIZE = 0x58, TMD_HEADER_SIZE = 0x1E4, CONTENT_HEADER_SIZE = 0x24, - TICKET_SIZE = 0x2A4 }; private: bool Initialize(const std::string& name); - void InitializeContentEntries(const std::vector& tmd, - const std::vector& decrypted_title_key, - const std::vector& data_app); + void InitializeContentEntries(const std::vector& tmd, const std::vector& data_app); bool m_Valid; bool m_IsWAD; @@ -123,7 +119,7 @@ private: u16 m_TitleVersion; u8 m_TMDView[TMD_VIEW_SIZE]; u8 m_TMDHeader[TMD_HEADER_SIZE]; - std::vector m_Ticket; + ES::TicketReader m_ticket; u8 m_Country; std::vector m_Content; diff --git a/Source/Core/DiscIO/WiiWad.cpp b/Source/Core/DiscIO/WiiWad.cpp index 9e85669204..04e4ff8a7c 100644 --- a/Source/Core/DiscIO/WiiWad.cpp +++ b/Source/Core/DiscIO/WiiWad.cpp @@ -88,7 +88,7 @@ bool WiiWAD::ParseWAD(IBlobReader& reader) u32 offset = 0x40; m_certificate_chain = CreateWADEntry(reader, certificate_chain_size, offset); offset += Common::AlignUp(certificate_chain_size, 0x40); - m_ticket = CreateWADEntry(reader, ticket_size, offset); + m_ticket.SetBytes(CreateWADEntry(reader, ticket_size, offset)); offset += Common::AlignUp(ticket_size, 0x40); m_tmd = CreateWADEntry(reader, tmd_size, offset); offset += Common::AlignUp(tmd_size, 0x40); diff --git a/Source/Core/DiscIO/WiiWad.h b/Source/Core/DiscIO/WiiWad.h index 21f8b746bd..ea0c3de43a 100644 --- a/Source/Core/DiscIO/WiiWad.h +++ b/Source/Core/DiscIO/WiiWad.h @@ -8,6 +8,7 @@ #include #include "Common/CommonTypes.h" +#include "Core/IOS/ES/Formats.h" namespace DiscIO { @@ -22,7 +23,7 @@ public: bool IsValid() const { return m_valid; } const std::vector& GetCertificateChain() const { return m_certificate_chain; } - const std::vector& GetTicket() const { return m_ticket; } + const ES::TicketReader& GetTicket() const { return m_ticket; } const std::vector& GetTMD() const { return m_tmd; } const std::vector& GetDataApp() const { return m_data_app; } const std::vector& GetFooter() const { return m_footer; } @@ -32,7 +33,7 @@ private: bool m_valid; std::vector m_certificate_chain; - std::vector m_ticket; + ES::TicketReader m_ticket; std::vector m_tmd; std::vector m_data_app; std::vector m_footer; diff --git a/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp b/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp index e534f88395..6a839c32be 100644 --- a/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp @@ -182,7 +182,7 @@ void InfoPanel::LoadISODetails() m_fst->SetValue(StrToWxStr(std::to_string(m_opened_iso->GetFSTSize()))); if (m_ios_version) { - IOS::HLE::TMDReader tmd{m_opened_iso->GetTMD()}; + ES::TMDReader tmd{m_opened_iso->GetTMD()}; if (tmd.IsValid()) m_ios_version->SetValue(StringFromFormat("IOS%u", static_cast(tmd.GetIOSId()))); }