ctr_Repair/trunk/ConsoleDataMigration/sources/tools/ExportedDataVerifier/main.cpp
N2614 e60a75f616 [Verifier]ビルドエラー修正
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@235 385bec56-5757-e545-9c3a-d8741f4650f1
2011-04-27 07:12:22 +00:00

497 lines
16 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: FileTransfer.cpp
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include <nn.h>
#include <nn/version.h>
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
#include <nn/mcu.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/ps.h>
#include <nn/nwm.h>
#include <nn/ac.h>
#include <nn/friends.h>
#include <nn/friends/CTR/friends_ApiPrivate.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_ApiSysSaveData.h>
#include <nn/cfg/CTR/cfg_ApiNor.h>
#include <nn/os/os_SharedInfo.h>
#include <nn/pl/CTR/pl_Version.h>
#include <nn/fs/fs_ApiSharedExtSaveData.h>
#include <nn/nim.h>
#include <nn/ndm.h>
#include <nn/crypto/crypto_AesCmac.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/crypto/crypto_Sha256.h>
#include <nn/crypto/crypto_SwAesCmac.h>
#include "Aes_define.h"
#include "FileTransfer.h"
#include "CommonLogger.h"
#include "demo.h"
#include <vector>
#include <string>
#include "DrawSystemState.h"
#include "FileName.h"
#include "SimplePlayer.h"
#include "CommonLogger.h"
#include "SDMountManager.h"
#include "HeapManager.h"
#include "PlayHistoryManager.h"
#include "common_Types.h"
#include "VersionDetect.h"
#include "Util.h"
#include "CommonLogger.h"
namespace
{
// グラフィックスに割り当てるメモリ
const size_t s_GxHeapSize = 0x800000;
const u32 CONSOLE_WIDTH = 38;
const u32 CONSOLE_HEIGHT = 24;
const u32 CONSOLE_MAX_LINE = 1000;
const size_t VERIFY_THREAD_STACK_SIZE = 0x4000;
nn::os::Thread s_VerifyThread;
nn::os::StackBuffer<VERIFY_THREAD_STACK_SIZE> s_VerifyThreadStack;
u32 s_VerifySuccess = 0;
u32 s_VerifyFail = 0;
}
void GenerateNandPath(wchar_t* toPath, const wchar_t* fromPath)
{
// 切り詰める
std::string tmp(common::GetCharStr(fromPath));
std::string twlPhotoRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME));
std::string twlSoundRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME));
std::string ctrRoot(common::GetCharStr(common::SD_SAVEDATA_ROOT_NAME));
std::string output;
std::string::size_type size;
size = tmp.find(twlPhotoRoot.c_str());
if(size == std::string::npos)
{
size = tmp.find(twlSoundRoot.c_str());
if(size == std::string::npos)
{
size = tmp.find(ctrRoot.c_str());
if(size == std::string::npos)
{
// 想定外のパスへの出力のためreturn
return;
}
else
{
output += std::string("nand:/data/");
output += tmp.substr(size + ctrRoot.size());
}
}
else
{
output += std::string("twls:/");
output += tmp.substr(size + twlSoundRoot.size());
}
}
else
{
output += std::string("twlp:/");
output += tmp.substr(size + twlPhotoRoot.size());
}
s32 length = std::mbstowcs(toPath, output.c_str(), nn::fs::MAX_FILE_PATH_LENGTH);
if(length == -1)
{
NN_PANIC("failed mbstowcs");
}
}
bool CalculateAndCompareCmac(nn::crypto::Sha256Context* context, bit8* sdCmac)
{
nn::Result result;
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
context->GetHash(sha256Hash);
context->Finalize();
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, sizeof(sha256Hash), common::cmacKey);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
return std::memcmp(cmac, sdCmac, sizeof(cmac)) == 0;
}
// ディレクトリ間のコピー
// アーカイブ越しのコピーが可能
// アーカイブにマウントした状態で呼び出す必要あり
// 書き込み先のディレクトリはあらかじめ消去しておくこと。
// 引数はスラッシュ付き
// TODO:分割して短くする
bool VerifyDirectory(const wchar_t * from_path, void* buf,
const size_t bufSize)
{
using namespace common;
nn::fs::Directory from_dir;
nn::fs::DirectoryEntry entry;
s32 numread = 0;
std::wostringstream target_from;
bool ret_value = true;
nn::Result result = from_dir.TryInitialize(from_path);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
while (1)
{
result = from_dir.TryRead(&numread, &entry, 1);
if (result.IsFailure() || numread != 1)
{
break;
}
if (std::wcscmp(entry.entryName, L".") == 0 || std::wcscmp(entry.entryName, L"..") == 0)
{
continue;
}
target_from.str(L"");
target_from.clear(std::stringstream::goodbit);
target_from << from_path << entry.entryName;
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
{
target_from << L"/";
// 再帰処理
if (!VerifyDirectory(target_from.str().c_str(), buf, bufSize))
{
ret_value = false;
}
}
}
// ファイルの場合
// SDカード上のファイルのCMACを検証する
else
{
nn::fs::FileInputStream sdFile;
s64 sdFileSize;
result = sdFile.TryInitialize(target_from.str().c_str());
if(result.IsFailure())
{
ret_value = false;
break;
}
result = sdFile.TryGetSize(&sdFileSize);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
break;
}
else
{
bit8 sdCmac[nn::crypto::AES_CMAC_MAC_SIZE];
// ハッシュが付加されていないとエラー
if (sdFileSize < nn::crypto::AES_CMAC_MAC_SIZE)
{
return false;
}
s32 readSize;
// ハッシュを取得する
nn::crypto::Initialize();
result = sdFile.TrySetPosition(sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE);
if (result.IsSuccess())
{
result = sdFile.TryRead(&readSize, sdCmac, sizeof(sdCmac));
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
}
else
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
sdFile.SetPosition(0);
// 復号化しながらハッシュを計算する
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
nn::crypto::Sha256Context context;
context.Initialize();
wchar_t nandPath[nn::fs::MAX_FILE_PATH_LENGTH];
// sdパスからnandパスを生成する
GenerateNandPath(nandPath, target_from.str().c_str());
// NAND上のフルパスをハッシュに含めている
context.Update(nandPath, std::wcslen(nandPath) * sizeof(wchar_t));
BackupDataHeader enc;
BackupDataHeader dec;
std::memset(&enc, 0, sizeof(enc));
std::memset(&dec, 0, sizeof(dec));
sdFile.TryRead(&readSize, &enc, sizeof(enc));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if(result.IsFailure())
{
ret_value = false;
break;
}
context.Update(&enc, sizeof(enc));
swAesCtrContext.Decrypt(&dec, &enc, sizeof(enc));
size_t totalReadSize = 0;
while (1)
{
result = sdFile.TryRead(&readSize, buf, bufSize);
totalReadSize += readSize;
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
break;
}
else
{
if (readSize == 0)
{
ret_value = CalculateAndCompareCmac(&context, sdCmac);
if(!ret_value)
{
COMMON_LOGGER("********** Verification Failed **********\n %s\n", common::GetCharStr(target_from.str().c_str()));
s_VerifyFail++;
}
else
{
COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str()));
s_VerifySuccess++;
}
break;
}
else
{
bool readDone = false;;
// CMACまで読んだかどうか
if (sdFileSize - (sizeof(BackupDataHeader) + nn::crypto::AES_CMAC_MAC_SIZE) < totalReadSize)
{
readSize -= totalReadSize - (sdFileSize - (sizeof(BackupDataHeader) + nn::crypto::AES_CMAC_MAC_SIZE));
readDone = true;
}
context.Update(buf, readSize);
if(readDone)
{
ret_value = CalculateAndCompareCmac(&context, sdCmac);
if(!ret_value)
{
COMMON_LOGGER("********** Verification Failed **********\n %s\n", common::GetCharStr(target_from.str().c_str()));
s_VerifyFail++;
}
else
{
COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str()));
s_VerifySuccess++;
}
break;
}
}
}
}
nn::crypto::Finalize();
sdFile.Finalize();
}
}
}
from_dir.Finalize();
return ret_value;
}
void VerifyThreadFunc()
{
nn::Result result;
COMMON_LOGGER("VerifyThreadFunc Start\n");
s_VerifyFail = 0;
s_VerifySuccess = 0;
result = common::SdMountManager::Mount();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL)
{
u32 i = 0;
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[i], common::TWL_FS_ARCHIVE_KIND[i]);
if (result.IsSuccess())
{
VerifyDirectory(
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)).c_str(), buf, bufSize);
}
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[i]);
i++;
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[i], common::TWL_FS_ARCHIVE_KIND[i]);
if (result.IsSuccess())
{
VerifyDirectory(
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)).c_str(), buf, bufSize);
}
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[i]);
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
if(result.IsSuccess())
{
VerifyDirectory(
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(),
buf, bufSize);
}
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
common::HeapManager::GetHeap()->Free(buf);
}
common::SdMountManager::Unmount();
COMMON_LOGGER("Verify Thread Finalize\n");
COMMON_LOGGER("\n\n");
COMMON_LOGGER("Verify Finished, success = %d, fail = %d\n", s_VerifySuccess, s_VerifyFail);
}
extern "C" void nnMain(void)
{
nn::Result result;
// os の初期化
nn::os::Initialize();
// fs の初期化
nn::fs::Initialize();
// appletの初期化
nn::applet::Enable( false );
// hid の初期化
result = nn::hid::Initialize();
NN_UTIL_PANIC_IF_FAILED(result);
// ヒープの確保
common::HeapManager::GetHeap()->Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize(), nn::os::ALLOCATE_OPTION_LINEAR);
// RenderSystem の準備
uptr heapForGx = reinterpret_cast<uptr>(common::HeapManager::GetHeap()->Allocate(s_GxHeapSize));
demo::RenderSystemDrawing s_RenderSystem;
s_RenderSystem.Initialize(heapForGx, s_GxHeapSize);
// ログ描画の初期化
common::Logger::GetLoggerInstance()->Initialize(CONSOLE_WIDTH, CONSOLE_HEIGHT, CONSOLE_MAX_LINE, &s_RenderSystem);
// RenderSystemを作ってからログが出せる
common::Logger::InitializeEjectThread();
COMMON_LOGGER("Verify Start\n");
// ボタン入力
nn::hid::PadReader s_PadReader;
nn::hid::PadStatus padStatus;
for(;;)
{
s_PadReader.ReadLatest(&padStatus);
if(padStatus.trigger & nn::hid::BUTTON_A)
{
// SDにコピーするためのスレッドの作成
if(s_VerifyThread.IsValid() && !s_VerifyThread.IsAlive())
{
s_VerifyThread.Join();
s_VerifyThread.Finalize();
}
s_VerifyThread.Start(VerifyThreadFunc, s_VerifyThreadStack);
}
// コンソールスクロール
if(padStatus.hold & nn::hid::BUTTON_UP)
{
common::Logger::GetLoggerInstance()->ScrollUp();
}
// コンソールスクロール
if(padStatus.hold & nn::hid::BUTTON_DOWN)
{
common::Logger::GetLoggerInstance()->ScrollDown();
}
if(padStatus.hold & nn::hid::BUTTON_LEFT)
{
common::Logger::GetLoggerInstance()->ScrollToBegin();
}
if(padStatus.hold & nn::hid::BUTTON_RIGHT)
{
common::Logger::GetLoggerInstance()->ScrollToEnd();
}
s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
s_RenderSystem.Clear();
s_RenderSystem.SetColor(1.f, 1.f, 1.f);
common::Logger::GetLoggerInstance()->DrawConsole();
s_RenderSystem.SwapBuffers();
s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
}
}