mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-26 15:49:50 -06:00
Merge pull request #6836 from leoetlino/wii-save-cleanup
WiiSave: (not so) Minor cleanup
This commit is contained in:
@ -150,7 +150,7 @@ add_library(core
|
|||||||
HW/WiimoteEmu/Encryption.cpp
|
HW/WiimoteEmu/Encryption.cpp
|
||||||
HW/WiimoteEmu/Speaker.cpp
|
HW/WiimoteEmu/Speaker.cpp
|
||||||
HW/WiimoteReal/WiimoteReal.cpp
|
HW/WiimoteReal/WiimoteReal.cpp
|
||||||
HW/WiiSaveCrypted.cpp
|
HW/WiiSave.cpp
|
||||||
IOS/Device.cpp
|
IOS/Device.cpp
|
||||||
IOS/DeviceStub.cpp
|
IOS/DeviceStub.cpp
|
||||||
IOS/IOS.cpp
|
IOS/IOS.cpp
|
||||||
|
@ -179,7 +179,7 @@
|
|||||||
<ClCompile Include="HW\WiimoteReal\IOWin.cpp" />
|
<ClCompile Include="HW\WiimoteReal\IOWin.cpp" />
|
||||||
<ClCompile Include="HW\WiimoteReal\WiimoteReal.cpp" />
|
<ClCompile Include="HW\WiimoteReal\WiimoteReal.cpp" />
|
||||||
<ClCompile Include="HW\WII_IPC.cpp" />
|
<ClCompile Include="HW\WII_IPC.cpp" />
|
||||||
<ClCompile Include="HW\WiiSaveCrypted.cpp" />
|
<ClCompile Include="HW\WiiSave.cpp" />
|
||||||
<ClCompile Include="IOS\Device.cpp" />
|
<ClCompile Include="IOS\Device.cpp" />
|
||||||
<ClCompile Include="IOS\DeviceStub.cpp" />
|
<ClCompile Include="IOS\DeviceStub.cpp" />
|
||||||
<ClCompile Include="IOS\IOS.cpp" />
|
<ClCompile Include="IOS\IOS.cpp" />
|
||||||
@ -437,7 +437,7 @@
|
|||||||
<ClInclude Include="HW\WiimoteEmu\WiimoteHid.h" />
|
<ClInclude Include="HW\WiimoteEmu\WiimoteHid.h" />
|
||||||
<ClInclude Include="HW\WiimoteReal\WiimoteReal.h" />
|
<ClInclude Include="HW\WiimoteReal\WiimoteReal.h" />
|
||||||
<ClInclude Include="HW\WiimoteReal\WiimoteRealBase.h" />
|
<ClInclude Include="HW\WiimoteReal\WiimoteRealBase.h" />
|
||||||
<ClInclude Include="HW\WiiSaveCrypted.h" />
|
<ClInclude Include="HW\WiiSave.h" />
|
||||||
<ClInclude Include="HW\WII_IPC.h" />
|
<ClInclude Include="HW\WII_IPC.h" />
|
||||||
<ClInclude Include="IOS\Device.h" />
|
<ClInclude Include="IOS\Device.h" />
|
||||||
<ClInclude Include="IOS\DeviceStub.h" />
|
<ClInclude Include="IOS\DeviceStub.h" />
|
||||||
|
@ -561,7 +561,7 @@
|
|||||||
<ClCompile Include="HW\SystemTimers.cpp">
|
<ClCompile Include="HW\SystemTimers.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\WiiSaveCrypted.cpp">
|
<ClCompile Include="HW\WiiSave.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="DSP\DSPAssembler.cpp">
|
<ClCompile Include="DSP\DSPAssembler.cpp">
|
||||||
@ -1242,7 +1242,7 @@
|
|||||||
<ClInclude Include="HW\SystemTimers.h">
|
<ClInclude Include="HW\SystemTimers.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\WiiSaveCrypted.h">
|
<ClInclude Include="HW\WiiSave.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="DSP\DSPAssembler.h">
|
<ClInclude Include="DSP\DSPAssembler.h">
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// Licensed under the terms of the GNU GPL, version 2
|
// Licensed under the terms of the GNU GPL, version 2
|
||||||
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||||||
|
|
||||||
#include "Core/HW/WiiSaveCrypted.h"
|
#include "Core/HW/WiiSave.h"
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@ -29,35 +29,30 @@
|
|||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Swap.h"
|
|
||||||
|
|
||||||
const u8 CWiiSaveCrypted::s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08,
|
using Md5 = std::array<u8, 0x10>;
|
||||||
0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D};
|
|
||||||
const u8 CWiiSaveCrypted::s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17,
|
|
||||||
0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93};
|
|
||||||
const u32 CWiiSaveCrypted::s_ng_id = 0x0403AC68;
|
|
||||||
|
|
||||||
bool CWiiSaveCrypted::ImportWiiSave(const std::string& filename)
|
constexpr std::array<u8, 0x10> s_sd_initial_iv{{0x21, 0x67, 0x12, 0xE6, 0xAA, 0x1F, 0x68, 0x9F,
|
||||||
|
0x95, 0xC5, 0xA2, 0x23, 0x24, 0xDC, 0x6A, 0x98}};
|
||||||
|
constexpr std::array<u8, 0x10> s_sd_key{{0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, 0xAF, 0xBA,
|
||||||
|
0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}};
|
||||||
|
constexpr Md5 s_md5_blanker{{0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, 0xAB, 0x06, 0xEC, 0x22,
|
||||||
|
0x45, 0x1A, 0x57, 0x93}};
|
||||||
|
constexpr u32 s_ng_id = 0x0403AC68;
|
||||||
|
|
||||||
|
bool WiiSave::Import(std::string filename)
|
||||||
{
|
{
|
||||||
CWiiSaveCrypted save_file(filename);
|
WiiSave save_file{std::move(filename)};
|
||||||
return save_file.m_valid;
|
return save_file.Import();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWiiSaveCrypted::ExportWiiSave(u64 title_id)
|
bool WiiSave::Export(u64 title_id, std::string export_path)
|
||||||
{
|
{
|
||||||
CWiiSaveCrypted export_save("", title_id);
|
WiiSave export_save{title_id, std::move(export_path)};
|
||||||
if (export_save.m_valid)
|
return export_save.Export();
|
||||||
{
|
|
||||||
SuccessAlertT("Successfully exported file to %s", export_save.m_encrypted_save_path.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PanicAlertT("Export failed");
|
|
||||||
}
|
|
||||||
return export_save.m_valid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::ExportAllSaves()
|
size_t WiiSave::ExportAll(std::string export_path)
|
||||||
{
|
{
|
||||||
std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title";
|
std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title";
|
||||||
std::vector<u64> titles;
|
std::vector<u64> titles;
|
||||||
@ -85,56 +80,50 @@ void CWiiSaveCrypted::ExportAllSaves()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SuccessAlertT("Found %zu save file(s)", titles.size());
|
size_t exported_save_count = 0;
|
||||||
u32 success = 0;
|
|
||||||
for (const u64& title : titles)
|
for (const u64& title : titles)
|
||||||
{
|
{
|
||||||
CWiiSaveCrypted export_save{"", title};
|
WiiSave export_save{title, export_path};
|
||||||
if (export_save.m_valid)
|
if (export_save.Export())
|
||||||
success++;
|
++exported_save_count;
|
||||||
}
|
}
|
||||||
SuccessAlertT("Successfully exported %u save(s) to %s", success,
|
return exported_save_count;
|
||||||
(File::GetUserPath(D_USER_IDX) + "private/wii/title/").c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CWiiSaveCrypted::CWiiSaveCrypted(const std::string& filename, u64 title_id)
|
WiiSave::WiiSave(std::string filename)
|
||||||
: m_encrypted_save_path(filename), m_title_id(title_id)
|
: m_sd_iv{s_sd_initial_iv}, m_encrypted_save_path(std::move(filename)), m_valid{true}
|
||||||
{
|
{
|
||||||
memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10);
|
mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key.data(), 128);
|
||||||
|
}
|
||||||
|
|
||||||
if (!title_id) // Import
|
bool WiiSave::Import()
|
||||||
{
|
{
|
||||||
mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key, 128);
|
|
||||||
m_valid = true;
|
|
||||||
ReadHDR();
|
ReadHDR();
|
||||||
ReadBKHDR();
|
ReadBKHDR();
|
||||||
ImportWiiSaveFiles();
|
ImportWiiSaveFiles();
|
||||||
// TODO: check_sig()
|
// TODO: check_sig()
|
||||||
if (m_valid)
|
return m_valid;
|
||||||
{
|
|
||||||
SuccessAlertT("Successfully imported save file(s)");
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
WiiSave::WiiSave(u64 title_id, std::string export_path)
|
||||||
|
: m_sd_iv{s_sd_initial_iv}, m_encrypted_save_path(std::move(export_path)), m_title_id{title_id}
|
||||||
{
|
{
|
||||||
PanicAlertT("Import failed");
|
mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key.data(), 128);
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key, 128);
|
|
||||||
|
|
||||||
if (getPaths(true))
|
if (getPaths(true))
|
||||||
{
|
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiiSave::Export()
|
||||||
|
{
|
||||||
WriteHDR();
|
WriteHDR();
|
||||||
WriteBKHDR();
|
WriteBKHDR();
|
||||||
ExportWiiSaveFiles();
|
ExportWiiSaveFiles();
|
||||||
do_sig();
|
do_sig();
|
||||||
}
|
return m_valid;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::ReadHDR()
|
void WiiSave::ReadHDR()
|
||||||
{
|
{
|
||||||
File::IOFile data_file(m_encrypted_save_path, "rb");
|
File::IOFile data_file(m_encrypted_save_path, "rb");
|
||||||
if (!data_file)
|
if (!data_file)
|
||||||
@ -151,9 +140,9 @@ void CWiiSaveCrypted::ReadHDR()
|
|||||||
}
|
}
|
||||||
data_file.Close();
|
data_file.Close();
|
||||||
|
|
||||||
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv,
|
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv.data(),
|
||||||
(const u8*)&m_encrypted_header, (u8*)&m_header);
|
(const u8*)&m_encrypted_header, (u8*)&m_header);
|
||||||
u32 banner_size = Common::swap32(m_header.hdr.BannerSize);
|
u32 banner_size = m_header.hdr.banner_size;
|
||||||
if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) ||
|
if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) ||
|
||||||
(((banner_size - BNR_SZ) % ICON_SZ) != 0))
|
(((banner_size - BNR_SZ) % ICON_SZ) != 0))
|
||||||
{
|
{
|
||||||
@ -161,18 +150,17 @@ void CWiiSaveCrypted::ReadHDR()
|
|||||||
m_valid = false;
|
m_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_title_id = Common::swap64(m_header.hdr.SaveGameTitle);
|
m_title_id = m_header.hdr.save_game_title;
|
||||||
|
|
||||||
u8 md5_file[16];
|
Md5 md5_file = m_header.hdr.md5;
|
||||||
u8 md5_calc[16];
|
m_header.hdr.md5 = s_md5_blanker;
|
||||||
memcpy(md5_file, m_header.hdr.Md5, 0x10);
|
Md5 md5_calc;
|
||||||
memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10);
|
mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc.data());
|
||||||
mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc);
|
if (md5_file == md5_calc)
|
||||||
if (memcmp(md5_file, md5_calc, 0x10))
|
|
||||||
{
|
{
|
||||||
ERROR_LOG(CONSOLE, "MD5 mismatch\n %016" PRIx64 "%016" PRIx64 " != %016" PRIx64 "%016" PRIx64,
|
ERROR_LOG(CONSOLE, "MD5 mismatch\n %016" PRIx64 "%016" PRIx64 " != %016" PRIx64 "%016" PRIx64,
|
||||||
Common::swap64(md5_file), Common::swap64(md5_file + 8), Common::swap64(md5_calc),
|
Common::swap64(md5_file.data()), Common::swap64(md5_file.data() + 8),
|
||||||
Common::swap64(md5_calc + 8));
|
Common::swap64(md5_calc.data()), Common::swap64(md5_calc.data() + 8));
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +177,7 @@ void CWiiSaveCrypted::ReadHDR()
|
|||||||
{
|
{
|
||||||
INFO_LOG(CONSOLE, "Creating file %s", banner_file_path.c_str());
|
INFO_LOG(CONSOLE, "Creating file %s", banner_file_path.c_str());
|
||||||
File::IOFile banner_file(banner_file_path, "wb");
|
File::IOFile banner_file(banner_file_path, "wb");
|
||||||
banner_file.WriteBytes(m_header.BNR, banner_size);
|
banner_file.WriteBytes(m_header.banner, banner_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -197,7 +185,7 @@ void CWiiSaveCrypted::ReadHDR()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::WriteHDR()
|
void WiiSave::WriteHDR()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
@ -205,28 +193,28 @@ void CWiiSaveCrypted::WriteHDR()
|
|||||||
|
|
||||||
std::string banner_file_path = m_wii_title_path + "/banner.bin";
|
std::string banner_file_path = m_wii_title_path + "/banner.bin";
|
||||||
u32 banner_size = static_cast<u32>(File::GetSize(banner_file_path));
|
u32 banner_size = static_cast<u32>(File::GetSize(banner_file_path));
|
||||||
m_header.hdr.BannerSize = Common::swap32(banner_size);
|
m_header.hdr.banner_size = banner_size;
|
||||||
|
|
||||||
m_header.hdr.SaveGameTitle = Common::swap64(m_title_id);
|
m_header.hdr.save_game_title = m_title_id;
|
||||||
memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10);
|
m_header.hdr.md5 = s_md5_blanker;
|
||||||
m_header.hdr.Permissions = 0x3C;
|
m_header.hdr.permissions = 0x3C;
|
||||||
|
|
||||||
File::IOFile banner_file(banner_file_path, "rb");
|
File::IOFile banner_file(banner_file_path, "rb");
|
||||||
if (!banner_file.ReadBytes(m_header.BNR, banner_size))
|
if (!banner_file.ReadBytes(m_header.banner, banner_size))
|
||||||
{
|
{
|
||||||
ERROR_LOG(CONSOLE, "Failed to read banner.bin");
|
ERROR_LOG(CONSOLE, "Failed to read banner.bin");
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// remove nocopy flag
|
// remove nocopy flag
|
||||||
m_header.BNR[7] &= ~1;
|
m_header.banner[7] &= ~1;
|
||||||
|
|
||||||
u8 md5_calc[16];
|
Md5 md5_calc;
|
||||||
mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc);
|
mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc.data());
|
||||||
memcpy(m_header.hdr.Md5, md5_calc, 0x10);
|
m_header.hdr.md5 = std::move(md5_calc);
|
||||||
|
|
||||||
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_header,
|
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv.data(),
|
||||||
(u8*)&m_encrypted_header);
|
(const u8*)&m_header, (u8*)&m_encrypted_header);
|
||||||
|
|
||||||
File::IOFile data_file(m_encrypted_save_path, "wb");
|
File::IOFile data_file(m_encrypted_save_path, "wb");
|
||||||
if (!data_file.WriteBytes(&m_encrypted_header, HEADER_SZ))
|
if (!data_file.WriteBytes(&m_encrypted_header, HEADER_SZ))
|
||||||
@ -236,7 +224,7 @@ void CWiiSaveCrypted::WriteHDR()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::ReadBKHDR()
|
void WiiSave::ReadBKHDR()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
@ -257,47 +245,41 @@ void CWiiSaveCrypted::ReadBKHDR()
|
|||||||
}
|
}
|
||||||
fpData_bin.Close();
|
fpData_bin.Close();
|
||||||
|
|
||||||
if (m_bk_hdr.size != Common::swap32(BK_LISTED_SZ) ||
|
if (m_bk_hdr.size != BK_LISTED_SZ || m_bk_hdr.magic != BK_HDR_MAGIC)
|
||||||
m_bk_hdr.magic != Common::swap32(BK_HDR_MAGIC))
|
|
||||||
{
|
{
|
||||||
ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", m_bk_hdr.size, m_bk_hdr.magic);
|
ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", u32(m_bk_hdr.size),
|
||||||
|
u32(m_bk_hdr.magic));
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_files_list_size = Common::swap32(m_bk_hdr.numberOfFiles);
|
if (m_bk_hdr.size_of_files + FULL_CERT_SZ != m_bk_hdr.total_size)
|
||||||
m_size_of_files = Common::swap32(m_bk_hdr.sizeOfFiles);
|
|
||||||
m_total_size = Common::swap32(m_bk_hdr.totalSize);
|
|
||||||
|
|
||||||
if (m_size_of_files + FULL_CERT_SZ != m_total_size)
|
|
||||||
{
|
{
|
||||||
WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", m_size_of_files,
|
WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)",
|
||||||
FULL_CERT_SZ, m_total_size);
|
u32(m_bk_hdr.size_of_files), FULL_CERT_SZ, u32(m_bk_hdr.total_size));
|
||||||
}
|
}
|
||||||
if (m_title_id != Common::swap64(m_bk_hdr.SaveGameTitle))
|
if (m_title_id != m_bk_hdr.save_game_title)
|
||||||
{
|
{
|
||||||
WARN_LOG(CONSOLE,
|
WARN_LOG(CONSOLE,
|
||||||
"Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")",
|
"Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")",
|
||||||
m_title_id, Common::swap64(m_bk_hdr.SaveGameTitle));
|
m_title_id, u64(m_bk_hdr.save_game_title));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::WriteBKHDR()
|
void WiiSave::WriteBKHDR()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
m_files_list_size = 0;
|
u32 number_of_files = 0, size_of_files = 0;
|
||||||
m_size_of_files = 0;
|
ScanForFiles(m_wii_title_path, m_files_list, &number_of_files, &size_of_files);
|
||||||
|
|
||||||
ScanForFiles(m_wii_title_path, m_files_list, &m_files_list_size, &m_size_of_files);
|
|
||||||
memset(&m_bk_hdr, 0, BK_SZ);
|
memset(&m_bk_hdr, 0, BK_SZ);
|
||||||
m_bk_hdr.size = Common::swap32(BK_LISTED_SZ);
|
m_bk_hdr.size = BK_LISTED_SZ;
|
||||||
m_bk_hdr.magic = Common::swap32(BK_HDR_MAGIC);
|
m_bk_hdr.magic = BK_HDR_MAGIC;
|
||||||
m_bk_hdr.NGid = s_ng_id;
|
m_bk_hdr.ngid = s_ng_id;
|
||||||
m_bk_hdr.numberOfFiles = Common::swap32(m_files_list_size);
|
m_bk_hdr.number_of_files = number_of_files;
|
||||||
m_bk_hdr.sizeOfFiles = Common::swap32(m_size_of_files);
|
m_bk_hdr.size_of_files = size_of_files;
|
||||||
m_bk_hdr.totalSize = Common::swap32(m_size_of_files + FULL_CERT_SZ);
|
m_bk_hdr.total_size = size_of_files + FULL_CERT_SZ;
|
||||||
m_bk_hdr.SaveGameTitle = Common::swap64(m_title_id);
|
m_bk_hdr.save_game_title = m_title_id;
|
||||||
|
|
||||||
File::IOFile data_file(m_encrypted_save_path, "ab");
|
File::IOFile data_file(m_encrypted_save_path, "ab");
|
||||||
if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ))
|
if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ))
|
||||||
@ -307,7 +289,7 @@ void CWiiSaveCrypted::WriteBKHDR()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::ImportWiiSaveFiles()
|
void WiiSave::ImportWiiSaveFiles()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
@ -324,11 +306,10 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
|||||||
|
|
||||||
FileHDR file_hdr_tmp;
|
FileHDR file_hdr_tmp;
|
||||||
|
|
||||||
for (u32 i = 0; i < m_files_list_size; ++i)
|
for (u32 i = 0; i < m_bk_hdr.number_of_files; ++i)
|
||||||
{
|
{
|
||||||
memset(&file_hdr_tmp, 0, FILE_HDR_SZ);
|
memset(&file_hdr_tmp, 0, FILE_HDR_SZ);
|
||||||
memset(m_iv, 0, 0x10);
|
m_iv.fill(0);
|
||||||
u32 file_size = 0;
|
|
||||||
|
|
||||||
if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ))
|
if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ))
|
||||||
{
|
{
|
||||||
@ -336,7 +317,7 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
|||||||
m_valid = false;
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Common::swap32(file_hdr_tmp.magic) != FILE_HDR_MAGIC)
|
if (file_hdr_tmp.magic != FILE_HDR_MAGIC)
|
||||||
{
|
{
|
||||||
ERROR_LOG(CONSOLE, "Bad File Header");
|
ERROR_LOG(CONSOLE, "Bad File Header");
|
||||||
break;
|
break;
|
||||||
@ -345,15 +326,14 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
|||||||
{
|
{
|
||||||
// Allows files in subfolders to be escaped properly (ex: "nocopy/data00")
|
// Allows files in subfolders to be escaped properly (ex: "nocopy/data00")
|
||||||
// Special characters in path components will be escaped such as /../
|
// Special characters in path components will be escaped such as /../
|
||||||
std::string file_path = Common::EscapePath(reinterpret_cast<const char*>(file_hdr_tmp.name));
|
std::string file_path = Common::EscapePath(file_hdr_tmp.name.data());
|
||||||
|
|
||||||
std::string file_path_full = m_wii_title_path + '/' + file_path;
|
std::string file_path_full = m_wii_title_path + '/' + file_path;
|
||||||
File::CreateFullPath(file_path_full);
|
File::CreateFullPath(file_path_full);
|
||||||
const File::FileInfo file_info(file_path_full);
|
const File::FileInfo file_info(file_path_full);
|
||||||
if (file_hdr_tmp.type == 1)
|
if (file_hdr_tmp.type == 1)
|
||||||
{
|
{
|
||||||
file_size = Common::swap32(file_hdr_tmp.size);
|
u32 file_size_rounded = Common::AlignUp<u32>(file_hdr_tmp.size, BLOCK_SZ);
|
||||||
u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ);
|
|
||||||
std::vector<u8> file_data(file_size_rounded);
|
std::vector<u8> file_data(file_size_rounded);
|
||||||
std::vector<u8> file_data_enc(file_size_rounded);
|
std::vector<u8> file_data_enc(file_size_rounded);
|
||||||
|
|
||||||
@ -364,14 +344,14 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_iv, file_hdr_tmp.IV, 0x10);
|
m_iv = file_hdr_tmp.iv;
|
||||||
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv,
|
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv.data(),
|
||||||
static_cast<const u8*>(file_data_enc.data()), file_data.data());
|
static_cast<const u8*>(file_data_enc.data()), file_data.data());
|
||||||
|
|
||||||
INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str());
|
INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str());
|
||||||
|
|
||||||
File::IOFile raw_save_file(file_path_full, "wb");
|
File::IOFile raw_save_file(file_path_full, "wb");
|
||||||
raw_save_file.WriteBytes(file_data.data(), file_size);
|
raw_save_file.WriteBytes(file_data.data(), file_hdr_tmp.size);
|
||||||
}
|
}
|
||||||
else if (file_hdr_tmp.type == 2)
|
else if (file_hdr_tmp.type == 2)
|
||||||
{
|
{
|
||||||
@ -391,12 +371,12 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::ExportWiiSaveFiles()
|
void WiiSave::ExportWiiSaveFiles()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (u32 i = 0; i < m_files_list_size; i++)
|
for (u32 i = 0; i < m_bk_hdr.number_of_files; i++)
|
||||||
{
|
{
|
||||||
FileHDR file_hdr_tmp;
|
FileHDR file_hdr_tmp;
|
||||||
memset(&file_hdr_tmp, 0, FILE_HDR_SZ);
|
memset(&file_hdr_tmp, 0, FILE_HDR_SZ);
|
||||||
@ -414,9 +394,9 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ);
|
u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ);
|
||||||
file_hdr_tmp.magic = Common::swap32(FILE_HDR_MAGIC);
|
file_hdr_tmp.magic = FILE_HDR_MAGIC;
|
||||||
file_hdr_tmp.size = Common::swap32(file_size);
|
file_hdr_tmp.size = file_size;
|
||||||
file_hdr_tmp.Permissions = 0x3c;
|
file_hdr_tmp.permissions = 0x3c;
|
||||||
|
|
||||||
std::string name =
|
std::string name =
|
||||||
Common::UnescapeFileName(m_files_list[i].substr(m_wii_title_path.length() + 1));
|
Common::UnescapeFileName(m_files_list[i].substr(m_wii_title_path.length() + 1));
|
||||||
@ -428,7 +408,7 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
|||||||
m_valid = false;
|
m_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strncpy((char*)file_hdr_tmp.name, name.c_str(), sizeof(file_hdr_tmp.name));
|
std::strncpy(file_hdr_tmp.name.data(), name.c_str(), file_hdr_tmp.name.size());
|
||||||
|
|
||||||
{
|
{
|
||||||
File::IOFile fpData_bin(m_encrypted_save_path, "ab");
|
File::IOFile fpData_bin(m_encrypted_save_path, "ab");
|
||||||
@ -459,8 +439,9 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
|||||||
m_valid = false;
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, file_hdr_tmp.IV,
|
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded,
|
||||||
static_cast<const u8*>(file_data.data()), file_data_enc.data());
|
file_hdr_tmp.iv.data(), static_cast<const u8*>(file_data.data()),
|
||||||
|
file_data_enc.data());
|
||||||
|
|
||||||
File::IOFile fpData_bin(m_encrypted_save_path, "ab");
|
File::IOFile fpData_bin(m_encrypted_save_path, "ab");
|
||||||
if (!fpData_bin.WriteBytes(file_data_enc.data(), file_size_rounded))
|
if (!fpData_bin.WriteBytes(file_data_enc.data(), file_size_rounded))
|
||||||
@ -471,7 +452,7 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::do_sig()
|
void WiiSave::do_sig()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
@ -514,7 +495,7 @@ void CWiiSaveCrypted::do_sig()
|
|||||||
generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash);
|
generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash);
|
||||||
make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0);
|
make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0);
|
||||||
|
|
||||||
data_size = Common::swap32(m_bk_hdr.sizeOfFiles) + 0x80;
|
data_size = m_bk_hdr.size_of_files + 0x80;
|
||||||
|
|
||||||
File::IOFile data_file(m_encrypted_save_path, "rb");
|
File::IOFile data_file(m_encrypted_save_path, "rb");
|
||||||
if (!data_file)
|
if (!data_file)
|
||||||
@ -550,7 +531,7 @@ void CWiiSaveCrypted::do_sig()
|
|||||||
m_valid = data_file.IsGood();
|
m_valid = data_file.IsGood();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name,
|
void WiiSave::make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name,
|
||||||
const u8* priv, const u32 key_id)
|
const u8* priv, const u32 key_id)
|
||||||
{
|
{
|
||||||
memset(cert, 0, 0x180);
|
memset(cert, 0, 0x180);
|
||||||
@ -564,7 +545,7 @@ void CWiiSaveCrypted::make_ec_cert(u8* cert, const u8* sig, const char* signer,
|
|||||||
ec_priv_to_pub(priv, cert + 0x108);
|
ec_priv_to_pub(priv, cert + 0x108);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWiiSaveCrypted::getPaths(bool for_export)
|
bool WiiSave::getPaths(bool for_export)
|
||||||
{
|
{
|
||||||
if (m_title_id)
|
if (m_title_id)
|
||||||
{
|
{
|
||||||
@ -591,12 +572,7 @@ bool CWiiSaveCrypted::getPaths(bool for_export)
|
|||||||
ERROR_LOG(CONSOLE, "No banner file found for title %s", game_id);
|
ERROR_LOG(CONSOLE, "No banner file found for title %s", game_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_encrypted_save_path.length() == 0)
|
m_encrypted_save_path += StringFromFormat("/private/wii/title/%s/data.bin", game_id);
|
||||||
{
|
|
||||||
// If no path was passed, use User folder
|
|
||||||
m_encrypted_save_path = File::GetUserPath(D_USER_IDX);
|
|
||||||
}
|
|
||||||
m_encrypted_save_path += StringFromFormat("private/wii/title/%s/data.bin", game_id);
|
|
||||||
File::CreateFullPath(m_encrypted_save_path);
|
File::CreateFullPath(m_encrypted_save_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -606,9 +582,8 @@ bool CWiiSaveCrypted::getPaths(bool for_export)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory,
|
void WiiSave::ScanForFiles(const std::string& save_directory, std::vector<std::string>& file_list,
|
||||||
std::vector<std::string>& file_list, u32* num_files,
|
u32* num_files, u32* size_files)
|
||||||
u32* size_files)
|
|
||||||
{
|
{
|
||||||
std::vector<std::string> directories;
|
std::vector<std::string> directories;
|
||||||
directories.push_back(save_directory);
|
directories.push_back(save_directory);
|
||||||
@ -653,6 +628,6 @@ void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory,
|
|||||||
*size_files = size;
|
*size_files = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWiiSaveCrypted::~CWiiSaveCrypted()
|
WiiSave::~WiiSave()
|
||||||
{
|
{
|
||||||
}
|
}
|
135
Source/Core/Core/HW/WiiSave.h
Normal file
135
Source/Core/Core/HW/WiiSave.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// Copyright 2010 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <mbedtls/aes.h>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Swap.h"
|
||||||
|
|
||||||
|
class WiiSave
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Import a save into the NAND from a .bin file.
|
||||||
|
static bool Import(std::string filename);
|
||||||
|
/// Export a save to a .bin file.
|
||||||
|
static bool Export(u64 title_id, std::string export_path);
|
||||||
|
/// Export all saves that are in the NAND. Returns the number of exported saves.
|
||||||
|
static size_t ExportAll(std::string export_path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit WiiSave(std::string filename);
|
||||||
|
explicit WiiSave(u64 title_id, std::string export_path);
|
||||||
|
~WiiSave();
|
||||||
|
|
||||||
|
bool Import();
|
||||||
|
bool Export();
|
||||||
|
|
||||||
|
void ReadHDR();
|
||||||
|
void ReadBKHDR();
|
||||||
|
void WriteHDR();
|
||||||
|
void WriteBKHDR();
|
||||||
|
void ImportWiiSaveFiles();
|
||||||
|
void ExportWiiSaveFiles();
|
||||||
|
void do_sig();
|
||||||
|
void make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, const u8* priv,
|
||||||
|
const u32 key_id);
|
||||||
|
bool getPaths(bool for_export = false);
|
||||||
|
void ScanForFiles(const std::string& save_directory, std::vector<std::string>& file_list,
|
||||||
|
u32* num_files, u32* size_files);
|
||||||
|
|
||||||
|
mbedtls_aes_context m_aes_ctx;
|
||||||
|
std::array<u8, 0x10> m_sd_iv;
|
||||||
|
std::vector<std::string> m_files_list;
|
||||||
|
|
||||||
|
std::string m_encrypted_save_path;
|
||||||
|
|
||||||
|
std::string m_wii_title_path;
|
||||||
|
|
||||||
|
std::array<u8, 0x10> m_iv;
|
||||||
|
|
||||||
|
u64 m_title_id;
|
||||||
|
|
||||||
|
bool m_valid;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BLOCK_SZ = 0x40,
|
||||||
|
HDR_SZ = 0x20,
|
||||||
|
ICON_SZ = 0x1200,
|
||||||
|
BNR_SZ = 0x60a0,
|
||||||
|
FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ
|
||||||
|
FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ
|
||||||
|
HEADER_SZ = 0xF0C0, // HDR_SZ + FULL_BNR_MAX
|
||||||
|
BK_LISTED_SZ = 0x70, // Size before rounding to nearest block
|
||||||
|
BK_SZ = 0x80,
|
||||||
|
FILE_HDR_SZ = 0x80,
|
||||||
|
|
||||||
|
SIG_SZ = 0x40,
|
||||||
|
NG_CERT_SZ = 0x180,
|
||||||
|
AP_CERT_SZ = 0x180,
|
||||||
|
FULL_CERT_SZ = 0x3C0, // SIG_SZ + NG_CERT_SZ + AP_CERT_SZ + 0x80?
|
||||||
|
|
||||||
|
BK_HDR_MAGIC = 0x426B0001,
|
||||||
|
FILE_HDR_MAGIC = 0x03adf17e
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct DataBinHeader // encrypted
|
||||||
|
{
|
||||||
|
Common::BigEndianValue<u64> save_game_title;
|
||||||
|
Common::BigEndianValue<u32> banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0)
|
||||||
|
u8 permissions;
|
||||||
|
u8 unk1; // maybe permissions is a be16
|
||||||
|
std::array<u8, 0x10> md5; // md5 of plaintext header with md5 blanker applied
|
||||||
|
Common::BigEndianValue<u16> unk2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Header
|
||||||
|
{
|
||||||
|
DataBinHeader hdr;
|
||||||
|
u8 banner[FULL_BNR_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BkHeader // Not encrypted
|
||||||
|
{
|
||||||
|
Common::BigEndianValue<u32> size; // 0x00000070
|
||||||
|
// u16 magic; // 'Bk'
|
||||||
|
// u16 magic2; // or version (0x0001)
|
||||||
|
Common::BigEndianValue<u32> magic; // 0x426B0001
|
||||||
|
Common::BigEndianValue<u32> ngid;
|
||||||
|
Common::BigEndianValue<u32> number_of_files;
|
||||||
|
Common::BigEndianValue<u32> size_of_files;
|
||||||
|
Common::BigEndianValue<u32> unk1;
|
||||||
|
Common::BigEndianValue<u32> unk2;
|
||||||
|
Common::BigEndianValue<u32> total_size;
|
||||||
|
std::array<u8, 64> unk3;
|
||||||
|
Common::BigEndianValue<u64> save_game_title;
|
||||||
|
std::array<u8, 6> mac_address;
|
||||||
|
std::array<u8, 0x12> padding;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileHDR // encrypted
|
||||||
|
{
|
||||||
|
Common::BigEndianValue<u32> magic; // 0x03adf17e
|
||||||
|
Common::BigEndianValue<u32> size;
|
||||||
|
u8 permissions;
|
||||||
|
u8 attrib;
|
||||||
|
u8 type; // (1=file, 2=directory)
|
||||||
|
std::array<char, 0x45> name;
|
||||||
|
std::array<u8, 0x10> iv;
|
||||||
|
std::array<u8, 0x20> unk;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
Header m_header;
|
||||||
|
Header m_encrypted_header;
|
||||||
|
BkHeader m_bk_hdr;
|
||||||
|
};
|
@ -1,133 +0,0 @@
|
|||||||
// Copyright 2010 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <mbedtls/aes.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
|
|
||||||
class CWiiSaveCrypted
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool static ImportWiiSave(const std::string& filename);
|
|
||||||
bool static ExportWiiSave(u64 title_id);
|
|
||||||
void static ExportAllSaves();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CWiiSaveCrypted(const std::string& filename, u64 title_id = 0);
|
|
||||||
~CWiiSaveCrypted();
|
|
||||||
void ReadHDR();
|
|
||||||
void ReadBKHDR();
|
|
||||||
void WriteHDR();
|
|
||||||
void WriteBKHDR();
|
|
||||||
void Extract() {}
|
|
||||||
void ImportWiiSaveFiles();
|
|
||||||
void ExportWiiSaveFiles();
|
|
||||||
void do_sig();
|
|
||||||
void make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, const u8* priv,
|
|
||||||
const u32 key_id);
|
|
||||||
bool getPaths(bool for_export = false);
|
|
||||||
void ScanForFiles(const std::string& save_directory, std::vector<std::string>& file_list,
|
|
||||||
u32* num_files, u32* size_files);
|
|
||||||
|
|
||||||
static const u8 s_sd_key[16];
|
|
||||||
static const u8 s_md5_blanker[16];
|
|
||||||
static const u32 s_ng_id;
|
|
||||||
|
|
||||||
mbedtls_aes_context m_aes_ctx;
|
|
||||||
u8 m_sd_iv[0x10];
|
|
||||||
std::vector<std::string> m_files_list;
|
|
||||||
|
|
||||||
std::string m_encrypted_save_path;
|
|
||||||
|
|
||||||
std::string m_wii_title_path;
|
|
||||||
|
|
||||||
u8 m_iv[0x10];
|
|
||||||
|
|
||||||
u32 m_files_list_size;
|
|
||||||
u32 m_size_of_files;
|
|
||||||
u32 m_total_size;
|
|
||||||
|
|
||||||
u64 m_title_id;
|
|
||||||
|
|
||||||
bool m_valid;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
BLOCK_SZ = 0x40,
|
|
||||||
HDR_SZ = 0x20,
|
|
||||||
ICON_SZ = 0x1200,
|
|
||||||
BNR_SZ = 0x60a0,
|
|
||||||
FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ
|
|
||||||
FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ
|
|
||||||
HEADER_SZ = 0xF0C0, // HDR_SZ + FULL_BNR_MAX
|
|
||||||
BK_LISTED_SZ = 0x70, // Size before rounding to nearest block
|
|
||||||
BK_SZ = 0x80,
|
|
||||||
FILE_HDR_SZ = 0x80,
|
|
||||||
|
|
||||||
SIG_SZ = 0x40,
|
|
||||||
NG_CERT_SZ = 0x180,
|
|
||||||
AP_CERT_SZ = 0x180,
|
|
||||||
FULL_CERT_SZ = 0x3C0, // SIG_SZ + NG_CERT_SZ + AP_CERT_SZ + 0x80?
|
|
||||||
|
|
||||||
BK_HDR_MAGIC = 0x426B0001,
|
|
||||||
FILE_HDR_MAGIC = 0x03adf17e
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
struct Data_Bin_HDR // encrypted
|
|
||||||
{
|
|
||||||
u64 SaveGameTitle;
|
|
||||||
u32 BannerSize; // (0x72A0 or 0xF0A0, also seen 0xBAA0)
|
|
||||||
u8 Permissions;
|
|
||||||
u8 unk1; // maybe permissions is a be16
|
|
||||||
u8 Md5[0x10]; // md5 of plaintext header with md5 blanker applied
|
|
||||||
u16 unk2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HEADER
|
|
||||||
{
|
|
||||||
Data_Bin_HDR hdr;
|
|
||||||
u8 BNR[FULL_BNR_MAX];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BK_Header // Not encrypted
|
|
||||||
{
|
|
||||||
u32 size; // 0x00000070
|
|
||||||
// u16 magic; // 'Bk'
|
|
||||||
// u16 magic2; // or version (0x0001)
|
|
||||||
u32 magic; // 0x426B0001
|
|
||||||
u32 NGid;
|
|
||||||
u32 numberOfFiles;
|
|
||||||
u32 sizeOfFiles;
|
|
||||||
u32 unk1;
|
|
||||||
u32 unk2;
|
|
||||||
u32 totalSize;
|
|
||||||
u8 unk3[64];
|
|
||||||
u64 SaveGameTitle;
|
|
||||||
u8 MACaddress[6];
|
|
||||||
u8 padding[0x12];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileHDR // encrypted
|
|
||||||
{
|
|
||||||
u32 magic; // 0x03adf17e
|
|
||||||
u32 size;
|
|
||||||
u8 Permissions;
|
|
||||||
u8 attrib;
|
|
||||||
u8 type; // (1=file, 2=directory)
|
|
||||||
u8 name[0x45];
|
|
||||||
u8 IV[0x10];
|
|
||||||
u8 unk[0x20];
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
HEADER m_header;
|
|
||||||
HEADER m_encrypted_header;
|
|
||||||
BK_Header m_bk_hdr;
|
|
||||||
};
|
|
@ -20,7 +20,7 @@
|
|||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/HW/DVD/DVDInterface.h"
|
#include "Core/HW/DVD/DVDInterface.h"
|
||||||
#include "Core/HW/WiiSaveCrypted.h"
|
#include "Core/HW/WiiSave.h"
|
||||||
#include "Core/WiiUtils.h"
|
#include "Core/WiiUtils.h"
|
||||||
#include "DiscIO/Blob.h"
|
#include "DiscIO/Blob.h"
|
||||||
#include "DiscIO/Enums.h"
|
#include "DiscIO/Enums.h"
|
||||||
@ -258,14 +258,16 @@ void GameList::OpenProperties()
|
|||||||
|
|
||||||
void GameList::ExportWiiSave()
|
void GameList::ExportWiiSave()
|
||||||
{
|
{
|
||||||
QMessageBox result_dialog(this);
|
const QString export_dir = QFileDialog::getExistingDirectory(
|
||||||
|
this, tr("Select Export Directory"), QString::fromStdString(File::GetUserPath(D_USER_IDX)),
|
||||||
|
QFileDialog::ShowDirsOnly);
|
||||||
|
if (export_dir.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
const bool success = CWiiSaveCrypted::ExportWiiSave(GetSelectedGame()->GetTitleID());
|
if (WiiSave::Export(GetSelectedGame()->GetTitleID(), export_dir.toStdString()))
|
||||||
|
QMessageBox::information(this, tr("Save Export"), tr("Successfully exported save files"));
|
||||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
else
|
||||||
result_dialog.setText(success ? tr("Successfully exported save files") :
|
QMessageBox::critical(this, tr("Save Export"), tr("Failed to export save files."));
|
||||||
tr("Failed to export save files!"));
|
|
||||||
result_dialog.exec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::OpenWiki()
|
void GameList::OpenWiki()
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/Debugger/RSO.h"
|
#include "Core/Debugger/RSO.h"
|
||||||
#include "Core/HLE/HLE.h"
|
#include "Core/HLE/HLE.h"
|
||||||
#include "Core/HW/WiiSaveCrypted.h"
|
#include "Core/HW/WiiSave.h"
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
#include "Core/IOS/ES/ES.h"
|
#include "Core/IOS/ES/ES.h"
|
||||||
@ -896,13 +896,26 @@ void MenuBar::ImportWiiSave()
|
|||||||
tr("Wii save files (*.bin);;"
|
tr("Wii save files (*.bin);;"
|
||||||
"All Files (*)"));
|
"All Files (*)"));
|
||||||
|
|
||||||
if (!file.isEmpty())
|
if (file.isEmpty())
|
||||||
CWiiSaveCrypted::ImportWiiSave(file.toStdString());
|
return;
|
||||||
|
|
||||||
|
if (WiiSave::Import(file.toStdString()))
|
||||||
|
QMessageBox::information(this, tr("Save Import"), tr("Successfully imported save files."));
|
||||||
|
else
|
||||||
|
QMessageBox::critical(this, tr("Save Import"), tr("Failed to import save files."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuBar::ExportWiiSaves()
|
void MenuBar::ExportWiiSaves()
|
||||||
{
|
{
|
||||||
CWiiSaveCrypted::ExportAllSaves();
|
const QString export_dir = QFileDialog::getExistingDirectory(
|
||||||
|
this, tr("Select Export Directory"), QString::fromStdString(File::GetUserPath(D_USER_IDX)),
|
||||||
|
QFileDialog::ShowDirsOnly);
|
||||||
|
if (export_dir.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const size_t count = WiiSave::ExportAll(export_dir.toStdString());
|
||||||
|
QMessageBox::information(this, tr("Save Export"),
|
||||||
|
tr("Exported %n save(s)", "", static_cast<int>(count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuBar::CheckNAND()
|
void MenuBar::CheckNAND()
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#include "Core/HW/GCPad.h"
|
#include "Core/HW/GCPad.h"
|
||||||
#include "Core/HW/ProcessorInterface.h"
|
#include "Core/HW/ProcessorInterface.h"
|
||||||
#include "Core/HW/SI/SI_Device.h"
|
#include "Core/HW/SI/SI_Device.h"
|
||||||
#include "Core/HW/WiiSaveCrypted.h"
|
#include "Core/HW/WiiSave.h"
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
#include "Core/HotkeyManager.h"
|
#include "Core/HotkeyManager.h"
|
||||||
@ -1204,7 +1204,7 @@ void CFrame::OnLoadGameCubeIPLEUR(wxCommandEvent&)
|
|||||||
|
|
||||||
void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED(event))
|
void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED(event))
|
||||||
{
|
{
|
||||||
CWiiSaveCrypted::ExportAllSaves();
|
WiiSave::ExportAll(File::GetUserPath(D_USER_IDX));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event))
|
void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event))
|
||||||
@ -1215,7 +1215,7 @@ void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event))
|
|||||||
wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this);
|
wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this);
|
||||||
|
|
||||||
if (!path.IsEmpty())
|
if (!path.IsEmpty())
|
||||||
CWiiSaveCrypted::ImportWiiSave(WxStrToStr(path));
|
WiiSave::Import(WxStrToStr(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event))
|
void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event))
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/HW/DVD/DVDInterface.h"
|
#include "Core/HW/DVD/DVDInterface.h"
|
||||||
#include "Core/HW/WiiSaveCrypted.h"
|
#include "Core/HW/WiiSave.h"
|
||||||
#include "Core/Movie.h"
|
#include "Core/Movie.h"
|
||||||
#include "Core/SysConf.h"
|
#include "Core/SysConf.h"
|
||||||
#include "Core/TitleDatabase.h"
|
#include "Core/TitleDatabase.h"
|
||||||
@ -988,7 +988,7 @@ void GameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED(event))
|
|||||||
{
|
{
|
||||||
const UICommon::GameFile* iso = GetSelectedISO();
|
const UICommon::GameFile* iso = GetSelectedISO();
|
||||||
if (iso)
|
if (iso)
|
||||||
CWiiSaveCrypted::ExportWiiSave(iso->GetTitleID());
|
WiiSave::Export(iso->GetTitleID(), File::GetUserPath(D_USER_IDX));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save this file as the default file
|
// Save this file as the default file
|
||||||
|
Reference in New Issue
Block a user