mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
NANDに一時ファイルとして作成しCMAC検証に通ってからリネームするように
CMAC検証に失敗したらNANDから削除するように BackupDataHeaderを0クリアしてから書き込むように git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@148 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
parent
f5c3d6d0f9
commit
5ea854b610
@ -37,7 +37,11 @@ u64 s_Progress = 0;
|
||||
|
||||
}
|
||||
|
||||
bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bufSize);
|
||||
bool VerifyMac(nn::fs::FileInputStream* sdFile, nn::fs::FileStream* nandFile, s64 sdFileSize, s64 nandFileSize,
|
||||
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);
|
||||
|
||||
const char* GetCharStr(const wchar_t* path)
|
||||
{
|
||||
@ -120,7 +124,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -153,7 +157,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
result = nn::fs::TryCreateDirectory(target_to.str().c_str());
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
else
|
||||
@ -170,9 +174,22 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
// ファイルの場合
|
||||
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::FileOutputStream to_file;
|
||||
nn::fs::FileStream to_file;
|
||||
s64 filesize;
|
||||
s64 fileSizeWithoutHeaderAndFooter;
|
||||
s32 readsize;
|
||||
@ -185,7 +202,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
else
|
||||
@ -194,23 +211,11 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
result = from_file.TryGetSize(&filesize);
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 復号するならまず検証する
|
||||
if(!encode)
|
||||
{
|
||||
NN_LOG("Verify CMAC %ls\n", target_from.str().c_str());
|
||||
if(!VerifyMac(&from_file, filesize, buf, bufSize))
|
||||
{
|
||||
COMMON_LOGGER("Verification Failed %s\n", GetCharStr(target_from.str().c_str()));
|
||||
ret_value = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nn::crypto::SwAesCtrContext swAesCtrContext;
|
||||
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
|
||||
|
||||
@ -222,16 +227,20 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
if (encode)
|
||||
{
|
||||
// 書き込み対象ファイル作成
|
||||
result = nn::fs::TryCreateFile(target_to.str().c_str(), filesize);
|
||||
result = to_file.TryInitialize(target_to.str().c_str(), false);
|
||||
result = nn::fs::TryCreateFile(target_tmp.str().c_str(), filesize);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(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);
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
|
||||
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_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
@ -250,6 +259,8 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
// ハッシュの計算は終わっているので復号化のみ
|
||||
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));
|
||||
if (result.IsFailure())
|
||||
@ -264,11 +275,13 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
fileSizeWithoutHeaderAndFooter = dec.size;
|
||||
|
||||
// 書き込み対象ファイル作成
|
||||
result = nn::fs::TryCreateFile(target_to.str().c_str(), fileSizeWithoutHeaderAndFooter);
|
||||
result = to_file.TryInitialize(target_to.str().c_str(), false);
|
||||
result = nn::fs::TryCreateFile(target_tmp.str().c_str(), fileSizeWithoutHeaderAndFooter);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(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);
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
}
|
||||
@ -281,7 +294,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
break;
|
||||
}
|
||||
@ -310,11 +323,24 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
}
|
||||
|
||||
result = to_file.TryFlush();
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
|
||||
// 復号済みなら検証する
|
||||
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()))
|
||||
{
|
||||
ret_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
@ -324,17 +350,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
NN_LOG("EncryptSize = %d\n", readsize);
|
||||
|
||||
u8 paddingSize = 0;
|
||||
// 最後の書き込み時にはPKCS5でパディングする
|
||||
if (readsize < bufSize / 2)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*>(buf), bufSize / 2, &readsize);
|
||||
|
||||
// 暗号化後SHA256を計算しつつ書き込み
|
||||
result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*> (buf) + bufSize / 2, buf,
|
||||
@ -387,13 +403,21 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
|
||||
ret_value = false;
|
||||
}
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(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()))
|
||||
{
|
||||
ret_value = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
nn::dbg::PrintResult(result);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
|
||||
@ -442,13 +466,14 @@ bool CalculateAndCompareCmac(nn::crypto::Sha256Context* context, bit8* sdCmac)
|
||||
}
|
||||
|
||||
|
||||
bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bufSize)
|
||||
bool VerifyMac(nn::fs::FileInputStream* sdFile, nn::fs::FileStream* nandFile, s64 sdFileSize, s64 nandFileSize,
|
||||
void* buf, size_t bufSize)
|
||||
{
|
||||
nn::Result result;
|
||||
bit8 sdCmac[nn::crypto::AES_CMAC_MAC_SIZE];
|
||||
|
||||
// ハッシュが付加されていないとエラー
|
||||
if(filesize < nn::crypto::AES_CMAC_MAC_SIZE)
|
||||
if(sdFileSize < nn::crypto::AES_CMAC_MAC_SIZE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -456,10 +481,10 @@ bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bu
|
||||
s32 readSize;
|
||||
// ハッシュを取得する
|
||||
nn::crypto::Initialize();
|
||||
result = file->TrySetPosition(filesize - nn::crypto::AES_CMAC_MAC_SIZE);
|
||||
result = sdFile->TrySetPosition(sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
result = file->TryRead(&readSize, sdCmac, sizeof(sdCmac));
|
||||
result = sdFile->TryRead(&readSize, sdCmac, sizeof(sdCmac));
|
||||
if(result.IsFailure())
|
||||
{
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
@ -472,17 +497,32 @@ bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bu
|
||||
return false;
|
||||
}
|
||||
|
||||
file->SetPosition(0);
|
||||
sdFile->Finalize();
|
||||
|
||||
nandFile->SetPosition(0);
|
||||
|
||||
// ハッシュを計算する
|
||||
nn::crypto::SwAesCtrContext swAesCtrContext;
|
||||
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
|
||||
|
||||
nn::crypto::Sha256Context context;
|
||||
context.Initialize();
|
||||
|
||||
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_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
context.Update(&enc, sizeof(enc));
|
||||
|
||||
bool ret_value = false;
|
||||
|
||||
size_t totalReadSize = 0;
|
||||
while (1)
|
||||
{
|
||||
result = file->TryRead(&readSize, buf, bufSize);
|
||||
result = nandFile->TryRead(&readSize, buf, bufSize / 2);
|
||||
totalReadSize += readSize;
|
||||
|
||||
if (result.IsFailure())
|
||||
@ -500,21 +540,11 @@ bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bu
|
||||
}
|
||||
else
|
||||
{
|
||||
bool readDone = false;
|
||||
// ハッシュ部分まで読んでいたらハッシュ検証サイズを減らす
|
||||
size_t fileSizeWithoutCmac = filesize - nn::crypto::AES_CMAC_MAC_SIZE;
|
||||
if (fileSizeWithoutCmac < totalReadSize)
|
||||
{
|
||||
readSize -= totalReadSize - fileSizeWithoutCmac;
|
||||
readDone = true;
|
||||
}
|
||||
|
||||
context.Update(buf, readSize);
|
||||
if(readDone)
|
||||
{
|
||||
ret_value = CalculateAndCompareCmac(&context, sdCmac);
|
||||
break;
|
||||
}
|
||||
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_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
context.Update(reinterpret_cast<bit8*>(buf) + bufSize / 2 , readSize);
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
@ -525,10 +555,57 @@ bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bu
|
||||
}
|
||||
}
|
||||
nn::crypto::Finalize();
|
||||
|
||||
file->SetPosition(0);
|
||||
nandFile->Finalize();
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bool ret_value = true;
|
||||
NN_LOG("Verify CMAC %ls\n", sdPath);
|
||||
if (!VerifyMac(from_file, to_file, sdFileSize, nandFileSize, buf, bufSize))
|
||||
{
|
||||
// 検証に失敗したので削除する
|
||||
COMMON_LOGGER("Verification Failed %s, Delete\n", GetCharStr(sdPath));
|
||||
result = nn::fs::TryDeleteFile(tmpPath);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
ret_value = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
NN_LOG("Verification Success %s, Rename\n", GetCharStr(sdPath));
|
||||
// リネームする
|
||||
result = nn::fs::TryRenameFile(tmpPath, truePath);
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
|
||||
if (result.IsFailure())
|
||||
{
|
||||
ret_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
//! @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user