ctr_Repair/branches/work/VerificationFailed/sources/common/FileTransfer.cpp
N2614 f1b229ee78 暗号化無効に。バッファの後半半分にそのままデータをコピーして書き込むように
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@519 385bec56-5757-e545-9c3a-d8741f4650f1
2011-11-17 01:29:52 +00:00

878 lines
32 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 <vector>
#include <string>
#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 "common_Types.h"
#include "FileName.h"
namespace common
{
namespace
{
u64 s_TotalFileSize;
u64 s_FinishedFileSize = 0;
u64 s_Progress = 0;
}
bool VerifyMac(nn::fs::FileInputStream* sdFile, nn::fs::FileStream* nandFile, s64 sdFileSize, s64 nandFileSize,
const wchar_t* nandPath, void* buf, size_t bufSize);
bool ConfirmFile(nn::fs::FileInputStream* from_file, nn::fs::FileStream* to_file, s64 sdFileSize, s64 nandFileSize,
void* buf, size_t bufSize, const wchar_t* sdPath, const wchar_t* tmpPath, const wchar_t* truePath);
void AddPkcsPadding(u8* paddingSize, void* buf, size_t bufSize, s32* readSize);
bool AddPathNameAndUpdateContext(nn::fs::FileOutputStream* file, const wchar_t *str, s64 fileSize,
nn::crypto::Sha256Context* context);
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;
}
nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, s64& fileSize)
{
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
if (numEntry == 0)
{
// カレントディレクトリを閉じる
dir.Finalize();
// カレントディレクトリの子を開く
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
if (entryIndex->attributes.isDirectory)
{
result = CalculateFileNum(currentDirectory + std::wstring(entryIndex->entryName) + std::wstring(L"/"),
fileNum, fileSize);
}
}
return result;
}
entryList.push_back(entry);
fileNum++;
fileSize += entry.entrySize;
}
}
bool ExistsInList(ImportDataList* fileList, const wchar_t* path, bool isDirectory)
{
std::wstring sdPath(path);
if(isDirectory)
{
sdPath += std::wstring(L"/");
}
char str[nn::fs::MAX_FILE_PATH_LENGTH];
std::strlcpy(str, GetCharStr(sdPath.c_str()), sizeof(str));
bool returnValue = false;
for(ImportDataList::iterator it = fileList->begin(); it != fileList->end(); it++)
{
if(std::strcmp(str, it->fileName.c_str()) == 0)
{
returnValue = true;
NN_LOG("%s exists in FileList.txt\n", str);
break;
}
}
return returnValue;
}
bool ExportTwlSaveDirectory(const wchar_t* dirPath, nn::fs::FileOutputStream* list,
nn::crypto::Sha256Context* listContext)
{
NN_LOG("Create Directory %ls\n", dirPath);
nn::Result result = nn::fs::TryCreateDirectory(dirPath);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return AddPathNameAndUpdateContext(list, dirPath, -1, listContext);
}
bool ExportTwlSaveFile(const wchar_t* from_path, const wchar_t* to_path, void* buf, const size_t bufSize,
nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext)
{
NN_LOG("from = %ls\n", from_path);
NN_LOG("to = %ls\n", to_path);
nn::Result result;
// ファイル作成
nn::fs::FileInputStream from_file;
nn::fs::FileStream to_file;
s64 filesize;
s32 readsize;
s32 writesize;
NN_LOG("Copy File %ls\n", from_path);
// 読み込み対象ファイル開く
result = from_file.TryInitialize(from_path);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 読み込み対象ファイルのサイズ取得
result = from_file.TryGetSize(&filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (!AddPathNameAndUpdateContext(list, to_path, filesize, listContext))
{
return false;
}
#ifndef SKIP_VERIFY
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
#endif
size_t totalReadSize = 0;
#ifndef SKIP_VERIFY
nn::crypto::Sha256Context context;
context.Initialize();
#endif
// ファイルサイズをヘッダに書いておく
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(to_path, filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryInitialize(to_path,
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#ifndef SKIP_VERIFY
// フルパスをハッシュに含める
context.Update(from_path, std::wcslen(from_path) * 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));
s32 writeSize;
result = to_file.TryWrite(&writeSize, &enc, sizeof(enc), false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
while (1)
{
// バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
totalReadSize += readsize;
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (readsize == 0)
{
#ifndef SKIP_VERIFY
NN_LOG("Add CMAC %ls\n", from_path);
// 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);
result = to_file.TryWrite(&writesize, cmac, sizeof(cmac));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
break;
}
else
{
NN_LOG("EncryptSize = %d\n", readsize);
#ifndef SKIP_VERIFY
u8 paddingSize = 0;
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);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize, false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 事前計算したファイルサイズに一致させるためパディング分減算
readsize -= paddingSize;
#else
// 後半半分にコピーしてから書き込む
std::memcpy(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize, false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG( "finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
}
}
to_file.Finalize();
from_file.Finalize();
return true;
}
bool CopyDirectory(ImportDataList* fileList, const wchar_t * from_path, const wchar_t * to_path, void* buf,
const size_t bufSize, bool encode, nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext)
{
nn::fs::Directory from_dir;
nn::fs::DirectoryEntry entry;
s32 numread = 0;
std::wostringstream target_from;
std::wostringstream target_to;
nn::Result result = from_dir.TryInitialize(from_path);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
while (1)
{
result = from_dir.TryRead(&numread, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if(numread == 0)
{
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;
target_to.str(L"");
target_to.clear(std::stringstream::goodbit);
target_to << to_path << entry.entryName;
// NAND書き込みの場合はリストに存在するかチェックする
if (!encode)
{
if (!ExistsInList(fileList, target_from.str().c_str(), entry.attributes.isDirectory))
{
NN_LOG("============No such file %ls in FileList.txt. Skip=============\n", target_from.str().c_str());
continue;
}
}
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
// ディレクトリ作成
NN_LOG("Create Directory %ls\n", target_to.str().c_str());
result = nn::fs::TryCreateDirectory(target_to.str().c_str());
if (result.IsSuccess() || result.IsFailure() && result <= nn::fs::ResultAlreadyExists())
{
target_from << L"/";
target_to << L"/";
if(encode)
{
if(!AddPathNameAndUpdateContext(list, target_to.str().c_str(), -1, listContext))
{
return false;
}
}
// 再帰処理
if (!CopyDirectory(fileList, target_from.str().c_str(), target_to.str().c_str(), buf, bufSize, encode, list, listContext))
{
return false;
}
}
else
{
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
}
// ファイルの場合
else
{
std::wostringstream target_tmp;
target_tmp.str(L"");
target_tmp.clear(std::stringstream::goodbit);
if(!encode)
{
target_tmp << to_path << L"_" << entry.entryName;
}
else
{
target_tmp << target_to.str();
}
// ファイル作成
nn::fs::FileInputStream from_file;
nn::fs::FileStream to_file;
s64 filesize;
#ifndef SKIP_VERIFY
s64 fileSizeWithoutHeaderAndFooter;
#endif
s32 readsize;
s32 writesize;
NN_LOG("Copy File %ls\n", target_from.str().c_str());
// 読み込み対象ファイル開く
result = from_file.TryInitialize(target_from.str().c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 読み込み対象ファイルのサイズ取得
result = from_file.TryGetSize(&filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (encode)
{
if (!AddPathNameAndUpdateContext(list, target_to.str().c_str(), filesize, listContext))
{
return false;
}
}
#ifndef SKIP_VERIFY
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
#endif
size_t totalReadSize = 0;
#ifndef SKIP_VERIFY
nn::crypto::Sha256Context context;
context.Initialize();
#endif
// ファイルサイズをヘッダに書いておく
if (encode)
{
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(target_tmp.str().c_str(), filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryInitialize(target_tmp.str().c_str(),
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#ifndef SKIP_VERIFY
// フルパスをハッシュに含める
context.Update(target_from.str().c_str(), target_from.str().size() * 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));
s32 writeSize;
result = to_file.TryWrite(&writeSize, &enc, sizeof(enc), false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
}
else
{
#ifndef SKIP_VERIFY
// ヘッダを読む
// ハッシュの計算は終わっているので復号化のみ
BackupDataHeader header;
BackupDataHeader dec;
std::memset(&header, 0, sizeof(header));
std::memset(&dec, 0, sizeof(dec));
s32 readSize;
result = from_file.TryRead(&readSize, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
swAesCtrContext.Decrypt(&dec, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
fileSizeWithoutHeaderAndFooter = dec.size;
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(target_tmp.str().c_str(), fileSizeWithoutHeaderAndFooter);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
result = to_file.TryInitialize(target_tmp.str().c_str(),
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
while (1)
{
// バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
totalReadSize += readsize;
if (readsize == 0)
{
if (encode)
{
#ifndef SKIP_VERIFY
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);
result = to_file.TryWrite(&writesize, cmac, sizeof(cmac));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
}
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#ifndef SKIP_VERIFY
// 復号済みなら検証する
if (!encode)
{
if (!ConfirmFile(&from_file, &to_file, filesize, fileSizeWithoutHeaderAndFooter, buf, bufSize,
target_from.str().c_str(), target_tmp.str().c_str(), target_to.str().c_str()))
{
return false;
}
}
#endif
break;
}
else
{
if (encode)
{
#ifndef SKIP_VERIFY
NN_LOG("EncryptSize = %d\n", readsize);
u8 paddingSize = 0;
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);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize,
false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 事前計算したファイルサイズに一致させるためパディング分減算
readsize -= paddingSize;
#else
// 後半半分にコピーしてから書き込む
std::memcpy(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize, false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
#endif
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG(
"finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
}
else
{
#ifndef SKIP_VERIFY
// ハッシュ検証は通っているので復号化しつつ書き込み
// パディング以降は書き込まないよう書き込みサイズを変更する
NN_LOG("DecryptSize = %d\n", readsize);
result = swAesCtrContext.Decrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// パディングまで読んだかどうか
bool readDone = false;
// パディングまで読んでいたら書き込みサイズを減らす
if (fileSizeWithoutHeaderAndFooter < totalReadSize)
{
readsize -= totalReadSize - fileSizeWithoutHeaderAndFooter;
readDone = true;
}
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize,
false);
#else
// 後半半分にコピーしてから書き込む
std::memcpy(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize, false);
#endif
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG(
"finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
#ifndef SKIP_VERIFY
// 読みきったので次のファイルへ
if (readDone)
{
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (!ConfirmFile(&from_file, &to_file, filesize, fileSizeWithoutHeaderAndFooter, buf,
bufSize, target_from.str().c_str(), target_tmp.str().c_str(),
target_to.str().c_str()))
{
return false;
}
break;
}
#endif
}
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
}
to_file.Finalize();
from_file.Finalize();
}
}
from_dir.Finalize();
return true;
}
u32 GetProgress()
{
return s_Progress;
}
void InitializeTransferProgress(u64 totalSize)
{
s_TotalFileSize = totalSize;
s_FinishedFileSize = 0;
}
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);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return std::memcmp(cmac, sdCmac, sizeof(cmac)) == 0;
}
bool VerifyMac(nn::fs::FileInputStream* sdFile, nn::fs::FileStream* nandFile, s64 sdFileSize, s64 nandFileSize,
const wchar_t* nandPath, void* buf, size_t bufSize)
{
nn::Result result;
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);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = sdFile->TryRead(&readSize, sdCmac, sizeof(sdCmac));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
sdFile->Finalize();
nandFile->SetPosition(0);
// ハッシュを計算する
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
nn::crypto::Sha256Context context;
context.Initialize();
// 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 = nandFileSize;
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(&enc, sizeof(enc));
bool retValue = false;
size_t totalReadSize = 0;
while (1)
{
result = nandFile->TryRead(&readSize, buf, bufSize / 2);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retValue = false;
break;
}
else
{
totalReadSize += readSize;
if (readSize == 0)
{
retValue = CalculateAndCompareCmac(&context, sdCmac);
break;
}
else
{
u8 paddingSize = 0;
AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*>(buf), bufSize / 2, &readSize);
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);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retValue = false;
break;
}
}
}
}
nn::crypto::Finalize();
nandFile->Finalize();
return retValue;
}
bool ConfirmFile(nn::fs::FileInputStream* from_file, nn::fs::FileStream* to_file, s64 sdFileSize, s64 nandFileSize,
void* buf, size_t bufSize, const wchar_t* sdPath, const wchar_t* tmpPath, const wchar_t* truePath)
{
nn::Result result;
NN_LOG("Verify CMAC %ls\n", sdPath);
if (!VerifyMac(from_file, to_file, sdFileSize, nandFileSize, truePath, buf, bufSize))
{
// 検証に失敗したので削除する
s_FinishedFileSize -= nandFileSize;
COMMON_LOGGER("**********Verification Failed %s, Delete**********\n", GetCharStr(sdPath));
result = nn::fs::TryDeleteFile(tmpPath);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return false;
}
else
{
NN_LOG("Verification Success %s, Rename\n", GetCharStr(sdPath));
// 書き込み先を削除する
result = nn::fs::TryDeleteFile(truePath);
if (result.IsFailure() && !nn::fs::ResultNotFound::Includes(result))
{
COMMON_LOGGER("**********Verification Failed %s, Delete**********\n", GetCharStr(sdPath));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
// 正しいファイル名にリネームする
result = nn::fs::TryRenameFile(tmpPath, truePath);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsFailure())
{
COMMON_LOGGER("**********Verification Failed %s, Delete**********\n", GetCharStr(sdPath));
s_FinishedFileSize -= nandFileSize;
return false;
}
}
return true;
}
//! @brief 入力データの末尾16バイトをPKCS5で必要バイト数パディングする
//! @param[out] paddingSize パディングしたバイト数
//! @param[in] buf 入力データの入ったバッファ
//! @param[in] bufSize バッファサイズ
//! @param[inout] readSize バッファに読み込んだバイト数。書き込み時に参照するためパディングしたら増加させる
void AddPkcsPadding(u8* paddingSize, void* buf, size_t bufSize, s32* readSize)
{
if (*readSize < bufSize)
{
if ((*readSize % AES_BLOCK_SIZE) != 0)
{
*paddingSize = AES_BLOCK_SIZE - *readSize % AES_BLOCK_SIZE;
std::memset(reinterpret_cast<bit8*>(buf) + *readSize, *paddingSize, *paddingSize);
*readSize += *paddingSize;
}
}
}
//! @brief パスにnimのセーブデータディレクトリが含まれているかどうかを返します
//! @param[in] str パス
//! @return パスにnimのセーブデータディレクトリが含まれているか
bool ContainsNimSaveDataDir(const wchar_t* str)
{
return std::wcsstr(str, common::NIM_SAVEDATA_DIRECTORY_NAME) != NULL;
}
//! @brief ファイルに文字列とサイズをカンマ区切り、改行付きで追加します
//! @param[in] file 文字列を出力したいファイル
//! @param[in] str 入力文字列
//! @param[in] fileSize サイズ
//! @param[in] context SHA-256計算用コンテキスト
bool AddPathNameAndUpdateContext(nn::fs::FileOutputStream* file, const wchar_t *str, s64 fileSize,
nn::crypto::Sha256Context* context)
{
nn::Result result;
s32 writeSize;
if(ContainsNimSaveDataDir(str))
{
return true;
}
std::string output(GetCharStr(str));
result = file->TryWrite(&writeSize, output.c_str(), output.size(), true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(output.c_str(), output.size());
char comma = ',';
result = file->TryWrite(&writeSize, &comma, sizeof(comma), true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(&comma, sizeof(comma));
char sizeStr[10];
std::memset(sizeStr, 0, sizeof(sizeStr));
s32 sizeStrSize = std::snprintf(sizeStr, sizeof(sizeStr), "%lld", fileSize);
result = file->TryWrite(&writeSize, sizeStr, sizeStrSize, true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(sizeStr, sizeStrSize);
char newLine = '\n';
result = file->TryWrite(&writeSize, &newLine, sizeof(newLine), true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(&newLine, sizeof(newLine));
return true;
}
nn::Result CalculateFileSizeRecursively(std::wstring currentDirectory, s64& fileSize)
{
nn::fs::Directory dir;
nn::fs::DirectoryEntry entry;
nn::Result result;
NN_LOG("%s\n", common::GetCharStr(currentDirectory.c_str()));
result = dir.TryInitialize(currentDirectory.c_str());
if(result.IsFailure())
{
return result;
}
for (;;)
{
s32 numRead;
result = dir.TryRead(&numRead, &entry, 1);
if(result.IsFailure())
{
continue;
}
if(numRead == 0)
{
break;
}
if (std::wcscmp(entry.entryName, L".") == 0 || std::wcscmp(entry.entryName, L"..") == 0)
{
continue;
}
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
result = CalculateFileSizeRecursively(currentDirectory + std::wstring(entry.entryName) + std::wstring(L"/"), fileSize);
NN_UTIL_RETURN_IF_FAILED(result);
}
// ファイルの場合
else
{
nn::fs::FileInputStream file;
std::wstring filePath = (currentDirectory + std::wstring(entry.entryName)).c_str();
const wchar_t* path = filePath.c_str();
result = file.TryInitialize(path);
if(result.IsFailure())
{
continue;
}
fileSize += file.GetSize();
}
}
return nn::ResultSuccess();
}
}