diff --git a/trunk/ConsoleDataMigration/OMakefile b/trunk/ConsoleDataMigration/OMakefile index 203c656..4b3eca3 100644 --- a/trunk/ConsoleDataMigration/OMakefile +++ b/trunk/ConsoleDataMigration/OMakefile @@ -19,6 +19,7 @@ common \ ConsoleBackup \ ConsoleRestore \ + tools \ ) DefineDefaultRules() diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/ExportedDataVerifier.bsf b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/ExportedDataVerifier.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/ExportedDataVerifier.bsf differ diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/ExportedDataVerifier.rsf b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/ExportedDataVerifier.rsf new file mode 100644 index 0000000..d1dd8dd --- /dev/null +++ b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/ExportedDataVerifier.rsf @@ -0,0 +1,48 @@ +BasicInfo: + Title : ExportedDataVeri + ProductCode: ExportedDataVeri + BackupMemoryType: None + +TitleInfo: + Use: Evaluation + Category: Application + UniqueId: 0xf8023 + Version: 0 + +SystemControlInfo: + AppType : Application + StackSize : 0xF000 + Dependency : + - gpio + - pdn + - spi + - i2c + - mcu + - ptm + - codec + - cfg + - hid + - gsp + +AccessControlInfo: + Priority : 16 + DisableDebug : true + + FileSystemAccess: + - DirectSdmc + - Debug + - Core + - CategoryFileSystemTool + + IoAccessControl: + - FsMountCardSpi + - FsMountNand + - FsMountTwln + +Option: + FreeProductCode: true + + +Rom: + # ROM に含めるファイルシステムのルートパスを指定します。 + HostRoot: "$(ROMFS_ROOT)" \ No newline at end of file diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/OMakefile b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/OMakefile new file mode 100644 index 0000000..9300c96 --- /dev/null +++ b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/OMakefile @@ -0,0 +1,76 @@ +#!/usr/bin/env omake +#---------------------------------------------------------------------------- +# Project: Horizon +# File: OMakefile +# +# Copyright (C)2009 Nintendo Co., Ltd. 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$ +#---------------------------------------------------------------------------- +SUPPORTED_TARGETS = CTR-T*.Process.MPCore.* +CTR_APPTYPE = BOTH +CTR_MAKE_DEVELOPMENT_IMAGE = true + +TARGET_PROGRAM = ExportedDataVerifier + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../common + +SOURCES[] = + main.cpp + ../../common/HardwareInfo.cpp + ../../common/DrawSystemState.cpp + ../../common/FileTransfer.cpp + ../../common/FileChecker.cpp + ../../common/SdReaderWriter.cpp + ../../common/HeapManager.cpp + ../../common/SdLogger.cpp + ../../common/wave.cpp + ../../common/SimplePlayer.cpp + ../../common/LogConsole.cpp + ../../common/CommonLogger.cpp + ../../common/SdMountManager.cpp + ../../common/configLoader.cpp + ../../common/PlayHistoryManager.cpp + ../../common/VersionDetect.cpp + +CTR_BANNER_SPEC = $(TARGET_PROGRAM).bsf + +ROMFS_ROOT = ../../common/romfiles + +LIBS += libnn_cfg \ + libnn_driversEeprom \ + libnn_driversi2c \ + libnn_driversCal \ + libnn_crypto \ + libnn_driversCodec \ + libnn_spi \ + libnn_gpio \ + libnn_pdn \ + libnn_mcu \ + libnn_i2c \ + libnn_driversCamera \ + libnn_ps \ + libnn_driversRsa \ + lib_demo \ + libnn_nwm \ + libnn_friends \ + libnn_ns \ + libnn_am \ + libnn_nim \ + +INSTALL_SDK_TOOL = true + +ROM_SPEC_FILE = $(TARGET_PROGRAM).rsf +DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/_private/RepairTool.desc + +include $(ROOT_OMAKE)/modulerules + +build: $(DEFAULT_TARGETS) diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/model.cbmd b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/model.cbmd differ diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/sound.cbsd b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/sound.cbsd differ diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/unknown24x24.ctpk b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/unknown48x48.ctpk b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/main.cpp b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/main.cpp new file mode 100644 index 0000000..7d620bd --- /dev/null +++ b/trunk/ConsoleDataMigration/tools/ExportedDataVerifier/main.cpp @@ -0,0 +1,503 @@ +/*---------------------------------------------------------------------------* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Aes_define.h" +#include "FileTransfer.h" +#include "CommonLogger.h" + +#include "demo.h" + +#include +#include + +#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 "HardwareInfo.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 s_VerifyThreadStack; + +u32 s_VerifySuccess = 0; +u32 s_VerifyFail = 0; + +} + +const char* GetCharStr(const wchar_t* path) +{ + static char filename[nn::fs::MAX_FILE_PATH_LENGTH]; + std::memset(filename, 0, sizeof(filename)); + std::wcstombs(filename, path, sizeof(filename)); + filename[sizeof(filename) - 1] = '\0'; + return filename; +} + +void GenerateNandPath(wchar_t* toPath, const wchar_t* fromPath) +{ + // 切り詰める + std::string tmp(GetCharStr(fromPath)); + std::string twlPhotoRoot(GetCharStr(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)); + std::string twlSoundRoot(GetCharStr(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)); + std::string ctrRoot(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, %s\n", GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success\n"); + 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, %s\n", GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success\n"); + s_VerifySuccess++; + } + break; + } + } + } + } + nn::crypto::Finalize(); + sdFile.Finalize(); + } + } + } + from_dir.Finalize(); + return ret_value; +} + + +void VerifyThreadFunc() +{ + nn::Result result; + + COMMON_LOGGER("VerifyThreadFunc Start\n"); + + 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(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); + } +} diff --git a/trunk/ConsoleDataMigration/tools/OMakefile b/trunk/ConsoleDataMigration/tools/OMakefile new file mode 100644 index 0000000..2d83e1f --- /dev/null +++ b/trunk/ConsoleDataMigration/tools/OMakefile @@ -0,0 +1,16 @@ +#!/usr/bin/env omake +#---------------------------------------------------------------------------- +# Project: Horizon +# File: OMakefile +# +# Copyright (C)2009 Nintendo Co., Ltd. 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$ +#---------------------------------------------------------------------------- +.SUBDIRS: $(glob D, *)