FalsifyTwlBackup:カテゴリ処理におけるマジックナンバーの排除、マルチコンテンツ対応

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@30 6b0af911-cb57-b745-895f-eec5701120e1
This commit is contained in:
n2460 2011-10-22 07:47:10 +00:00
parent f20e008a2d
commit feaf55c5d1
7 changed files with 232 additions and 130 deletions

View File

@ -36,7 +36,7 @@ partial class Program
break;
case 101:
ReplaceImproperData(blocksForFalsifying[INDEX_BANNER].body, improperData);
ReplaceImproperData(blocksForFalsifying[SECTION_BANNER].body, improperData);
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -72,7 +72,7 @@ partial class Program
break;
case 108:
ReplaceImproperData(blocksForFalsifying[INDEX_TMD].body, improperData);
ReplaceImproperData(blocksForFalsifying[SECTION_TMD].body, improperData);
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -88,7 +88,7 @@ partial class Program
break;
case 111:
ReplaceImproperData(blocksForFalsifying[INDEX_CONTENT].body, improperData);
ReplaceImproperData(blocksForFalsifying[SECTION_CONTENT].body, improperData);
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -104,7 +104,7 @@ partial class Program
break;
case 114:
ReplaceImproperData(blocksForFalsifying[INDEX_PUBLIC_SAVE].body, improperData);
ReplaceImproperData(blocksForFalsifying[SECTION_PUBLIC_SAVE].body, improperData);
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -120,7 +120,7 @@ partial class Program
break;
case 117:
ReplaceImproperData(blocksForFalsifying[INDEX_SUB_BANNER].body, improperData);
ReplaceImproperData(blocksForFalsifying[SECTION_SUB_BANNER].body, improperData);
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;

View File

@ -72,26 +72,30 @@ partial class Program
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// TMD の fileSize を変更
case 207:
header.fileSizes[0]++;
header.fileSizes[(int)Utility.SectionIndex.TMD]++;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// コンテンツ[0] の fileSize を変更
case 208:
header.fileSizes[1]++;
header.fileSizes[(int)Utility.SectionIndex.CONTENT]++;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize を変更
case 209:
header.fileSizes[2]++;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE]++;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// sub banner の fileSize を変更
case 210:
header.fileSizes[3]++;
header.fileSizes[(int)Utility.SectionIndex.SUB_BANNER]++;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -117,8 +121,9 @@ partial class Program
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize, TMD Reserved の publicSaveSize を変更
case 214:
header.fileSizes[2]++;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE]++;
header.tmdReserved.publicSaveSize++;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);

View File

@ -42,50 +42,58 @@ partial class Program
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// TMD の fileSize を大きくした上で、コンテンツデータの前に不正なデータを入れる
case 402:
header.fileSizes[0] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.TMD] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_TMD, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// TMD の fileSize を大きくした上で、コンテンツデータの後ろに不正なデータを入れる
case 403:
header.fileSizes[0] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.TMD] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_TMD, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// コンテンツ[0] の fileSize を大きくした上で、コンテンツデータの前に不正なデータを入れる
case 404:
header.fileSizes[1] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.CONTENT] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_CONTENT, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// コンテンツ[0] の fileSize を大きくした上で、コンテンツデータの後ろに不正なデータを入れる
case 405:
header.fileSizes[1] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.CONTENT] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_CONTENT, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize を大きくした上で、public save の前に不正なデータを入れる
case 406:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_PUBLIC_SAVE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize を大きくした上で、public save の後ろに不正なデータを入れる
case 407:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_PUBLIC_SAVE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// サブバナーの fileSize を大きくした上で、サブバナーの前に不正なデータを入れる
case 408:
header.fileSizes[3] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.SUB_BANNER] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_SUB_BANNER, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// サブバナーの fileSize を大きくした上で、サブバナーの後ろに不正なデータを入れる
case 409:
header.fileSizes[3] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.SUB_BANNER] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_SUB_BANNER, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -102,15 +110,17 @@ partial class Program
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize, TMD Reserved の publicSave を変更し、public save の前にデータを入れる
case 412:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
header.tmdReserved.publicSaveSize += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_PUBLIC_SAVE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize, TMD Reserved の publicSave を変更し、public save の後ろにデータを入れる
case 413:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
header.tmdReserved.publicSaveSize += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_PUBLIC_SAVE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);

View File

@ -42,50 +42,66 @@ partial class Program
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// TMD の fileSize を大きくした上で、コンテンツデータの前に不正なデータを入れる
// TMD ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 502:
header.fileSizes[0] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.TMD] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_TMD, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// TMD の fileSize を大きくした上で、コンテンツデータの後ろに不正なデータを入れる
// TMD ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 503:
header.fileSizes[0] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.TMD] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_TMD, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// コンテンツ[0] の fileSize を大きくした上で、コンテンツデータの前に不正なデータを入れる
// コンテンツ[0] ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 504:
header.fileSizes[1] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.CONTENT] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_CONTENT, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// コンテンツ[0] の fileSize を大きくした上で、コンテンツデータの後ろに不正なデータを入れる
// コンテンツ[0] ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 505:
header.fileSizes[1] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.CONTENT] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_CONTENT, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize を大きくした上で、public save の前に不正なデータを入れる
// public save ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 506:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_PUBLIC_SAVE, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize を大きくした上で、public save の後ろに不正なデータを入れる
// public save ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 507:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_PUBLIC_SAVE, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// サブバナーの fileSize を大きくした上で、サブバナーの前に不正なデータを入れる
// サブバナーブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 508:
header.fileSizes[3] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.SUB_BANNER] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_SUB_BANNER, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// サブバナーの fileSize を大きくした上で、サブバナーの後ろに不正なデータを入れる
// サブバナーブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 509:
header.fileSizes[3] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.SUB_BANNER] += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_SUB_BANNER, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
@ -102,15 +118,19 @@ partial class Program
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize, TMD Reserved の publicSave を変更し、public save の前にデータを入れる
// public save ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 512:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
header.tmdReserved.publicSaveSize += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, FRONT_PUBLIC_SAVE, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break;
// public save の fileSize, TMD Reserved の publicSave を変更し、public save の後ろにデータを入れる
// public save ブロックの MAC を更新し、署名ブロック内ハッシュも更新する
case 513:
header.fileSizes[2] += IMPROPER_DATA_SIZE;
header.fileSizes[(int)Utility.SectionIndex.PUBLIC_SAVE] += IMPROPER_DATA_SIZE;
header.tmdReserved.publicSaveSize += IMPROPER_DATA_SIZE;
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, REAR_PUBLIC_SAVE, CHG_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData);

View File

@ -12,33 +12,35 @@ namespace FalsifyTwlBackup
{
partial class Program
{
// ブロックのインデックス
private const int INDEX_BANNER = 0;
private const int INDEX_HEADER = 1;
private const int INDEX_SIGNATURE = 2;
private const int INDEX_TMD = 3;
private const int INDEX_CONTENT = 4;
private const int INDEX_PUBLIC_SAVE = 5;
private const int INDEX_SUB_BANNER = 6;
private const int MAX_CONTENTS = 8;
// ブロックセクション
private const int SECTION_BANNER = 0;
private const int SECTION_HEADER = 1;
private const int SECTION_SIGNATURE = 2;
private const int SECTION_TMD = 3;
private const int SECTION_CONTENT = 4;
private const int SECTION_PUBLIC_SAVE = SECTION_CONTENT + MAX_CONTENTS;
private const int SECTION_SUB_BANNER = SECTION_PUBLIC_SAVE + 1;
// データの挿入位置
private const int NONE = -1;
private const int FRONT_BANNER = 10; // ブロック内データ本体の前
private const int FRONT_HEADER = 11;
private const int FRONT_SIGNATURE = 12;
private const int FRONT_TMD = 13;
private const int FRONT_CONTENT = 14;
private const int FRONT_PUBLIC_SAVE = 15;
private const int FRONT_SUB_BANNER = 16;
private const int FRONT_BANNER = 100; // ブロック内データ本体の前
private const int FRONT_HEADER = 101;
private const int FRONT_SIGNATURE = 102;
private const int FRONT_TMD = 103;
private const int FRONT_CONTENT = 104;
private const int FRONT_PUBLIC_SAVE = FRONT_CONTENT + MAX_CONTENTS;
private const int FRONT_SUB_BANNER = FRONT_PUBLIC_SAVE + 1;
private const int REAR_BANNER = 20; // ブロック内データ本体の後
private const int REAR_HEADER = 21;
private const int REAR_SIGNATURE = 22;
private const int REAR_TMD = 23;
private const int REAR_CONTENT = 24;
private const int REAR_PUBLIC_SAVE = 25;
private const int REAR_SUB_BANNER = 26;
private const int REAR_BANNER = 200; // ブロック内データ本体の後
private const int REAR_HEADER = 201;
private const int REAR_SIGNATURE = 202;
private const int REAR_TMD = 203;
private const int REAR_CONTENT = 204;
private const int REAR_PUBLIC_SAVE = REAR_CONTENT + MAX_CONTENTS;
private const int REAR_SUB_BANNER = REAR_PUBLIC_SAVE + 1;
private const int REAR_DATA = 99; // データ全体の後
@ -78,14 +80,13 @@ partial class Program
private const int NC_MAC_AND_HASHSET = 0;
private const int CHG_MAC_AND_HASHSET = 1;
private const int BLOCK_NUM = 7; // バックアップデータのブロックの個数
private const int BLOCK_NUM = 14; // バックアップデータのブロックの個数
private const int IMPROPER_DATA_SIZE = 16 * 1024; // 不正なデータのサイズ(16 KB)
private const int KEY_SIZE = 16; // 鍵のサイズ(16 Byte)
private const int HASH_SIZE = 32; // ハッシュのサイズ(32 Byte)
private const int AES_BLOCK_SIZE = 16 * 8; // 暗号化のブロックサイズ(16Byte)
private const string EXTENSION = ".bin"; // TwlBackupファイルの拡張子
/// <summary>
/// 使用方法を表示します。
/// </summary>
@ -265,45 +266,47 @@ partial class Program
/// </summary>
/// <param name="dataBlocks">変更対象となる署名ブロックを有するBlocks</param>
/// <param name="hash">新しいハッシュ値</param>
/// <param name="index">変更するブロックのインデックス</param>
static void ChangeHashSet(Blocks dataBlocks, byte[] hash, int index)
/// <param name="section">変更するブロックセクション</param>
static void ChangeHashSet(Blocks dataBlocks, byte[] hash, int section)
{
Debug.Assert((index <= BLOCK_NUM - 1) && (index >= 0));
Debug.Assert((section <= BLOCK_NUM - 1) && (section >= 0));
SignatureBody signature;
signature = (SignatureBody)dataBlocks.signature.body;
switch (index)
if (SECTION_CONTENT <= section && section < SECTION_CONTENT + MAX_CONTENTS)
{
case INDEX_BANNER:
hash.CopyTo(signature.digest.banner, 0);
break;
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.CONTENT + section - SECTION_CONTENT], 0);
}
else
{
switch (section)
{
case SECTION_BANNER:
hash.CopyTo(signature.digest.banner, 0);
break;
case INDEX_HEADER:
hash.CopyTo(signature.digest.header, 0);
break;
case SECTION_HEADER:
hash.CopyTo(signature.digest.header, 0);
break;
case INDEX_TMD:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.TMD], 0);
break;
// TODO : マルチコンテンツ対応
case INDEX_CONTENT:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.CONTENT], 0);
break;
case SECTION_TMD:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.TMD], 0);
break;
case INDEX_PUBLIC_SAVE:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PUBLIC_SAVE], 0);
break;
case SECTION_PUBLIC_SAVE:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PUBLIC_SAVE], 0);
break;
case INDEX_SUB_BANNER:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.SUB_BANNER], 0);
break;
case SECTION_SUB_BANNER:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.SUB_BANNER], 0);
break;
// TODO : Private Save 追加
// TODO : Private Save 追加
default:
Debug.Assert(false);
break;
default:
Debug.Assert(false);
break;
}
}
}
@ -339,33 +342,33 @@ partial class Program
/// 必要に応じて不正データを挿入します。
/// </summary>
/// <param name="dataBlocks">暗号化するBlockを持つBlocks</param>
/// <param name="index">暗号化するBlockのインデックス</param>
/// <param name="section">暗号化するBlockのセクション</param>
/// <param name="prop">バックアップデータに関するインスタンス</param>
/// <param name="impData">挿入する不正データ</param>
/// <param name="insertPos">挿入する位置</param>
/// <param name="byteMac">格納するMAC</param>
/// <param name="byteHash">MACを算出するためのハッシュ値</param>
/// <returns>データ本体、MAC、IVを順に結合したbyte列</returns>
static byte[] EncryptBlock(Blocks dataBlocks, int index, Properties prop, byte[] impData, int insertPos, byte[] byteMac, byte[] byteHash = null)
static byte[] EncryptBlock(Blocks dataBlocks, int section, Properties prop, byte[] impData, int insertPos, byte[] byteMac, byte[] byteHash = null)
{
byte[] encryptedBlock = new byte[0];
// (データ本体の前に不正データ挿入)
if (insertPos >= FRONT_BANNER && insertPos <= FRONT_SUB_BANNER)
{
if (index == insertPos - 10)
if (section == insertPos - FRONT_BANNER)
{
encryptedBlock = MergeByteArray(encryptedBlock, impData);
}
}
// データ本体を暗号化
encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[index].body.GetBytes()); // bodyを暗号化
encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[section].body.GetBytes()); // bodyを暗号化
// (データ本体の後に不正データ挿入)
if (insertPos >= REAR_BANNER && insertPos <= REAR_SUB_BANNER)
{
if (index == insertPos - 20)
if (section == insertPos - REAR_BANNER)
{
encryptedBlock = MergeByteArray(encryptedBlock, impData);
}
@ -378,12 +381,12 @@ partial class Program
byteMac = Utility.GetAesCmac(byteHash, prop.macKeyData); // SHA256ハッシュからMACを算出
}
encryptedBlock = Utility.EncryptBody(encryptedBlock, prop.keyData, dataBlocks[index].iv); // データ本体を暗号化
encryptedBlock = Utility.EncryptBody(encryptedBlock, prop.keyData, dataBlocks[section].iv); // データ本体を暗号化
encryptedBlock = MergeByteArray(encryptedBlock, byteMac); // MACを結合
encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[index].iv); // IVを結合
encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[section].iv); // IVを結合
// (データブロックの後に不正データ挿入)
if (index == INDEX_SUB_BANNER && insertPos == REAR_DATA)
if (section == SECTION_SUB_BANNER && insertPos == REAR_DATA)
{
encryptedBlock = MergeByteArray(encryptedBlock, impData);
}
@ -417,16 +420,23 @@ partial class Program
for (int i = 0; i < BLOCK_NUM; i++) // 署名部以外を暗号化byte列に結合
{
byteHash[i] = new byte[HASH_SIZE];
if (i != INDEX_SIGNATURE)
if (i != SECTION_SIGNATURE)
{
encryptedBlocks[i] = EncryptBlock(dataBlocks, i, prop, impData, insertPos, byteMac[i], byteHash[i]); // ブロックを暗号化&結合
ChangeHashSet(dataBlocks, byteHash[i], i); // ハッシュセットを更新
if (dataBlocks[i].body != null)
{
encryptedBlocks[i] = EncryptBlock(dataBlocks, i, prop, impData, insertPos, byteMac[i], byteHash[i]); // ブロックを暗号化&結合
ChangeHashSet(dataBlocks, byteHash[i], i); // ハッシュセットを更新
}
else
{
encryptedBlocks[i] = null;
}
}
}
// 最後に署名部を暗号化byte列に結合
byteHash[INDEX_SIGNATURE] = Utility.GetSha256(dataBlocks[INDEX_SIGNATURE].body.GetBytes()); // 平文からSHA256ハッシュ算出
byteMac[INDEX_SIGNATURE] = Utility.GetAesCmac(byteHash[INDEX_SIGNATURE], prop.macKeyData); // SHA256ハッシュからMACを算出
encryptedBlocks[INDEX_SIGNATURE] = EncryptBlock(dataBlocks, INDEX_SIGNATURE, prop, impData, insertPos, byteMac[INDEX_SIGNATURE]);
byteHash[SECTION_SIGNATURE] = Utility.GetSha256(dataBlocks[SECTION_SIGNATURE].body.GetBytes()); // 平文からSHA256ハッシュ算出
byteMac[SECTION_SIGNATURE] = Utility.GetAesCmac(byteHash[SECTION_SIGNATURE], prop.macKeyData); // SHA256ハッシュからMACを算出
encryptedBlocks[SECTION_SIGNATURE] = EncryptBlock(dataBlocks, SECTION_SIGNATURE, prop, impData, insertPos, byteMac[SECTION_SIGNATURE]);
}
// ( MAC & HASH SET更新しない場合 )
@ -434,7 +444,14 @@ partial class Program
{
for (int i = 0; i < BLOCK_NUM; i++)
{
encryptedBlocks[i] = EncryptBlock(dataBlocks, i, prop, impData, insertPos, dataBlocks[i].mac); // ブロックを暗号化&結合
if (dataBlocks[i].body != null)
{
encryptedBlocks[i] = EncryptBlock(dataBlocks, i, prop, impData, insertPos, dataBlocks[i].mac); // ブロックを暗号化&結合
}
else
{
encryptedBlocks[i] = null;
}
}
}
@ -442,7 +459,10 @@ partial class Program
// 暗号化した各ブロックを結合
for (int i = 0; i < BLOCK_NUM; i++)
{
outData = MergeByteArray(outData, encryptedBlocks[i]);
if (encryptedBlocks[i] != null)
{
outData = MergeByteArray(outData, encryptedBlocks[i]);
}
}
return outData;
}

View File

@ -8,13 +8,13 @@ namespace TwlBackupBlock
/// </summary>
public class Blocks : ICloneable
{
private const int NUM_BLOCKS = 7;
private const int NUM_BLOCKS = 14;
public Block banner;
public Block header;
public Block signature;
public Block tmd;
public Block content;
public Block[] content;
public Block saveData;
public Block subBanner;
@ -27,7 +27,11 @@ namespace TwlBackupBlock
header = new Block();
signature = new Block();
tmd = new Block();
content = new Block();
content = new Block[HeaderBody.MAX_CONTENTS];
for (int i = 0; i < HeaderBody.MAX_CONTENTS; i++)
{
content[i] = new Block();
}
saveData = new Block();
subBanner = new Block();
}
@ -41,24 +45,30 @@ namespace TwlBackupBlock
{
get
{
switch (index)
if (4 <= index && index < 4 + HeaderBody.MAX_CONTENTS)
{
case 0: return banner;
case 1: return header;
case 2: return signature;
case 3: return tmd;
case 4: return content;
case 5: return saveData;
case 6: return subBanner;
default:
Debug.Assert(false);
return null; // never reach
return content[index - 4];
}
else
{
switch (index)
{
case 0: return banner;
case 1: return header;
case 2: return signature;
case 3: return tmd;
case 12: return saveData;
case 13: return subBanner;
default:
Debug.Assert(false);
return null; // never reach
}
}
}
}
/// <summary>
/// ブロック数(=7を取得します。
/// ブロック数を取得します。
/// </summary>
public int Length
{
@ -79,7 +89,13 @@ namespace TwlBackupBlock
newBlocks.header = (Block)header.Clone();
newBlocks.signature = (Block)signature.Clone();
newBlocks.tmd = (Block)tmd.Clone();
newBlocks.content = (Block)content.Clone();
for (int i = 0; i < HeaderBody.MAX_CONTENTS; i++)
{
if (content[i].body != null)
{
newBlocks.content[i] = (Block)content[i].Clone();
}
}
newBlocks.saveData = (Block)saveData.Clone();
newBlocks.subBanner = (Block)subBanner.Clone();
return newBlocks;

View File

@ -86,15 +86,28 @@ namespace TwlBackupBlock
blocks.signature.body = new SignatureBody(DecryptBlock(br, SIGNATURE_SIZE, key, out blocks.signature.mac, out blocks.signature.iv));
// TORIAEZU
// TODO : 複数コンテンツ対応
// TODO : Legacy, WPS 対応
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
int CONTENT_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT];
int[] CONTENT_SIZE = new int[MAX_CONTENTS];
for (int i = 0; i < MAX_CONTENTS; i++)
{
CONTENT_SIZE[i] = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT + i];
}
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
blocks.tmd.body = new Body(DecryptBlock(br, TMD_SIZE, key, out blocks.tmd.mac, out blocks.tmd.iv));
blocks.content.body = new Body(DecryptBlock(br, CONTENT_SIZE, key, out blocks.content.mac, out blocks.content.iv));
for (int i = 0; i < MAX_CONTENTS; i++)
{
if (CONTENT_SIZE[i] > 0)
{
blocks.content[i].body = new Body(DecryptBlock(br, CONTENT_SIZE[i], key, out blocks.content[i].mac, out blocks.content[i].iv));
}
else
{
blocks.content[i].body = null;
}
}
blocks.saveData.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, key, out blocks.saveData.mac, out blocks.saveData.iv));
blocks.subBanner.body = new Body(DecryptBlock(br, SUB_BANNER_SIZE, key, out blocks.subBanner.mac, out blocks.subBanner.iv));
@ -402,13 +415,24 @@ namespace TwlBackupBlock
// TODO : 複数コンテンツ対応
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
int CONTENT_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT];
int[] CONTENT_SIZE = new int[MAX_CONTENTS];
for (int i = 0; i < MAX_CONTENTS; i++)
{
CONTENT_SIZE[i] = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT + i];
}
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) + RoundUp(CONTENT_SIZE, ROUND_SCALE) +
int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) +
RoundUp(PUBLIC_SAVE_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) +
AES_SIGN_HEADER_SIZE * 4;
AES_SIGN_HEADER_SIZE * 3;
for (int i = 0; i < MAX_CONTENTS; i++)
{
if (CONTENT_SIZE[i] > 0)
{
restSize += RoundUp(CONTENT_SIZE[i], ROUND_SCALE) + AES_SIGN_HEADER_SIZE;
}
}
if (data.Length - ms.Position != restSize)
{
Console.WriteLine("TMD、コンテンツ、publicセーブデータ、サブバナーブロックサイズが実際のサイズと一致しません");
@ -425,16 +449,23 @@ namespace TwlBackupBlock
Console.WriteLine("TMDブロックのハッシュが一致しません");
return false;
}
blocks.content.body = new Body(DecryptBlock(br, CONTENT_SIZE, aesCbcKey, out blocks.content.mac, out blocks.content.iv));
if (!CheckMac(blocks.content, aesCmacKey, blocks.content.mac))
for (int i = 0; i < MAX_CONTENTS; i++)
{
Console.WriteLine("コンテンツブロックのMACが一致しません");
return false;
}
if (!CheckHash(blocks.content, signatureBody.digest.section[(int)SectionIndex.CONTENT]))
{
Console.WriteLine("コンテンツブロックのハッシュが一致しません");
return false;
if (CONTENT_SIZE[i] > 0)
{
blocks.content[i].body =
new Body(DecryptBlock(br, CONTENT_SIZE[i], aesCbcKey, out blocks.content[i].mac, out blocks.content[i].iv));
if (!CheckMac(blocks.content[i], aesCmacKey, blocks.content[i].mac))
{
Console.WriteLine("コンテンツブロック[{0}]のMACが一致しません", i);
return false;
}
if (!CheckHash(blocks.content[i], signatureBody.digest.section[(int)SectionIndex.CONTENT + i]))
{
Console.WriteLine("コンテンツブロック[{0}]のハッシュが一致しません", i);
return false;
}
}
}
blocks.saveData.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, aesCbcKey, out blocks.saveData.mac, out blocks.saveData.iv));
if (!CheckMac(blocks.saveData, aesCmacKey, blocks.saveData.mac))