diff options
| author | JosJuice <josjuice@gmail.com> | 2020-01-23 16:47:49 +0100 |
|---|---|---|
| committer | JosJuice <josjuice@gmail.com> | 2020-04-24 14:24:12 +0200 |
| commit | 319c50897881c7ee1aba8e0bfe396cb385d9eb37 (patch) | |
| tree | 23cee44984e349b86fddda4bfc9b8112aa46a9c7 /Source/Core/DiscIO/DirectoryBlob.cpp | |
| parent | a4c7100bcc1d7bcd92ba436503d41361d46eb38c (diff) | |
DiscIO: Implement re-encryption of Wii partition data
Diffstat (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp')
| -rw-r--r-- | Source/Core/DiscIO/DirectoryBlob.cpp | 70 |
1 files changed, 60 insertions, 10 deletions
diff --git a/Source/Core/DiscIO/DirectoryBlob.cpp b/Source/Core/DiscIO/DirectoryBlob.cpp index 64d4497925..77ca32d19b 100644 --- a/Source/Core/DiscIO/DirectoryBlob.cpp +++ b/Source/Core/DiscIO/DirectoryBlob.cpp @@ -27,8 +27,10 @@ #include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/Boot/DolReader.h" +#include "Core/IOS/ES/Formats.h" #include "DiscIO/Blob.h" #include "DiscIO/VolumeWii.h" +#include "DiscIO/WiiEncryptionCache.h" namespace DiscIO { @@ -70,6 +72,11 @@ DiscContent::DiscContent(u64 offset, u64 size, const u8* data) { } +DiscContent::DiscContent(u64 offset, u64 size, DirectoryBlobReader* blob) + : m_offset(offset), m_size(size), m_content_source(blob) +{ +} + DiscContent::DiscContent(u64 offset) : m_offset(offset) { } @@ -107,11 +114,21 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const if (!file.Seek(offset_in_content, SEEK_SET) || !file.ReadBytes(*buffer, bytes_to_read)) return false; } - else + else if (std::holds_alternative<const u8*>(m_content_source)) { const u8* const content_pointer = std::get<const u8*>(m_content_source) + offset_in_content; std::copy(content_pointer, content_pointer + bytes_to_read, *buffer); } + else + { + DirectoryBlobReader* blob = std::get<DirectoryBlobReader*>(m_content_source); + const u64 decrypted_size = m_size * VolumeWii::BLOCK_DATA_SIZE / VolumeWii::BLOCK_TOTAL_SIZE; + if (!blob->EncryptPartitionData(offset_in_content, bytes_to_read, *buffer, m_offset, + decrypted_size)) + { + return false; + } + } *length -= bytes_to_read; *buffer += bytes_to_read; @@ -133,6 +150,12 @@ void DiscContentContainer::Add(u64 offset, u64 size, const u8* data) m_contents.emplace(offset, size, data); } +void DiscContentContainer::Add(u64 offset, u64 size, DirectoryBlobReader* blob) +{ + if (size != 0) + m_contents.emplace(offset, size, blob); +} + u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path) { const u64 size = File::GetSize(path); @@ -332,6 +355,7 @@ std::unique_ptr<DirectoryBlobReader> DirectoryBlobReader::Create(const std::stri DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, const std::string& true_root) + : m_encryption_cache(this) { DirectoryBlobPartition game_partition(game_partition_root, {}); m_is_wii = game_partition.IsWii(); @@ -340,6 +364,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root, { m_gamecube_pseudopartition = std::move(game_partition); m_data_size = m_gamecube_pseudopartition.GetDataSize(); + m_encrypted = false; } else { @@ -377,7 +402,6 @@ bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer) if (offset + length > m_data_size) return false; - // TODO: We don't handle raw access to the encrypted area of Wii discs correctly. return (m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents()) .Read(offset, length, buffer); } @@ -403,6 +427,21 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, return it->second.GetContents().Read(offset, size, buffer); } +bool DirectoryBlobReader::EncryptPartitionData(u64 offset, u64 size, u8* buffer, + u64 partition_data_offset, + u64 partition_data_decrypted_size) +{ + auto it = m_partitions.find(partition_data_offset); + if (it == m_partitions.end()) + return false; + + if (!m_encrypted) + return it->second.GetContents().Read(offset, size, buffer); + + return m_encryption_cache.EncryptGroups(offset, size, buffer, partition_data_offset, + partition_data_decrypted_size, it->second.GetKey()); +} + BlobType DirectoryBlobReader::GetBlobType() const { return BlobType::DIRECTORY; @@ -440,6 +479,9 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector<u8>& parti if (header_bin_bytes_read < 0x61) m_disc_header_nonpartition[0x61] = 0; + m_encrypted = std::all_of(m_disc_header_nonpartition.data() + 0x60, + m_disc_header_nonpartition.data() + 0x64, [](u8 x) { return x == 0; }); + m_nonpartition_contents.Add(NONPARTITION_DISCHEADER_ADDRESS, m_disc_header_nonpartition); } @@ -512,13 +554,14 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti Write32(static_cast<u32>(partitions[i].type), offset_in_table, &m_partition_table); offset_in_table += 4; - SetPartitionHeader(partitions[i].partition, partition_address); + SetPartitionHeader(&partitions[i].partition, partition_address); - const u64 partition_data_size = partitions[i].partition.GetDataSize(); + const u64 data_size = partitions[i].partition.GetDataSize(); m_partitions.emplace(partition_address + PARTITION_DATA_OFFSET, std::move(partitions[i].partition)); + m_nonpartition_contents.Add(partition_address + PARTITION_DATA_OFFSET, data_size, this); const u64 unaligned_next_partition_address = VolumeWii::EncryptedPartitionOffsetToRawOffset( - partition_data_size, Partition(partition_address), PARTITION_DATA_OFFSET); + data_size, Partition(partition_address), PARTITION_DATA_OFFSET); partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull); } m_data_size = partition_address; @@ -528,7 +571,7 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti // This function sets the header that's shortly before the start of the encrypted // area, not the header that's right at the beginning of the encrypted area -void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& partition, +void DirectoryBlobReader::SetPartitionHeader(DirectoryBlobPartition* partition, u64 partition_address) { constexpr u32 TICKET_OFFSET = 0x0; @@ -538,10 +581,10 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti constexpr u32 H3_OFFSET = 0x4000; constexpr u32 H3_SIZE = 0x18000; - const std::string& partition_root = partition.GetRootDirectory(); + const std::string& partition_root = partition->GetRootDirectory(); - m_nonpartition_contents.CheckSizeAndAdd(partition_address + TICKET_OFFSET, TICKET_SIZE, - partition_root + "ticket.bin"); + const u64 ticket_size = m_nonpartition_contents.CheckSizeAndAdd( + partition_address + TICKET_OFFSET, TICKET_SIZE, partition_root + "ticket.bin"); const u64 tmd_size = m_nonpartition_contents.CheckSizeAndAdd( partition_address + TMD_OFFSET, MAX_TMD_SIZE, partition_root + "tmd.bin"); @@ -555,7 +598,7 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti partition_root + "h3.bin"); constexpr u32 PARTITION_HEADER_SIZE = 0x1c; - const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000; + const u64 data_size = Common::AlignUp(partition->GetDataSize(), 0x7c00) / 0x7c00 * 0x8000; m_partition_headers.emplace_back(PARTITION_HEADER_SIZE); std::vector<u8>& partition_header = m_partition_headers.back(); Write32(static_cast<u32>(tmd_size), 0x0, &partition_header); @@ -567,6 +610,13 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti Write32(static_cast<u32>(data_size >> 2), 0x18, &partition_header); m_nonpartition_contents.Add(partition_address + TICKET_SIZE, partition_header); + + std::vector<u8> ticket_buffer(ticket_size); + m_nonpartition_contents.Read(partition_address + TICKET_OFFSET, ticket_size, + ticket_buffer.data()); + IOS::ES::TicketReader ticket(std::move(ticket_buffer)); + if (ticket.IsValid()) + partition->SetKey(ticket.GetTitleKey()); } DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory, |
