ctr_Repair/branches/work/RW_Aging/sources/common/FileTransfer.cpp
N2614 497edc847f NAND、SD読み書きのエージング用ブランチ
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@361 385bec56-5757-e545-9c3a-d8741f4650f1
2011-07-07 02:31:39 +00:00

770 lines
29 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::FileInputStream fis;
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;
}
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
// ファイルサイズをヘッダに書いておく
// 書き込み対象ファイル作成
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);
// フルパスをハッシュに含める
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);
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)
{
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);
break;
}
else
{
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;
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);
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;
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;
s64 fileSizeWithoutHeaderAndFooter;
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;
}
}
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
// ファイルサイズをヘッダに書いておく
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);
// フルパスをハッシュに含める
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);
}
else
{
// ヘッダを読む
// ハッシュの計算は終わっているので復号化のみ
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);
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)
{
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);
}
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 復号済みなら検証する
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;
}
}
break;
}
else
{
if (encode)
{
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;
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
{
// ハッシュ検証は通っているので復号化しつつ書き込み
// パディング以降は書き込まないよう書き込みサイズを変更する
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);
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);
// 読みきったので次のファイルへ
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;
}
}
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);
}
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;
}
}