summaryrefslogtreecommitdiff
path: root/Source/Core/DiscIO/DirectoryBlob.cpp
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2020-01-23 16:47:49 +0100
committerJosJuice <josjuice@gmail.com>2020-04-24 14:24:12 +0200
commit319c50897881c7ee1aba8e0bfe396cb385d9eb37 (patch)
tree23cee44984e349b86fddda4bfc9b8112aa46a9c7 /Source/Core/DiscIO/DirectoryBlob.cpp
parenta4c7100bcc1d7bcd92ba436503d41361d46eb38c (diff)
DiscIO: Implement re-encryption of Wii partition data
Diffstat (limited to 'Source/Core/DiscIO/DirectoryBlob.cpp')
-rw-r--r--Source/Core/DiscIO/DirectoryBlob.cpp70
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,