diff --git a/trunk/ConsoleDataMigration/ConsoleBackup/Exporter.cpp b/trunk/ConsoleDataMigration/ConsoleBackup/Exporter.cpp index 99208cf..dd05021 100644 --- a/trunk/ConsoleDataMigration/ConsoleBackup/Exporter.cpp +++ b/trunk/ConsoleDataMigration/ConsoleBackup/Exporter.cpp @@ -225,12 +225,6 @@ void WriteIvs() { 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; size_t size; GetIvs(&ivs, &size); @@ -245,7 +239,7 @@ void WriteIvs() 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); s_SdWriter.WriteBufWithCmac(common::IVS_PATHNAME, enc, size); @@ -341,7 +335,7 @@ void WriteTwlData(enum common::TWL_PATH_INDEX path) common::CopyDirectory( (archiveString + ::std::wstring(L"/")).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); } @@ -421,7 +415,7 @@ void ExportThreadFunc() common::CopyDirectory( (::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(), - buf, bufSize); + buf, bufSize, true); common::HeapManager::GetHeap()->Free(buf); } diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/Importer.cpp b/trunk/ConsoleDataMigration/ConsoleRestore/Importer.cpp index f646adf..d1f7a55 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/Importer.cpp +++ b/trunk/ConsoleDataMigration/ConsoleRestore/Importer.cpp @@ -81,13 +81,6 @@ void ImportSaveData(); // SDからNORにNORデータをコピーする 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カードに保存してあるバージョン情報 common::VerDef s_SDVersionData; @@ -591,7 +584,7 @@ void ImportIvs() nn::crypto::Initialize(); 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); // IVS書き込み @@ -646,7 +639,7 @@ void ImportThreadFunc() common::CopyDirectory( (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH, - buf, bufSize); + buf, bufSize, false); common::HeapManager::GetHeap()->Free(buf); } @@ -1291,7 +1284,7 @@ void ImportTwlData(enum common::TWL_PATH_INDEX path) common::CopyDirectory( (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(), (archiveString + ::std::wstring(L"/")).c_str(), - buf, bufSize); + buf, bufSize, false); common::HeapManager::GetHeap()->Free(buf); } diff --git a/trunk/ConsoleDataMigration/common/Aes_define.h b/trunk/ConsoleDataMigration/common/Aes_define.h index e79fe3e..a817305 100644 --- a/trunk/ConsoleDataMigration/common/Aes_define.h +++ b/trunk/ConsoleDataMigration/common/Aes_define.h @@ -31,6 +31,14 @@ namespace common 0x87, 0xdd, 0xc6, 0xd6, 0xf2, 0xe0, 0x2c, 0xa6, 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_ */ diff --git a/trunk/ConsoleDataMigration/common/FileTransfer.cpp b/trunk/ConsoleDataMigration/common/FileTransfer.cpp index 7fad71d..091ea9a 100644 --- a/trunk/ConsoleDataMigration/common/FileTransfer.cpp +++ b/trunk/ConsoleDataMigration/common/FileTransfer.cpp @@ -13,9 +13,17 @@ $Rev$ *---------------------------------------------------------------------------*/ -#include "FileTransfer.h" #include +#include +#include +#include +#include + +#include "Aes_define.h" +#include "FileTransfer.h" +#include "CommonLogger.h" + 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::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::DirectoryEntry entry; @@ -140,7 +160,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf target_from << 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; } @@ -177,6 +197,18 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf } 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 = 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 { + nn::crypto::SwAesCtrContext swAesCtrContest; + swAesCtrContest.Initialize(iv, common::key, sizeof(key)); + + size_t totalReadSize = 0; + nn::crypto::Sha256Context context; + context.Initialize(); + while (1) { - result = from_file.TryRead(&readsize, buf, bufSize); + // バッファの後半半分を暗号・復号用に使う + result = from_file.TryRead(&readsize, buf, bufSize / 2); + totalReadSize += readsize; 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(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(); if (result.IsFailure()) { @@ -211,15 +271,63 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf } else { - result = to_file.TryWrite(&writesize, buf, 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 (encode) + { + // 暗号化後SHA256を計算しつつ書き込み + result = swAesCtrContest.Encrypt(reinterpret_cast (buf) + bufSize / 2, + buf, readsize); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + context.Update(reinterpret_cast (buf) + bufSize / 2, readsize); + + result = to_file.TryWrite(&writesize, reinterpret_cast(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(buf) + bufSize / 2, buf, readsize); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = to_file.TryWrite(&writesize, reinterpret_cast(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()) { nn::dbg::PrintResult(result); ret_value = false; } + } } } @@ -246,4 +354,113 @@ void InitializeTransferProgress(u64 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); + 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; +} + } diff --git a/trunk/ConsoleDataMigration/common/FileTransfer.h b/trunk/ConsoleDataMigration/common/FileTransfer.h index cacddfb..7af37f2 100644 --- a/trunk/ConsoleDataMigration/common/FileTransfer.h +++ b/trunk/ConsoleDataMigration/common/FileTransfer.h @@ -24,7 +24,7 @@ namespace common { 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(); void InitializeTransferProgress(u64 totalSize); diff --git a/trunk/ConsoleDataMigration/common/SdReaderWriter.cpp b/trunk/ConsoleDataMigration/common/SdReaderWriter.cpp index d5870cc..4bea638 100644 --- a/trunk/ConsoleDataMigration/common/SdReaderWriter.cpp +++ b/trunk/ConsoleDataMigration/common/SdReaderWriter.cpp @@ -23,6 +23,8 @@ #include #include +#include + namespace common { @@ -216,7 +218,10 @@ nn::Result SdReaderWriter::ReadBufWithCmac(const wchar_t* path, void* buf, size_ if(std::memcmp(reinterpret_cast(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(); }