mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@437 385bec56-5757-e545-9c3a-d8741f4650f1
434 lines
14 KiB
C++
434 lines
14 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 "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_EncryptThread;
|
|
nn::os::StackBuffer<VERIFY_THREAD_STACK_SIZE> s_EncryptThreadStack;
|
|
|
|
u32 s_EncryptSuccess = 0;
|
|
u32 s_EncryptFail = 0;
|
|
|
|
}
|
|
|
|
void GenerateNandPath(wchar_t* toPath, const wchar_t* fromPath)
|
|
{
|
|
// 切り詰める
|
|
std::string tmp(common::GetCharStr(fromPath));
|
|
std::string twlRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_ROOT_NAME));
|
|
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)
|
|
{
|
|
size = tmp.find(twlRoot.c_str());
|
|
if(size == std::string::npos)
|
|
{
|
|
// 想定外のパスへの出力のためreturn
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
output += std::string("twln:/title/");
|
|
output += tmp.substr(size + twlRoot.size());
|
|
}
|
|
}
|
|
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");
|
|
}
|
|
}
|
|
|
|
// ディレクトリ間のコピー
|
|
// アーカイブ越しのコピーが可能
|
|
// アーカイブにマウントした状態で呼び出す必要あり
|
|
// 書き込み先のディレクトリはあらかじめ消去しておくこと。
|
|
// 引数はスラッシュ付き
|
|
// TODO:分割して短くする
|
|
bool EncryptDirectory(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 (!EncryptDirectory(target_from.str().c_str(), buf, bufSize))
|
|
{
|
|
ret_value = false;
|
|
}
|
|
}
|
|
}
|
|
// ファイルの場合
|
|
// SDカード上のファイルを暗号化してCMACを出力する
|
|
else
|
|
{
|
|
nn::fs::FileInputStream sdFile;
|
|
s64 filesize;
|
|
s32 readsize;
|
|
|
|
// 読み込み対象ファイル開く
|
|
result = sdFile.TryInitialize(target_from.str().c_str());
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
|
|
// 読み込み対象ファイルのサイズ取得
|
|
result = sdFile.TryGetSize(&filesize);
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
|
|
nn::crypto::SwAesCtrContext swAesCtrContext;
|
|
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
|
|
|
|
size_t totalReadSize = 0;
|
|
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 header;
|
|
BackupDataHeader enc;
|
|
std::memset(&header, 0, sizeof(header));
|
|
std::memset(&enc, 0, sizeof(enc));
|
|
header.size = filesize;
|
|
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
context.Update(&enc, sizeof(enc));
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
// バッファの後半半分を暗号・復号用に使う
|
|
result = sdFile.TryRead(&readsize, buf, bufSize / 2);
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
|
|
totalReadSize += readsize;
|
|
|
|
if (readsize == 0)
|
|
{
|
|
{
|
|
NN_LOG("Add CMAC %ls\n", target_from.str().c_str());
|
|
// SHA256を計算してCMACを付加する
|
|
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
|
|
context.GetHash(sha256Hash);
|
|
|
|
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
|
|
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE,
|
|
common::cmacKey);
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
|
|
NN_LOG("cmac:\n");
|
|
for(u32 i = 0; i < sizeof(cmac); i++)
|
|
{
|
|
NN_LOG("%02X ", cmac[i]);
|
|
}
|
|
NN_LOG("\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
{
|
|
NN_LOG("EncryptSize = %d\n", readsize);
|
|
|
|
u8 paddingSize = 0;
|
|
common::AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*>(buf), bufSize / 2, &readsize);
|
|
|
|
// 暗号化後SHA256を計算しつつ書き込み
|
|
result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
context.Update(reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize);
|
|
|
|
// 事前計算したファイルサイズに一致させるためパディング分減算
|
|
readsize -= paddingSize;
|
|
}
|
|
|
|
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
|
|
|
|
}
|
|
}
|
|
sdFile.Finalize();
|
|
}
|
|
}
|
|
from_dir.Finalize();
|
|
return ret_value;
|
|
}
|
|
|
|
|
|
void EncryptThreadFunc()
|
|
{
|
|
nn::Result result;
|
|
|
|
COMMON_LOGGER("EncryptThreadFunc Start\n");
|
|
s_EncryptFail = 0;
|
|
s_EncryptSuccess = 0;
|
|
|
|
result = common::SdMountManager::Mount();
|
|
|
|
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
|
|
if(bufSize > common::FILE_COPY_HEAP_SIZE)
|
|
{
|
|
bufSize = common::FILE_COPY_HEAP_SIZE;
|
|
}
|
|
|
|
common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2);
|
|
void* buf = heap.GetAddr();
|
|
if (buf != NULL)
|
|
{
|
|
|
|
EncryptDirectory(
|
|
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(),
|
|
buf, bufSize);
|
|
|
|
EncryptDirectory(
|
|
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH)
|
|
+ ::std::wstring(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)).c_str(), buf, bufSize);
|
|
|
|
EncryptDirectory(
|
|
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH)
|
|
+ ::std::wstring(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)).c_str(), buf, bufSize);
|
|
|
|
EncryptDirectory(
|
|
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(),
|
|
buf, bufSize);
|
|
}
|
|
|
|
common::SdMountManager::Unmount();
|
|
|
|
COMMON_LOGGER("Encrypt Thread Finalize\n");
|
|
|
|
COMMON_LOGGER("\n\n");
|
|
COMMON_LOGGER("Encrypt Finished, success = %d, fail = %d\n", s_EncryptSuccess, s_EncryptFail);
|
|
}
|
|
|
|
extern "C" void nninitSetupDaemons(void)
|
|
{
|
|
}
|
|
|
|
|
|
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_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
|
|
|
|
// ヒープの確保
|
|
common::InitializeHeap();
|
|
|
|
// RenderSystem の準備
|
|
common::HeapManager gxHeap(s_GxHeapSize);
|
|
uptr heapForGx = reinterpret_cast<uptr>(gxHeap.GetAddr());
|
|
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("Encrypt 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_EncryptThread.IsValid() && !s_EncryptThread.IsAlive())
|
|
{
|
|
s_EncryptThread.Join();
|
|
s_EncryptThread.Finalize();
|
|
}
|
|
s_EncryptThread.Start(EncryptThreadFunc, s_EncryptThreadStack);
|
|
}
|
|
|
|
// コンソールスクロール
|
|
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);
|
|
}
|
|
}
|