nand:/data以下出力時にAES暗号化し、ファイルのSHA256を計算してAES-CMACを付加するように

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@137 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
N2614 2011-03-14 10:02:24 +00:00
parent eff9bf92df
commit 4dc123cbf9
6 changed files with 246 additions and 29 deletions

View File

@ -225,12 +225,6 @@ void WriteIvs()
{ {
COMMON_LOGGER("Export IVS.\n"); COMMON_LOGGER("Export IVS.\n");
bit8 iv[AES_BLOCK_SIZE] =
{
0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f,
0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9
};
void* ivs; void* ivs;
size_t size; size_t size;
GetIvs(&ivs, &size); GetIvs(&ivs, &size);
@ -245,7 +239,7 @@ void WriteIvs()
nn::crypto::SwAesCtrContext swAesCtrContest; nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(iv, common::key, sizeof(common::key)); swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
swAesCtrContest.Encrypt(enc, ivs, size); swAesCtrContest.Encrypt(enc, ivs, size);
s_SdWriter.WriteBufWithCmac(common::IVS_PATHNAME, enc, size); s_SdWriter.WriteBufWithCmac(common::IVS_PATHNAME, enc, size);
@ -341,7 +335,7 @@ void WriteTwlData(enum common::TWL_PATH_INDEX path)
common::CopyDirectory( common::CopyDirectory(
(archiveString + ::std::wstring(L"/")).c_str(), (archiveString + ::std::wstring(L"/")).c_str(),
(common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(), (common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(),
buf, bufSize); buf, bufSize, true);
common::HeapManager::GetHeap()->Free(buf); common::HeapManager::GetHeap()->Free(buf);
} }
@ -421,7 +415,7 @@ void ExportThreadFunc()
common::CopyDirectory( common::CopyDirectory(
(::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str(), (::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str(),
(common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str(), (common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str(),
buf, bufSize); buf, bufSize, true);
common::HeapManager::GetHeap()->Free(buf); common::HeapManager::GetHeap()->Free(buf);
} }

View File

@ -81,13 +81,6 @@ void ImportSaveData();
// SDからNORにNORデータをコピーする // SDからNORにNORデータをコピーする
void ImportNorData(); void ImportNorData();
// IVS復号化用IV
bit8 s_IvsDecryptIv[AES_BLOCK_SIZE] =
{
0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f,
0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9
};
// SDカードに保存してあるバージョン情報 // SDカードに保存してあるバージョン情報
common::VerDef s_SDVersionData; common::VerDef s_SDVersionData;
@ -591,7 +584,7 @@ void ImportIvs()
nn::crypto::Initialize(); nn::crypto::Initialize();
nn::crypto::SwAesCtrContext swAesCtrContest; nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(s_IvsDecryptIv, common::key, sizeof(common::key)); swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
swAesCtrContest.Decrypt(dec, enc, readSize); swAesCtrContest.Decrypt(dec, enc, readSize);
// IVS書き込み // IVS書き込み
@ -646,7 +639,7 @@ void ImportThreadFunc()
common::CopyDirectory( common::CopyDirectory(
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(),
common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH, common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH,
buf, bufSize); buf, bufSize, false);
common::HeapManager::GetHeap()->Free(buf); common::HeapManager::GetHeap()->Free(buf);
} }
@ -1291,7 +1284,7 @@ void ImportTwlData(enum common::TWL_PATH_INDEX path)
common::CopyDirectory( common::CopyDirectory(
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(), (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(),
(archiveString + ::std::wstring(L"/")).c_str(), (archiveString + ::std::wstring(L"/")).c_str(),
buf, bufSize); buf, bufSize, false);
common::HeapManager::GetHeap()->Free(buf); common::HeapManager::GetHeap()->Free(buf);
} }

View File

@ -31,6 +31,14 @@ namespace common
0x87, 0xdd, 0xc6, 0xd6, 0xf2, 0xe0, 0x2c, 0xa6, 0x87, 0xdd, 0xc6, 0xd6, 0xf2, 0xe0, 0x2c, 0xa6,
0x04, 0x21, 0x9c, 0x5e, 0x33, 0x8c, 0x3d, 0xaa 0x04, 0x21, 0x9c, 0x5e, 0x33, 0x8c, 0x3d, 0xaa
}; };
const bit8 iv[AES_BLOCK_SIZE] =
{
0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f,
0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9
};
} }
#endif /* AES_DEFINE_H_ */ #endif /* AES_DEFINE_H_ */

View File

@ -13,9 +13,17 @@
$Rev$ $Rev$
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
#include "FileTransfer.h"
#include <vector> #include <vector>
#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"
namespace common namespace common
{ {
@ -28,6 +36,17 @@ u64 s_Progress = 0;
} }
bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bufSize);
const char* GetCharStr(const wchar_t* path)
{
static char filename[256];
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, u32& fileSize) nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, u32& fileSize)
{ {
nn::fs::FileInputStream fis; nn::fs::FileInputStream fis;
@ -86,7 +105,8 @@ nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, u32& fi
// アーカイブにマウントした状態で呼び出す必要あり // アーカイブにマウントした状態で呼び出す必要あり
// 書き込み先のディレクトリはあらかじめ消去しておくこと。 // 書き込み先のディレクトリはあらかじめ消去しておくこと。
// 引数はスラッシュ付き // 引数はスラッシュ付き
bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf, const size_t bufSize) // TODO:分割して短くする
bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf, const size_t bufSize, bool encode)
{ {
nn::fs::Directory from_dir; nn::fs::Directory from_dir;
nn::fs::DirectoryEntry entry; nn::fs::DirectoryEntry entry;
@ -140,7 +160,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
target_from << L"/"; target_from << L"/";
target_to << L"/"; target_to << L"/";
// 再帰処理 // 再帰処理
if (!CopyDirectory(target_from.str().c_str(), target_to.str().c_str(), buf, bufSize)) if (!CopyDirectory(target_from.str().c_str(), target_to.str().c_str(), buf, bufSize, encode))
{ {
ret_value = false; ret_value = false;
} }
@ -177,6 +197,18 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
} }
else 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;
}
}
// 書き込み対象ファイル作成 // 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(target_to.str().c_str(), filesize); result = nn::fs::TryCreateFile(target_to.str().c_str(), filesize);
result = to_file.TryInitialize(target_to.str().c_str(), false); result = to_file.TryInitialize(target_to.str().c_str(), false);
@ -187,9 +219,18 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
} }
else else
{ {
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(iv, common::key, sizeof(key));
size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
while (1) while (1)
{ {
result = from_file.TryRead(&readsize, buf, bufSize); // バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
totalReadSize += readsize;
if (result.IsFailure()) if (result.IsFailure())
{ {
@ -201,6 +242,25 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
{ {
if (readsize == 0) 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_RESULT_IF_FAILED_WITH_LINE(result);
result = to_file.TryWrite(&writesize, cmac, sizeof(cmac));
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
}
result = to_file.TryFlush(); result = to_file.TryFlush();
if (result.IsFailure()) if (result.IsFailure())
{ {
@ -211,15 +271,63 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
} }
else else
{ {
result = to_file.TryWrite(&writesize, buf, readsize, false); if (encode)
s_FinishedFileSize += readsize; {
s_Progress = s_FinishedFileSize * 100/ s_TotalFileSize; // 暗号化後SHA256を計算しつつ書き込み
NN_LOG("finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress); result = swAesCtrContest.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);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2 , readsize, false);
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
{
// ハッシュ検証は通っているので復号化しつつ書き込み
// ハッシュ部分は書き込まないよう書き込みサイズを取得する
// ハッシュ部分まで読んだかどうか
bool readDone = false;
// ハッシュ部分まで読んでいたら書き込みサイズを減らす
size_t fileSizeWithoutCmac = filesize - nn::crypto::AES_CMAC_MAC_SIZE;
if (fileSizeWithoutCmac < totalReadSize)
{
readsize -= totalReadSize - fileSizeWithoutCmac;
readDone = true;
s_FinishedFileSize += nn::crypto::AES_CMAC_MAC_SIZE;
}
result = swAesCtrContest.Decrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2 , readsize, false);
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();
if (result.IsFailure())
{
ret_value = false;
}
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
break;
}
}
if (result.IsFailure()) if (result.IsFailure())
{ {
nn::dbg::PrintResult(result); nn::dbg::PrintResult(result);
ret_value = false; ret_value = false;
} }
} }
} }
} }
@ -246,4 +354,113 @@ void InitializeTransferProgress(u64 totalSize)
s_FinishedFileSize = 0; 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);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
return std::memcmp(cmac, sdCmac, sizeof(cmac)) == 0;
}
bool VerifyMac(nn::fs::FileInputStream* file, s64 filesize, void* buf, size_t bufSize)
{
nn::Result result;
bit8 sdCmac[nn::crypto::AES_CMAC_MAC_SIZE];
// ハッシュが付加されていないとエラー
if(filesize < nn::crypto::AES_CMAC_MAC_SIZE)
{
return false;
}
s32 readSize;
// ハッシュを取得する
nn::crypto::Initialize();
result = file->TrySetPosition(filesize - nn::crypto::AES_CMAC_MAC_SIZE);
if (result.IsSuccess())
{
result = file->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;
}
file->SetPosition(0);
// ハッシュを計算する
nn::crypto::Sha256Context context;
context.Initialize();
bool ret_value = false;
size_t totalReadSize = 0;
while (1)
{
result = file->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);
break;
}
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;
}
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
}
}
}
nn::crypto::Finalize();
file->SetPosition(0);
return ret_value;
}
} }

View File

@ -24,7 +24,7 @@ namespace common
{ {
nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, u32& fileSize); nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, u32& fileSize);
bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf, const size_t bufSize); bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf, const size_t bufSize, bool encode);
u32 GetProgress(); u32 GetProgress();
void InitializeTransferProgress(u64 totalSize); void InitializeTransferProgress(u64 totalSize);

View File

@ -23,6 +23,8 @@
#include <nn/crypto/crypto_Sha256.h> #include <nn/crypto/crypto_Sha256.h>
#include <nn/crypto/crypto_SwAesCmac.h> #include <nn/crypto/crypto_SwAesCmac.h>
#include <cstdlib>
namespace common namespace common
{ {
@ -216,7 +218,10 @@ nn::Result SdReaderWriter::ReadBufWithCmac(const wchar_t* path, void* buf, size_
if(std::memcmp(reinterpret_cast<bit8*>(buf) + *totalSize, cmac, sizeof(cmac)) != 0) if(std::memcmp(reinterpret_cast<bit8*>(buf) + *totalSize, cmac, sizeof(cmac)) != 0)
{ {
// 無効なファイル // 無効なファイル
COMMON_LOGGER("Verification Failed\n"); char filename[256];
std::wcstombs(filename, path, sizeof(filename));
filename[sizeof(filename) - 1] = '\0';
COMMON_LOGGER("Verification Failed %s\n", filename);
return nn::fs::ResultVerificationFailed(); return nn::fs::ResultVerificationFailed();
} }