mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
VolumeVerifier: Verify WAD contents
This commit is contained in:
parent
a469fb3150
commit
8709b21ac3
@ -73,6 +73,7 @@ public:
|
|||||||
{
|
{
|
||||||
return INVALID_CERT_CHAIN;
|
return INVALID_CERT_CHAIN;
|
||||||
}
|
}
|
||||||
|
virtual std::vector<u64> GetContentOffsets() const { return {}; }
|
||||||
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
|
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
|
||||||
virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0;
|
virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0;
|
||||||
virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
|
virtual u64 PartitionOffsetToRawOffset(u64 offset, const Partition& partition) const
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include <mbedtls/aes.h>
|
||||||
#include <mbedtls/md5.h>
|
#include <mbedtls/md5.h>
|
||||||
#include <mbedtls/sha1.h>
|
#include <mbedtls/sha1.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@ -630,7 +631,11 @@ void VolumeVerifier::CheckMisc()
|
|||||||
|
|
||||||
void VolumeVerifier::SetUpHashing()
|
void VolumeVerifier::SetUpHashing()
|
||||||
{
|
{
|
||||||
if (m_volume.GetVolumeType() == Platform::WiiDisc)
|
if (m_volume.GetVolumeType() == Platform::WiiWAD)
|
||||||
|
{
|
||||||
|
m_content_offsets = m_volume.GetContentOffsets();
|
||||||
|
}
|
||||||
|
else if (m_volume.GetVolumeType() == Platform::WiiDisc)
|
||||||
{
|
{
|
||||||
// Set up a DiscScrubber for checking whether blocks with errors are unused
|
// Set up a DiscScrubber for checking whether blocks with errors are unused
|
||||||
m_scrubber.SetupScrub(&m_volume, VolumeWii::BLOCK_TOTAL_SIZE);
|
m_scrubber.SetupScrub(&m_volume, VolumeWii::BLOCK_TOTAL_SIZE);
|
||||||
@ -663,14 +668,28 @@ void VolumeVerifier::Process()
|
|||||||
if (m_progress == m_max_progress)
|
if (m_progress == m_max_progress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
IOS::ES::Content content;
|
||||||
|
bool content_read = false;
|
||||||
u64 bytes_to_read = BLOCK_SIZE;
|
u64 bytes_to_read = BLOCK_SIZE;
|
||||||
if (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset == m_progress)
|
if (m_content_index < m_content_offsets.size() &&
|
||||||
|
m_content_offsets[m_content_index] == m_progress)
|
||||||
|
{
|
||||||
|
m_volume.GetTMD(PARTITION_NONE).GetContent(m_content_index, &content);
|
||||||
|
bytes_to_read = Common::AlignUp(content.size, 0x40);
|
||||||
|
content_read = true;
|
||||||
|
}
|
||||||
|
else if (m_content_index < m_content_offsets.size() &&
|
||||||
|
m_content_offsets[m_content_index] > m_progress)
|
||||||
|
{
|
||||||
|
bytes_to_read = std::min(bytes_to_read, m_content_offsets[m_content_index] - m_progress);
|
||||||
|
}
|
||||||
|
else if (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset == m_progress)
|
||||||
{
|
{
|
||||||
bytes_to_read = VolumeWii::BLOCK_TOTAL_SIZE;
|
bytes_to_read = VolumeWii::BLOCK_TOTAL_SIZE;
|
||||||
}
|
}
|
||||||
else if (m_block_index + 1 < m_blocks.size() && m_blocks[m_block_index + 1].offset > m_progress)
|
else if (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset > m_progress)
|
||||||
{
|
{
|
||||||
bytes_to_read = std::min(bytes_to_read, m_blocks[m_block_index + 1].offset - m_progress);
|
bytes_to_read = std::min(bytes_to_read, m_blocks[m_block_index].offset - m_progress);
|
||||||
}
|
}
|
||||||
bytes_to_read = std::min(bytes_to_read, m_max_progress - m_progress);
|
bytes_to_read = std::min(bytes_to_read, m_max_progress - m_progress);
|
||||||
|
|
||||||
@ -700,6 +719,17 @@ void VolumeVerifier::Process()
|
|||||||
|
|
||||||
m_progress += bytes_to_read;
|
m_progress += bytes_to_read;
|
||||||
|
|
||||||
|
if (content_read)
|
||||||
|
{
|
||||||
|
if (!CheckContentIntegrity(content))
|
||||||
|
{
|
||||||
|
AddProblem(Severity::High,
|
||||||
|
StringFromFormat(GetStringT("Content %08x is corrupt.").c_str(), content.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_content_index++;
|
||||||
|
}
|
||||||
|
|
||||||
while (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset < m_progress)
|
while (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset < m_progress)
|
||||||
{
|
{
|
||||||
if (!m_volume.CheckBlockIntegrity(m_blocks[m_block_index].block_index,
|
if (!m_volume.CheckBlockIntegrity(m_blocks[m_block_index].block_index,
|
||||||
@ -721,6 +751,30 @@ void VolumeVerifier::Process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VolumeVerifier::CheckContentIntegrity(const IOS::ES::Content& content)
|
||||||
|
{
|
||||||
|
const u64 padded_size = Common::AlignUp(content.size, 0x40);
|
||||||
|
std::vector<u8> encrypted_data(padded_size);
|
||||||
|
m_volume.Read(m_content_offsets[m_content_index], padded_size, encrypted_data.data(),
|
||||||
|
PARTITION_NONE);
|
||||||
|
|
||||||
|
mbedtls_aes_context context;
|
||||||
|
const std::array<u8, 16> key = m_volume.GetTicket(PARTITION_NONE).GetTitleKey();
|
||||||
|
mbedtls_aes_setkey_dec(&context, key.data(), 128);
|
||||||
|
|
||||||
|
std::array<u8, 16> iv{};
|
||||||
|
iv[0] = static_cast<u8>(content.index >> 8);
|
||||||
|
iv[1] = static_cast<u8>(content.index & 0xFF);
|
||||||
|
|
||||||
|
std::vector<u8> decrypted_data(padded_size);
|
||||||
|
mbedtls_aes_crypt_cbc(&context, MBEDTLS_AES_DECRYPT, padded_size, iv.data(),
|
||||||
|
encrypted_data.data(), decrypted_data.data());
|
||||||
|
|
||||||
|
std::array<u8, 20> sha1;
|
||||||
|
mbedtls_sha1(decrypted_data.data(), content.size, sha1.data());
|
||||||
|
return sha1 == content.sha1;
|
||||||
|
}
|
||||||
|
|
||||||
u64 VolumeVerifier::GetBytesProcessed() const
|
u64 VolumeVerifier::GetBytesProcessed() const
|
||||||
{
|
{
|
||||||
return m_progress;
|
return m_progress;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
namespace IOS::ES
|
namespace IOS::ES
|
||||||
{
|
{
|
||||||
|
struct Content;
|
||||||
class SignedBlobReader;
|
class SignedBlobReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ private:
|
|||||||
u64 GetBiggestUsedOffset(const FileInfo& file_info) const;
|
u64 GetBiggestUsedOffset(const FileInfo& file_info) const;
|
||||||
void CheckMisc();
|
void CheckMisc();
|
||||||
void SetUpHashing();
|
void SetUpHashing();
|
||||||
|
bool CheckContentIntegrity(const IOS::ES::Content& content);
|
||||||
|
|
||||||
void AddProblem(Severity severity, const std::string& text);
|
void AddProblem(Severity severity, const std::string& text);
|
||||||
|
|
||||||
@ -116,6 +118,8 @@ private:
|
|||||||
mbedtls_sha1_context m_sha1_context;
|
mbedtls_sha1_context m_sha1_context;
|
||||||
|
|
||||||
DiscScrubber m_scrubber;
|
DiscScrubber m_scrubber;
|
||||||
|
std::vector<u64> m_content_offsets;
|
||||||
|
u16 m_content_index = 0;
|
||||||
std::vector<BlockToVerify> m_blocks;
|
std::vector<BlockToVerify> m_blocks;
|
||||||
size_t m_block_index = 0; // Index in m_blocks, not index in a specific partition
|
size_t m_block_index = 0; // Index in m_blocks, not index in a specific partition
|
||||||
std::map<Partition, size_t> m_block_errors;
|
std::map<Partition, size_t> m_block_errors;
|
||||||
|
@ -40,8 +40,8 @@ VolumeWAD::VolumeWAD(std::unique_ptr<BlobReader> reader) : m_reader(std::move(re
|
|||||||
m_cert_chain_offset = Common::AlignUp(m_hdr_size, 0x40);
|
m_cert_chain_offset = Common::AlignUp(m_hdr_size, 0x40);
|
||||||
m_ticket_offset = m_cert_chain_offset + Common::AlignUp(m_cert_chain_size, 0x40);
|
m_ticket_offset = m_cert_chain_offset + Common::AlignUp(m_cert_chain_size, 0x40);
|
||||||
m_tmd_offset = m_ticket_offset + Common::AlignUp(m_ticket_size, 0x40);
|
m_tmd_offset = m_ticket_offset + Common::AlignUp(m_ticket_size, 0x40);
|
||||||
m_opening_bnr_offset =
|
m_data_offset = m_tmd_offset + Common::AlignUp(m_tmd_size, 0x40);
|
||||||
m_tmd_offset + Common::AlignUp(m_tmd_size, 0x40) + Common::AlignUp(m_data_size, 0x40);
|
m_opening_bnr_offset = m_data_offset + Common::AlignUp(m_data_size, 0x40);
|
||||||
|
|
||||||
std::vector<u8> ticket_buffer(m_ticket_size);
|
std::vector<u8> ticket_buffer(m_ticket_size);
|
||||||
Read(m_ticket_offset, m_ticket_size, ticket_buffer.data());
|
Read(m_ticket_offset, m_ticket_size, ticket_buffer.data());
|
||||||
@ -118,6 +118,21 @@ const std::vector<u8>& VolumeWAD::GetCertificateChain(const Partition& partition
|
|||||||
return m_cert_chain;
|
return m_cert_chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u64> VolumeWAD::GetContentOffsets() const
|
||||||
|
{
|
||||||
|
const std::vector<IOS::ES::Content> contents = m_tmd.GetContents();
|
||||||
|
std::vector<u64> content_offsets;
|
||||||
|
content_offsets.reserve(contents.size());
|
||||||
|
u64 offset = m_data_offset;
|
||||||
|
for (const IOS::ES::Content& content : contents)
|
||||||
|
{
|
||||||
|
content_offsets.emplace_back(offset);
|
||||||
|
offset += Common::AlignUp(content.size, 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content_offsets;
|
||||||
|
}
|
||||||
|
|
||||||
std::string VolumeWAD::GetGameID(const Partition& partition) const
|
std::string VolumeWAD::GetGameID(const Partition& partition) const
|
||||||
{
|
{
|
||||||
return m_tmd.GetGameID();
|
return m_tmd.GetGameID();
|
||||||
|
@ -38,6 +38,7 @@ public:
|
|||||||
const IOS::ES::TMDReader& GetTMD(const Partition& partition = PARTITION_NONE) const override;
|
const IOS::ES::TMDReader& GetTMD(const Partition& partition = PARTITION_NONE) const override;
|
||||||
const std::vector<u8>&
|
const std::vector<u8>&
|
||||||
GetCertificateChain(const Partition& partition = PARTITION_NONE) const override;
|
GetCertificateChain(const Partition& partition = PARTITION_NONE) const override;
|
||||||
|
std::vector<u64> GetContentOffsets() const override;
|
||||||
std::string GetGameID(const Partition& partition = PARTITION_NONE) const override;
|
std::string GetGameID(const Partition& partition = PARTITION_NONE) const override;
|
||||||
std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const override;
|
std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const override;
|
||||||
std::string GetMakerID(const Partition& partition = PARTITION_NONE) const override;
|
std::string GetMakerID(const Partition& partition = PARTITION_NONE) const override;
|
||||||
@ -69,6 +70,7 @@ private:
|
|||||||
u32 m_cert_chain_offset = 0;
|
u32 m_cert_chain_offset = 0;
|
||||||
u32 m_ticket_offset = 0;
|
u32 m_ticket_offset = 0;
|
||||||
u32 m_tmd_offset = 0;
|
u32 m_tmd_offset = 0;
|
||||||
|
u32 m_data_offset = 0;
|
||||||
u32 m_opening_bnr_offset = 0;
|
u32 m_opening_bnr_offset = 0;
|
||||||
u32 m_hdr_size = 0;
|
u32 m_hdr_size = 0;
|
||||||
u32 m_cert_chain_size = 0;
|
u32 m_cert_chain_size = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user