ソフトAES CTRモードが16バイトブロックモードのみのためPKCS#5でパディングするように

SD出力ファイルの先頭にヘッダをつけてファイルサイズを取得できるように
NAND書き込み時のファイルサイズを正しく設定するように
CopyDirectoryには16バイトアラインしたバッファを渡すように

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@140 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
N2614 2011-03-15 11:07:27 +00:00
parent b7781d4f37
commit 1ade502635
5 changed files with 173 additions and 100 deletions

View File

@ -326,7 +326,7 @@ void WriteTwlData(enum common::TWL_PATH_INDEX path)
// 進捗表示用 // 進捗表示用
common::InitializeTransferProgress(fileSize); common::InitializeTransferProgress(fileSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize); void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL) if (buf != NULL)
{ {
wchar_t archiveName[256]; wchar_t archiveName[256];
@ -408,7 +408,7 @@ void ExportThreadFunc()
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize(); size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize); NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize); void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL) if (buf != NULL)
{ {

View File

@ -664,7 +664,7 @@ void ImportThreadFunc()
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize(); size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize); NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize); void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL) if (buf != NULL)
{ {
@ -1316,7 +1316,7 @@ void ImportTwlData(enum common::TWL_PATH_INDEX path)
NN_LOG("File Size = %d\n", fileSize); NN_LOG("File Size = %d\n", fileSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize); void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL) if (buf != NULL)
{ {
wchar_t archiveName[256]; wchar_t archiveName[256];

View File

@ -20,7 +20,7 @@
namespace common namespace common
{ {
const bit8 key[AES_KEY_SIZE] = const bit8 key[AES_KEY_SIZE] NN_ATTRIBUTE_ALIGN(4) =
{ {
0x81, 0x35, 0xc6, 0x54, 0x19, 0x1a, 0x47, 0x2a, 0x81, 0x35, 0xc6, 0x54, 0x19, 0x1a, 0x47, 0x2a,
0x6b, 0x78, 0xbe, 0x25, 0x90, 0xf6, 0xee, 0x74 0x6b, 0x78, 0xbe, 0x25, 0x90, 0xf6, 0xee, 0x74
@ -32,13 +32,11 @@ namespace common
0x04, 0x21, 0x9c, 0x5e, 0x33, 0x8c, 0x3d, 0xaa 0x04, 0x21, 0x9c, 0x5e, 0x33, 0x8c, 0x3d, 0xaa
}; };
const bit8 iv[AES_BLOCK_SIZE] = const bit8 iv[AES_BLOCK_SIZE] NN_ATTRIBUTE_ALIGN(4) =
{ {
0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f, 0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f,
0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9 0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9
}; };
} }
#endif /* AES_DEFINE_H_ */ #endif /* AES_DEFINE_H_ */

View File

@ -23,6 +23,7 @@
#include "Aes_define.h" #include "Aes_define.h"
#include "FileTransfer.h" #include "FileTransfer.h"
#include "CommonLogger.h" #include "CommonLogger.h"
#include "common_Types.h"
namespace common namespace common
{ {
@ -173,6 +174,7 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
nn::fs::FileInputStream from_file; nn::fs::FileInputStream from_file;
nn::fs::FileOutputStream to_file; nn::fs::FileOutputStream to_file;
s64 filesize; s64 filesize;
s64 fileSizeWithoutHeaderAndFooter;
s32 readsize; s32 readsize;
s32 writesize; s32 writesize;
@ -209,126 +211,192 @@ bool CopyDirectory(const wchar_t * from_path, const wchar_t * to_path, void* buf
} }
} }
// 書き込み対象ファイル作成 nn::crypto::SwAesCtrContext swAesCtrContext;
result = nn::fs::TryCreateFile(target_to.str().c_str(), filesize); swAesCtrContext.Initialize(iv, common::key, sizeof(key));
result = to_file.TryInitialize(target_to.str().c_str(), false);
if (result.IsFailure()) size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
// ファイルサイズをヘッダに書いておく
if (encode)
{ {
nn::dbg::PrintResult(result); // 書き込み対象ファイル作成
ret_value = false; result = nn::fs::TryCreateFile(target_to.str().c_str(), filesize);
result = to_file.TryInitialize(target_to.str().c_str(), false);
if (result.IsFailure())
{
nn::dbg::PrintResult(result);
ret_value = false;
}
BackupDataHeader header;
BackupDataHeader enc;
header.size = filesize;
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
context.Update(&enc, sizeof(enc));
s32 writeSize;
result = to_file.TryWrite(&writeSize, &enc, sizeof(enc), false);
if (result.IsFailure())
{
ret_value = false;
continue;
}
} }
else else
{ {
nn::crypto::SwAesCtrContext swAesCtrContest; // ヘッダを読む
swAesCtrContest.Initialize(iv, common::key, sizeof(key)); // ハッシュの計算は終わっているので復号化のみ
BackupDataHeader header;
size_t totalReadSize = 0; BackupDataHeader dec;
nn::crypto::Sha256Context context; s32 readSize;
context.Initialize(); result = from_file.TryRead(&readSize, &header, sizeof(header));
if (result.IsFailure())
while (1)
{ {
// バッファの後半半分を暗号・復号用に使う COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = from_file.TryRead(&readsize, buf, bufSize / 2); ret_value = false;
totalReadSize += readsize; continue;
}
s_FinishedFileSize += sizeof(header);
swAesCtrContext.Decrypt(&dec, &header, sizeof(header));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
fileSizeWithoutHeaderAndFooter = dec.size;
if (result.IsFailure()) // 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(target_to.str().c_str(), fileSizeWithoutHeaderAndFooter);
result = to_file.TryInitialize(target_to.str().c_str(), false);
if (result.IsFailure())
{
nn::dbg::PrintResult(result);
ret_value = false;
}
}
while (1)
{
// バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
totalReadSize += readsize;
if (result.IsFailure())
{
nn::dbg::PrintResult(result);
ret_value = false;
break;
}
else
{
if (readsize == 0)
{ {
nn::dbg::PrintResult(result); if (encode)
ret_value = false; {
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())
{
nn::dbg::PrintResult(result);
ret_value = false;
}
break; break;
} }
else else
{ {
if (readsize == 0) if (encode)
{ {
if(encode) NN_LOG("EncryptSize = %d\n", readsize);
u8 paddingSize = 0;
// 最後の書き込み時にはPKCS5でパディングする
if (readsize < bufSize / 2)
{ {
NN_LOG("Add CMAC %ls\n", target_from.str().c_str()); if ((readsize % AES_BLOCK_SIZE) != 0)
// 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); paddingSize = AES_BLOCK_SIZE - readsize % AES_BLOCK_SIZE;
ret_value = false; std::memset(reinterpret_cast<bit8*> (buf) + readsize, paddingSize,
paddingSize);
readsize += paddingSize;
} }
} }
result = to_file.TryFlush(); // 暗号化後SHA256を計算しつつ書き込み
if (result.IsFailure()) result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*> (buf) + bufSize / 2, buf,
{ readsize);
nn::dbg::PrintResult(result); COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false; context.Update(reinterpret_cast<bit8*> (buf) + bufSize / 2, readsize);
}
break; result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*> (buf) + bufSize / 2,
readsize, false);
// 事前計算したファイルサイズに一致させるためパディング分減算
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 else
{ {
if (encode) // ハッシュ検証は通っているので復号化しつつ書き込み
{ // パディング以降は書き込まないよう書き込みサイズを変更する
// 暗号化後SHA256を計算しつつ書き込み
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); NN_LOG("DecryptSize = %d\n", readsize);
s_FinishedFileSize += readsize; result = swAesCtrContext.Decrypt(reinterpret_cast<bit8*> (buf) + bufSize / 2, buf,
s_Progress = s_FinishedFileSize * 100/ s_TotalFileSize; readsize);
NN_LOG("finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress); COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// パディングまで読んだかどうか
bool readDone = false;
// パディングまで読んでいたら書き込みサイズを減らす
if (fileSizeWithoutHeaderAndFooter < totalReadSize)
{
readsize -= totalReadSize - fileSizeWithoutHeaderAndFooter;
readDone = true;
s_FinishedFileSize += totalReadSize - fileSizeWithoutHeaderAndFooter;
} }
else
{
// ハッシュ検証は通っているので復号化しつつ書き込み
// ハッシュ部分は書き込まないよう書き込みサイズを取得する
// ハッシュ部分まで読んだかどうか result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*> (buf) + bufSize / 2,
bool readDone = false; readsize, false);
// ハッシュ部分まで読んでいたら書き込みサイズを減らす s_FinishedFileSize += readsize;
size_t fileSizeWithoutCmac = filesize - nn::crypto::AES_CMAC_MAC_SIZE; s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
if (fileSizeWithoutCmac < totalReadSize) NN_LOG("finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
// 読みきったので次のファイルへ
if (readDone)
{
result = to_file.TryFlush();
if (result.IsFailure())
{ {
readsize -= totalReadSize - fileSizeWithoutCmac; ret_value = false;
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); COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
break;
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())
{
nn::dbg::PrintResult(result);
ret_value = false;
}
} }
if (result.IsFailure())
{
nn::dbg::PrintResult(result);
ret_value = false;
}
} }
} }
} }

View File

@ -80,6 +80,13 @@ const nn::ProgramId cNupVerId[] =
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_EU, nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_EU,
}; };
struct BackupDataHeader
{
s64 size; // パディングを含まないファイルサイズ
NN_PADDING4;
NN_PADDING4;
};
} }
#endif /* COMMON_TYPES_H_ */ #endif /* COMMON_TYPES_H_ */