From f95bcfc1c24d60327178abddfc93d62bebea08c0 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Mon, 27 Jun 2011 06:19:23 +0000 Subject: [PATCH] Wii Save Export can now successfully create data.bin files that the wii will accept as long as the user has their wii's private keys. requires NG-id, NG-key-id, NG-priv, NG-sig sorry for not fixing this sooner, I forgot that I cleared my wiis private keys before the initial commit git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7642 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Src/MemoryCards/WiiSaveCrypted.cpp | 148 ++++++++++-------- .../Src/MemoryCards/WiiSaveCrypted.h | 21 ++- 2 files changed, 95 insertions(+), 74 deletions(-) diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp index 73b94e9419..43f4c63367 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp @@ -33,18 +33,16 @@ const u8 SDKey[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, const u8 MD5_BLANKER[0x10] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; -CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 title) - : _saveGameTitle(title) +CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 TitleID) + : m_TitleID(TitleID) { Common::ReadReplacements(replacements); strcpy(pathData_bin, FileName); memcpy(SD_IV, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); - if (!title) + if (!TitleID) // Import { - AES_set_decrypt_key(SDKey, 128, &m_AES_KEY); - - + AES_set_decrypt_key(SDKey, 128, &m_AES_KEY); do { b_valid = true; @@ -66,12 +64,39 @@ CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 title) if (getPaths(true)) { + memset(&keys, 0, sizeof(_keys)); + std::string keysdir = File::GetSysDirectory() + "/Wii/"; + std::string NG_id = keysdir + "NG-id"; + std::string NG_key_id = keysdir + "NG-key-id"; + std::string NG_priv = keysdir + "NG-priv"; + std::string NG_sig = keysdir + "NG-sig"; + if (!File::Exists(NG_id) || !File::Exists(NG_key_id) || + !File::Exists(NG_priv) ||!File::Exists(NG_sig)) + { + if (!AskYesNoT("Wii Private Keys not found, the exported save will only work with dolphin\n Continue?")) + { + PanicAlertT("Key files not found, save will not copy to wii\nPlace NG-id, NG-key-id, NG-priv, and NG-sig in the folder\n%s", keysdir.c_str()); + return; + } + } + else + { + File::IOFile fp_key(NG_id, "rb"); + fp_key.ReadBytes(keys.NG_id, 4); + fp_key.Open(NG_key_id, "rb"); + fp_key.ReadBytes(keys.NG_key_id, 4); + fp_key.Open(NG_priv, "rb"); + fp_key.ReadBytes(keys.NG_priv, 30); + fp_key.Open(NG_sig, "rb"); + fp_key.ReadBytes(keys.NG_sig, 60); + } + do { b_valid = true; WriteHDR(); WriteBKHDR(); - ExportWiiSaveFiles(); + ExportWiiSaveFiles(); do_sig(); if (b_valid) { @@ -110,7 +135,7 @@ void CWiiSaveCrypted::ReadHDR() b_valid = false; return; } - _saveGameTitle = Common::swap64(_header.hdr.SaveGameTitle); + m_TitleID = Common::swap64(_header.hdr.SaveGameTitle); memcpy(md5_file, _header.hdr.Md5, 0x10); memcpy(_header.hdr.Md5, MD5_BLANKER, 0x10); @@ -126,10 +151,10 @@ void CWiiSaveCrypted::ReadHDR() b_valid = false; return; } - if (!File::Exists(pathBanner_bin) || AskYesNoT("%s already exists, overwrite?", pathBanner_bin)) + if (!File::Exists(BannerFilePath) || AskYesNoT("%s already exists, overwrite?", BannerFilePath.c_str())) { - INFO_LOG(CONSOLE, "creating file %s", pathBanner_bin); - File::IOFile fpBanner_bin(pathBanner_bin, "wb"); + INFO_LOG(CONSOLE, "creating file %s", BannerFilePath.c_str()); + File::IOFile fpBanner_bin(BannerFilePath, "wb"); fpBanner_bin.WriteBytes(_header.BNR, _bannerSize); } } @@ -139,14 +164,15 @@ void CWiiSaveCrypted::WriteHDR() if (!b_valid) return; memset(&_header, 0, HEADER_SZ); - _header.hdr.BannerSize = Common::swap32(File::GetSize(pathBanner_bin)); + u32 bannerSize = File::GetSize(BannerFilePath); + _header.hdr.BannerSize = Common::swap32(bannerSize); - _header.hdr.SaveGameTitle = Common::swap64(_saveGameTitle); + _header.hdr.SaveGameTitle = Common::swap64(m_TitleID); memcpy(_header.hdr.Md5, MD5_BLANKER, 0x10); - _header.hdr.Permissions = 0x3C;//0x35; + _header.hdr.Permissions = 0x35; - File::IOFile fpBanner_bin(pathBanner_bin, "rb"); - if (!fpBanner_bin.ReadBytes(_header.BNR, Common::swap32(_header.hdr.BannerSize))) + File::IOFile fpBanner_bin(BannerFilePath, "rb"); + if (!fpBanner_bin.ReadBytes(_header.BNR, bannerSize)) { PanicAlertT("Failed to read banner.bin"); b_valid = false; @@ -202,8 +228,8 @@ void CWiiSaveCrypted::ReadBKHDR() if (_sizeOfFiles + FULL_CERT_SZ != _totalSize) WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", _sizeOfFiles, FULL_CERT_SZ, _totalSize); - if (_saveGameTitle != Common::swap64(bkhdr.SaveGameTitle)) - WARN_LOG(CONSOLE, "encrypted title (%llx) does not match unencrypted title (%llx)", _saveGameTitle, Common::swap64(bkhdr.SaveGameTitle)); + if (m_TitleID != Common::swap64(bkhdr.SaveGameTitle)) + WARN_LOG(CONSOLE, "encrypted title (%llx) does not match unencrypted title (%llx)", m_TitleID, Common::swap64(bkhdr.SaveGameTitle)); } void CWiiSaveCrypted::WriteBKHDR() @@ -212,21 +238,15 @@ void CWiiSaveCrypted::WriteBKHDR() _numberOfFiles = 0; _sizeOfFiles = 0; - ScanForFiles(pathSavedir, FilesList, &_numberOfFiles, &_sizeOfFiles); + ScanForFiles(WiiTitlePath, FilesList, &_numberOfFiles, &_sizeOfFiles); memset(&bkhdr, 0, BK_SZ); bkhdr.size = Common::swap32(BK_LISTED_SZ); bkhdr.magic = Common::swap32(BK_HDR_MAGIC); -//customize this - bkhdr.NGid = Common::swap32(1); -// + bkhdr.NGid = *(u32*)(keys.NG_id); bkhdr.numberOfFiles = Common::swap32(_numberOfFiles); bkhdr.sizeOfFiles = Common::swap32(_sizeOfFiles); bkhdr.totalSize = Common::swap32(_sizeOfFiles + FULL_CERT_SZ); - bkhdr.SaveGameTitle = Common::swap64(_saveGameTitle); -// customize this - const u8 MAC[6] = {0}; -// - memcpy(bkhdr.MACaddress, MAC, 6); + bkhdr.SaveGameTitle = Common::swap64(m_TitleID); File::IOFile fpData_bin(pathData_bin, "ab"); if (!fpData_bin.WriteBytes(&bkhdr, BK_SZ)) @@ -279,8 +299,8 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() fileName.replace(j, 1, iter->second); } - sprintf(pathRawSave, "%s%s", pathSavedir, fileName.c_str()); - File::CreateFullPath(pathRawSave); + std::string fullFilePath = WiiTitlePath + fileName; + File::CreateFullPath(fullFilePath); if (_tmpFileHDR.type == 1) { _fileSize = Common::swap32(_tmpFileHDR.size); @@ -299,11 +319,11 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() AES_cbc_encrypt((const unsigned char *)_encryptedData, _data, RoundedFileSize, &m_AES_KEY, IV, AES_DECRYPT); delete []_encryptedData; - if (!File::Exists(pathRawSave) || AskYesNoT("%s already exists, overwrite?", pathRawSave)) + if (!File::Exists(fullFilePath) || AskYesNoT("%s already exists, overwrite?", fullFilePath.c_str())) { - INFO_LOG(CONSOLE, "creating file %s", pathRawSave); + INFO_LOG(CONSOLE, "creating file %s", fullFilePath.c_str()); - File::IOFile fpRawSaveFile(pathRawSave, "wb"); + File::IOFile fpRawSaveFile(fullFilePath, "wb"); fpRawSaveFile.WriteBytes(_data, _fileSize); } delete []_data; @@ -330,7 +350,7 @@ void CWiiSaveCrypted::ExportWiiSaveFiles() tmpFileHDR.magic = Common::swap32(FILE_HDR_MAGIC); tmpFileHDR.size = Common::swap32(_fileSize); - tmpFileHDR.Permissions = 0x3C; + tmpFileHDR.Permissions = 0x35; tmpFileHDR.type = File::IsDirectory(FilesList[i]) ? 2 : 1; SplitPath(FilesList[i], NULL, &__name, &__ext); @@ -342,8 +362,6 @@ void CWiiSaveCrypted::ExportWiiSaveFiles() for (size_t j = 0; (j = __name.find(iter->second, j)) != __name.npos; ++j) { - /*std::string tmp = __name.substr(0, j) + iter->first +__name.substr(j+iter->second.length(), __name.length()); - __name = tmp;*/ __name.replace(j, iter->second.length(), 1, iter->first); } } @@ -409,16 +427,10 @@ void CWiiSaveCrypted::do_sig() char name[64]; u8 *data; u32 data_size; -//allow customization - u32 ng_id = Common::swap32(1); - u32 ng_key_id = Common::swap32(2); - u8 ng_sig[0x3C] = {0}; - u8 ng_priv[0x1E] = {0}; -//allow customization sprintf(signer, "Root-CA00000001-MS00000002"); - sprintf(name, "NG%08x", ng_id); - make_ec_cert(ng_cert, ng_sig, signer, name, ng_priv, ng_key_id); + sprintf(name, "NG%08x", Common::swap32(keys.NG_id)); + make_ec_cert(ng_cert, keys.NG_sig, signer, name, keys.NG_priv, Common::swap32(keys.NG_key_id)); memset(ap_priv, 0, sizeof ap_priv); @@ -426,12 +438,12 @@ void CWiiSaveCrypted::do_sig() memset(ap_sig, 81, sizeof ap_sig); // temp - sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", ng_id); + sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", Common::swap32(keys.NG_id)); sprintf(name, "AP%08x%08x", 1, 2); make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); sha1(ap_cert + 0x80, 0x100, hash); - generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash); + generate_ecdsa(ap_sig, ap_sig + 30, keys.NG_priv, hash); make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); data_size = Common::swap32(bkhdr.sizeOfFiles) + 0x80; @@ -446,7 +458,10 @@ void CWiiSaveCrypted::do_sig() fpData_bin.Seek(0xf0c0, SEEK_SET); if (!fpData_bin.ReadBytes(data, data_size)) - PanicAlert("read data for sig check"); + { + b_valid = false; + return; + } sha1(data, data_size, hash); sha1(hash, 20, hash); @@ -460,13 +475,12 @@ void CWiiSaveCrypted::do_sig() } generate_ecdsa(sig, sig + 30, ap_priv, hash); *(u32*)(sig + 60) = Common::swap32(0x2f536969); + + fpData_bin.WriteArray(sig, sizeof(sig)); + fpData_bin.WriteArray(ng_cert, sizeof(ng_cert)); + fpData_bin.WriteArray(ap_cert, sizeof(ap_cert)); - if (!fpData_bin.WriteArray(sig, sizeof(sig))) - PanicAlert("write sig"); - if (!fpData_bin.WriteArray(ng_cert, sizeof(ng_cert))) - PanicAlert("write NG cert"); - if (!fpData_bin.WriteArray(ap_cert, sizeof(ap_cert))) - PanicAlert("write AP cert"); + b_valid = fpData_bin.IsGood(); } @@ -485,40 +499,40 @@ void CWiiSaveCrypted::make_ec_cert(u8 *cert, u8 *sig, char *signer, char *name, bool CWiiSaveCrypted::getPaths(bool forExport) { - if (_saveGameTitle) + if (m_TitleID) { - sprintf(pathSavedir, "%stitle/%08x/%08x/data/", - File::GetUserPath(D_WIIUSER_IDX).c_str(), - (u32)(_saveGameTitle>>32), (u32)_saveGameTitle); - sprintf(pathBanner_bin, "%sbanner.bin", pathSavedir); - sprintf(_saveGameString, "%c%c%c%c", - (u8)(_saveGameTitle >> 24) & 0xFF, (u8)(_saveGameTitle >> 16) & 0xFF, - (u8)(_saveGameTitle >> 8) & 0xFF, (u8)_saveGameTitle & 0xFF); + WiiTitlePath = Common::GetTitleDataPath(m_TitleID); + BannerFilePath = WiiTitlePath + "banner.bin"; } if (forExport) { - if(!File::IsDirectory(pathSavedir)) + char GameID[5]; + sprintf(GameID, "%c%c%c%c", + (u8)(m_TitleID >> 24) & 0xFF, (u8)(m_TitleID >> 16) & 0xFF, + (u8)(m_TitleID >> 8) & 0xFF, (u8)m_TitleID & 0xFF); + + if(!File::IsDirectory(WiiTitlePath)) { b_valid = false; - PanicAlertT("No save folder found for title %s", _saveGameString); + PanicAlertT("No save folder found for title %s", GameID); return false; } - if(!File::Exists(pathBanner_bin)) + if(!File::Exists(BannerFilePath)) { b_valid = false; - PanicAlertT("No banner file found for title %s", _saveGameString); + PanicAlertT("No banner file found for title %s", GameID); return false; } if (strlen(pathData_bin) == 0) strcpy(pathData_bin, "."); // If no path was passed, use current dir - sprintf(pathData_bin, "%s/private/wii/title/%s/data.bin", pathData_bin, _saveGameString); + sprintf(pathData_bin, "%s/private/wii/title/%s/data.bin", pathData_bin, GameID); File::CreateFullPath(pathData_bin); } else { - File::CreateFullPath(pathSavedir); - if (!AskYesNoT("Warning! it is advised to backup all files in the folder:\n%s\nDo you wish to continue?", pathSavedir)) + File::CreateFullPath(WiiTitlePath); + if (!AskYesNoT("Warning! it is advised to backup all files in the folder:\n%s\nDo you wish to continue?", WiiTitlePath.c_str())) return false; } return true; diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h index 1743dee1ee..79066de928 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h @@ -30,7 +30,7 @@ class CWiiSaveCrypted { public: - CWiiSaveCrypted(const char* FileName, u64 title = 0); + CWiiSaveCrypted(const char* FileName, u64 TitleID = 0); ~CWiiSaveCrypted(); void ReadHDR(); void ReadBKHDR(); @@ -50,11 +50,10 @@ private: u8 SD_IV[0x10]; std::vector FilesList; - char pathData_bin[2048], - pathSavedir[2048], - pathBanner_bin[2048], //should always be FULL_WII_USER_DIR "title/%08x/%08x/data/" - pathRawSave[2048], - _saveGameString[5]; + char pathData_bin[2048]; + + std::string BannerFilePath, + WiiTitlePath; u8 IV[0x10], *_encryptedData, @@ -62,6 +61,14 @@ private: md5_file[16], md5_calc[16]; + struct _keys + { + u8 NG_priv[0x1E], + NG_sig[0x3C], + NG_id[4], + NG_key_id[4]; + }keys; + u32 _bannerSize, _numberOfFiles, _sizeOfFiles, @@ -69,7 +76,7 @@ private: _fileSize, _roundedfileSize; - u64 _saveGameTitle; + u64 m_TitleID; bool b_valid, b_tryAgain;