TwlBkpCheck/Windows:ヘッダ情報の更新(今までのは Legacy としてクラス分け)

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@27 6b0af911-cb57-b745-895f-eec5701120e1
This commit is contained in:
n2460 2011-10-19 08:51:52 +00:00
parent 82f3c9c94c
commit f26671db85
9 changed files with 394 additions and 156 deletions

View File

@ -49,6 +49,7 @@ namespace FalsifyTwlBackup
private const int CAT300 = 3; private const int CAT300 = 3;
private const int CAT400 = 4; private const int CAT400 = 4;
private const int CAT500 = 5; private const int CAT500 = 5;
private const int VERIFY = 9; // TORIAEZU : 上記が Mode == Pattern なのが引っかかる・・・
// 各カテゴリでの最大番号 // 各カテゴリでの最大番号
private const int MAX_OF_CAT100 = 118; private const int MAX_OF_CAT100 = 118;
@ -90,8 +91,9 @@ namespace FalsifyTwlBackup
Console.WriteLine(" -all (default) : output all falsifying pattern"); Console.WriteLine(" -all (default) : output all falsifying pattern");
Console.WriteLine(" -cat CAT_NUM : output all pattern of CAT_NUM category"); Console.WriteLine(" -cat CAT_NUM : output all pattern of CAT_NUM category");
Console.WriteLine(" ex) -cat 100 -> falsifying 100,101,102...."); Console.WriteLine(" ex) -cat 100 -> falsifying 100,101,102....");
Console.WriteLine(" -each PAT_NUM : output PAT_NUM pattern "); Console.WriteLine(" -each PAT_NUM : output PAT_NUM pattern");
Console.WriteLine(" ex) -each 204 -> falsifying 204 only"); Console.WriteLine(" ex) -each 204 -> falsifying 204 only");
Console.WriteLine(" -verify : verify backup file");
Environment.Exit(-1); Environment.Exit(-1);
} }
@ -178,7 +180,14 @@ namespace FalsifyTwlBackup
return Convert.ToInt16(args[4]); return Convert.ToInt16(args[4]);
} }
} }
// -verify
else if (args[3].ToUpper().TrimStart('-') == "VERIFY")
{
return VERIFY;
}
} }
// それ以外 // それ以外
return ALL; return ALL;
} }
@ -257,19 +266,31 @@ namespace FalsifyTwlBackup
switch (index) switch (index)
{ {
case INDEX_BANNER: case INDEX_BANNER:
hash.CopyTo(signature.digest.banner, 0); hash.CopyTo(signature.digest.banner, 0);
break; break;
case INDEX_HEADER: case INDEX_HEADER:
hash.CopyTo(signature.digest.header, 0); hash.CopyTo(signature.digest.header, 0);
break; break;
case INDEX_TMD: case INDEX_TMD:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.TMD], 0);
break;
// TODO : マルチコンテンツ対応
case INDEX_CONTENT: case INDEX_CONTENT:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.CONTENT], 0);
break;
case INDEX_PUBLIC_SAVE: case INDEX_PUBLIC_SAVE:
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PUBLIC_SAVE], 0);
break;
case INDEX_SUB_BANNER: case INDEX_SUB_BANNER:
hash.CopyTo(signature.digest.section[index - (INDEX_SIGNATURE + 1)], 0); hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.SUB_BANNER], 0);
break; break;
// TODO : Private Save 追加
default: default:
Debug.Assert(false); Debug.Assert(false);
@ -286,38 +307,6 @@ namespace FalsifyTwlBackup
/// <returns>連結後のbyte列</returns> /// <returns>連結後のbyte列</returns>
static byte[] MergeByteArray(byte[] front, byte[] rear) static byte[] MergeByteArray(byte[] front, byte[] rear)
{ {
/* ()
byte[] merged = new byte[front.Length + rear.Length];
for (int i = 0; i < (front.Length + rear.Length); i++)
{
if (i < front.Length)
{
merged[i] = front[i];
}
else
{
merged[i] = rear[i - front.Length];
}
}
*/
/* (ifは使わないほうがいいよ)
for (int i = 0; i < front.Length; i++)
{
merged[i] = front[i];
}
for (int i = 0; i < rear.Length; i++)
{
merged[i + front.Length] = rear[i];
}
*/
/* (使)
Array.Copy(front, 0, merged, 0, front.Length);
Array.Copy(rear, 0, merged, front.Length, rear.Length);
*/
// 田中さん案3(結局1行で出来ちゃったよ;;)
return front.Concat(rear).ToArray(); return front.Concat(rear).ToArray();
} }
@ -395,7 +384,7 @@ namespace FalsifyTwlBackup
/// <summary> /// <summary>
/// 各ブロックを暗号化した後、1つのbute列に結合します。 /// 各ブロックを暗号化した後、1つの byte 列に結合します。
/// </summary> /// </summary>
/// <param name="dataBlocks">暗号化するデータ</param> /// <param name="dataBlocks">暗号化するデータ</param>
/// <param name="prop">バックアップデータに関するインスタンス</param> /// <param name="prop">バックアップデータに関するインスタンス</param>
@ -662,7 +651,10 @@ namespace FalsifyTwlBackup
break; break;
case 211: case 211:
header.contentId++; for (int i = 0; i < header.contentId.Length; i++)
{
header.contentId[i]++;
}
outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET); outData = MergeEncryptBody(blocksForFalsifying, prop, improperData, NONE, NC_MAC_AND_HASHSET);
OutputFalsifiedData(improperNo, prop.outFolderPath, outData); OutputFalsifiedData(improperNo, prop.outFolderPath, outData);
break; break;
@ -1072,7 +1064,6 @@ namespace FalsifyTwlBackup
Properties prop = new Properties(); // インスタンスの作成 Properties prop = new Properties(); // インスタンスの作成
byte[] twlBackupData = File.ReadAllBytes(twlBackupName); // バックアップデータの読み込み byte[] twlBackupData = File.ReadAllBytes(twlBackupName); // バックアップデータの読み込み
prop.SetOutputFolderPath(twlBackupName); // 出力フォルダを作成
// 鍵データの読み込み // 鍵データの読み込み
string[] keyString = File.ReadAllLines(keyName); string[] keyString = File.ReadAllLines(keyName);
@ -1092,14 +1083,25 @@ namespace FalsifyTwlBackup
// ファイル名の出力 + 鍵データの dump // ファイル名の出力 + 鍵データの dump
Console.WriteLine("Twl Backup File : {0}", twlBackupName); Console.WriteLine("Twl Backup File : {0}", twlBackupName);
Console.Write("Block Key File : {0}, ", keyName); Console.WriteLine("Block Key File : {0} ({1})", keyName, dumpArray(prop.keyData));
dumpArray("", prop.keyData); Console.WriteLine("MAC Key File : {0} ({1})", macKeyData, dumpArray(prop.macKeyData));
Console.Write("MAC Key Data : {0}, ", macKeyData);
dumpArray("", prop.macKeyData); // TORIAEZU : ひとまず VERIFY だったら検証して終了
if (falsifyingType == VERIFY)
{
if (Utility.Verify(twlBackupData, prop.keyData, prop.macKeyData))
{
Console.WriteLine("{0} は検証に成功しました。", twlBackupName);
}
Environment.Exit(0);
}
// バックアップデータを復号化 // バックアップデータを復号化
prop.decryptedBlocks = Utility.DecryptBackupData(twlBackupData, prop.keyData); prop.decryptedBlocks = Utility.DecryptBackupData(twlBackupData, prop.keyData);
// 出力フォルダを作成
prop.SetOutputFolderPath(twlBackupName);
//========================================== //==========================================
// 改ざん&ファイル出力 // 改ざん&ファイル出力
Console.WriteLine("Start ------------"); Console.WriteLine("Start ------------");
@ -1111,14 +1113,14 @@ namespace FalsifyTwlBackup
} }
// byte 配列の 16 進表示 // byte 配列の 16 進表示
static void dumpArray(String msg, byte[] array) static string dumpArray(byte[] array)
{ {
Console.Write(msg); string str = "";
foreach (byte b in array) foreach (byte b in array)
{ {
Console.Write(String.Format("{0,0:X2} ", b)); str += String.Format("{0,0:X2} ", b);
} }
Console.WriteLine(); return str.TrimEnd();
} }
} }

View File

@ -43,7 +43,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Program.cs" /> <Compile Include="FalsifyTwlBackup.cs" />
<Compile Include="Properties.cs" /> <Compile Include="Properties.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@ -123,6 +123,18 @@ namespace TwlBackupBlock
br.Read(buffer, 0, buffer.Length); br.Read(buffer, 0, buffer.Length);
} }
/// <summary>
/// 現在のストリームから指定した配列に2バイト符号なし整数を読み取り、ストリームの現在位置を指定した配列のバイト数だけ進めます。
/// </summary>
/// <param name="buffer">データを読み取るバッファ</param>
public void Read(UInt16[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
Read(ref buffer[i]);
}
}
/// <summary> /// <summary>
/// 現在のストリームから指定した配列に4バイト符号なし整数を読み取り、ストリームの現在位置を指定した配列のバイト数だけ進めます。 /// 現在のストリームから指定した配列に4バイト符号なし整数を読み取り、ストリームの現在位置を指定した配列のバイト数だけ進めます。
/// </summary> /// </summary>

View File

@ -9,13 +9,14 @@ namespace TwlBackupBlock
/// </summary> /// </summary>
public class HeaderBody : AbstractBody public class HeaderBody : AbstractBody
{ {
public const int HEADER_SIZE = 160; public const int HEADER_SIZE = 240;
public const int UNIQUE_ID_SIZE = 32; public const int UNIQUE_ID_SIZE = 32;
public const int HARDWARE_ID_SIZE = 16; public const int HARDWARE_ID_SIZE = 16;
public const int NUM_OF_SECTION = 4; public const int MAX_CONTENTS = 8;
public const int NUM_OF_SECTION = 11;
public const int TMD_RESERVED_SIZE = 62; public const int TMD_RESERVED_SIZE = 62;
public const int RESERVED_SIZE = 4; public const int RESERVED_SIZE = 13;
public UInt32 signature; public UInt32 signature;
public UInt16 companyCode; public UInt16 companyCode;
@ -25,9 +26,10 @@ namespace TwlBackupBlock
public UInt64 titleId; public UInt64 titleId;
public Int64 requiredSize; public Int64 requiredSize;
public readonly UInt32[] fileSizes; public readonly UInt32[] fileSizes;
public UInt32 contentId; public readonly UInt32[] contentId;
public readonly UInt16[] contentIndex;
public readonly TmdReserved tmdReserved; public readonly TmdReserved tmdReserved;
public UInt16 contentIndex; public Byte headerVersion;
public readonly Byte[] reserved; public readonly Byte[] reserved;
public HeaderBody(byte[] data) public HeaderBody(byte[] data)
@ -45,6 +47,8 @@ namespace TwlBackupBlock
uniqueId = new Byte[UNIQUE_ID_SIZE]; uniqueId = new Byte[UNIQUE_ID_SIZE];
hardwareId = new Byte[HARDWARE_ID_SIZE]; hardwareId = new Byte[HARDWARE_ID_SIZE];
fileSizes = new UInt32[NUM_OF_SECTION]; fileSizes = new UInt32[NUM_OF_SECTION];
contentId = new UInt32[MAX_CONTENTS];
contentIndex = new UInt16[MAX_CONTENTS];
tmdReserved = new TmdReserved(); tmdReserved = new TmdReserved();
reserved = new Byte[RESERVED_SIZE]; reserved = new Byte[RESERVED_SIZE];
@ -130,9 +134,16 @@ namespace TwlBackupBlock
{ {
bw.Write(e); bw.Write(e);
} }
bw.Write(contentId); foreach (UInt32 e in contentId)
{
bw.Write(e);
}
foreach (UInt16 e in contentIndex)
{
bw.Write(e);
}
bw.Write(tmdReserved.GetBytes()); bw.Write(tmdReserved.GetBytes());
bw.Write(contentIndex); bw.Write(headerVersion);
bw.Write(reserved); bw.Write(reserved);
Debug.Assert(ms.Position == HEADER_SIZE); Debug.Assert(ms.Position == HEADER_SIZE);
@ -164,13 +175,14 @@ namespace TwlBackupBlock
br.Read(ref titleId); br.Read(ref titleId);
br.Read(ref requiredSize); br.Read(ref requiredSize);
br.Read(fileSizes); br.Read(fileSizes);
br.Read(ref contentId); br.Read(contentId);
br.Read(contentIndex);
{ {
byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE]; byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE];
br.Read(tmdReservedBytes); br.Read(tmdReservedBytes);
tmdReserved.SetBytes(tmdReservedBytes); tmdReserved.SetBytes(tmdReservedBytes);
} }
br.Read(ref contentIndex); br.Read(ref headerVersion);
br.Read(reserved); br.Read(reserved);
Debug.Assert(ms.Position == HEADER_SIZE); Debug.Assert(ms.Position == HEADER_SIZE);
@ -182,79 +194,4 @@ namespace TwlBackupBlock
return new HeaderBody(GetBytes()); return new HeaderBody(GetBytes());
} }
} }
/// <summary>
/// ヘッダブロック中のTMDReserved。
/// </summary>
public class TmdReserved
{
private const int TMD_RESERVED_SIZE = 62;
public const int RESERVED8_SIZE = 3;
public const int PARENTAL_CONTROL_SIZE = 16;
public const int RESERVED_SIZE = 30;
public UInt32 publicSaveSize;
public UInt32 privateSaveSize;
public UInt32 reserved32;
public Byte flags;
public readonly Byte[] reserved8;
public readonly Byte[] parentalControl;
public readonly Byte[] reserved;
public TmdReserved()
{
reserved8 = new Byte[RESERVED8_SIZE];
parentalControl = new Byte[PARENTAL_CONTROL_SIZE];
reserved = new Byte[RESERVED_SIZE];
}
public byte[] GetBytes()
{
byte[] bytes = new byte[TMD_RESERVED_SIZE];
using (var ms = new MemoryStream(bytes))
using (var bw = new BinaryWriter(ms))
{
bw.Write(publicSaveSize);
bw.Write(privateSaveSize);
bw.Write(reserved32);
bw.Write(flags);
bw.Write(reserved8);
bw.Write(parentalControl);
bw.Write(reserved);
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
}
return bytes;
}
public void SetBytes(byte[] bytes)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (bytes.Length != TMD_RESERVED_SIZE)
{
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", TMD_RESERVED_SIZE, bytes.Length);
throw new ArgumentException("bytes", message);
}
using (var ms = new MemoryStream(bytes))
using (var br = new ExtBinaryReader(ms))
{
br.Read(ref publicSaveSize);
br.Read(ref privateSaveSize);
br.Read(ref reserved32);
br.Read(ref flags);
br.Read(reserved8);
br.Read(parentalControl);
br.Read(reserved);
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
}
}
}
} }

View File

@ -0,0 +1,185 @@
using System;
using System.IO;
using System.Diagnostics;
namespace TwlBackupBlock
{
/// <summary>
/// ヘッダブロックのデータ本体。
/// </summary>
public class LegacyHeaderBody : AbstractBody
{
public const int HEADER_SIZE = 160;
public const int UNIQUE_ID_SIZE = 32;
public const int HARDWARE_ID_SIZE = 16;
public const int NUM_OF_SECTION = 4;
public const int TMD_RESERVED_SIZE = 62;
public const int RESERVED_SIZE = 4;
public UInt32 signature;
public UInt16 companyCode;
public UInt16 version;
public readonly Byte[] uniqueId;
public readonly Byte[] hardwareId;
public UInt64 titleId;
public Int64 requiredSize;
public readonly UInt32[] fileSizes;
public UInt32 contentId;
public readonly TmdReserved tmdReserved;
public UInt16 contentIndex;
public readonly Byte[] reserved;
public LegacyHeaderBody(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
if (data.Length != HEADER_SIZE)
{
string message = string.Format("data.Length % {0} != 0 (data.Length:{1})", HEADER_SIZE, data.Length);
throw new ArgumentException("data", message);
}
uniqueId = new Byte[UNIQUE_ID_SIZE];
hardwareId = new Byte[HARDWARE_ID_SIZE];
fileSizes = new UInt32[NUM_OF_SECTION];
tmdReserved = new TmdReserved();
reserved = new Byte[RESERVED_SIZE];
SetBytes(data);
}
public override byte this[int index]
{
get
{
if (index < 0 || index >= HEADER_SIZE)
{
throw new ArgumentException("index");
}
return ReadByte(index);
}
set
{
if (index < 0 || index >= HEADER_SIZE)
{
throw new ArgumentException("index");
}
WriteByte(index, value);
}
}
public override int Length
{
get
{
return HEADER_SIZE;
}
}
/// <summary>
/// 指定したバイトを取得します。
/// </summary>
/// <param name="index">取得したいバイトのインデックス。</param>
/// <returns><paramref name="index"/>で指定したバイト</returns>
public byte ReadByte(int index)
{
if (index < 0 || index >= HEADER_SIZE)
{
throw new ArgumentException("index");
}
// TODO 処理が遅ければ効率化
byte[] bytes = GetBytes();
return bytes[index];
}
/// <summary>
/// 指定したバイトを書き換えます。
/// </summary>
/// <param name="index">書き換えたいバイトのインデックス。</param>
/// <param name="b">上書きに使うバイト。</param>
public void WriteByte(int index, byte b)
{
if (index < 0 || index >= HEADER_SIZE)
{
throw new ArgumentException("index");
}
// TODO 処理が遅ければ効率化
byte[] bytes = GetBytes();
bytes[index] = b;
SetBytes(bytes);
}
public override byte[] GetBytes()
{
byte[] bytes = new byte[HEADER_SIZE];
using (var ms = new MemoryStream(bytes))
using (var bw = new BinaryWriter(ms))
{
bw.Write(signature);
bw.Write(companyCode);
bw.Write(version);
bw.Write(uniqueId);
bw.Write(hardwareId);
bw.Write(titleId);
bw.Write(requiredSize);
foreach (UInt32 e in fileSizes)
{
bw.Write(e);
}
bw.Write(contentId);
bw.Write(tmdReserved.GetBytes());
bw.Write(contentIndex);
bw.Write(reserved);
Debug.Assert(ms.Position == HEADER_SIZE);
}
return bytes;
}
public override void SetBytes(byte[] bytes)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (bytes.Length != HEADER_SIZE)
{
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", HEADER_SIZE, bytes.Length);
throw new ArgumentException("bytes", message);
}
using (var ms = new MemoryStream(bytes))
using (var br = new ExtBinaryReader(ms))
{
br.Read(ref signature);
br.Read(ref companyCode);
br.Read(ref version);
br.Read(uniqueId);
br.Read(hardwareId);
br.Read(ref titleId);
br.Read(ref requiredSize);
br.Read(fileSizes);
br.Read(ref contentId);
{
byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE];
br.Read(tmdReservedBytes);
tmdReserved.SetBytes(tmdReservedBytes);
}
br.Read(ref contentIndex);
br.Read(reserved);
Debug.Assert(ms.Position == HEADER_SIZE);
}
}
public override object Clone()
{
return new HeaderBody(GetBytes());
}
}
}

View File

@ -10,7 +10,8 @@ namespace TwlBackupBlock
public class TwlBackupHashSet public class TwlBackupHashSet
{ {
public const int HASH_SIZE = 32; public const int HASH_SIZE = 32;
public const int NUM_OF_SECTION = 4; public const int NUM_OF_SECTION = 11;
public const int NUM_OF_LEGACY_SECTION = 4;
public readonly byte[] banner; public readonly byte[] banner;
public readonly byte[] header; public readonly byte[] header;
@ -19,11 +20,12 @@ namespace TwlBackupBlock
/// <summary> /// <summary>
/// コンストラクタ。 /// コンストラクタ。
/// </summary> /// </summary>
public TwlBackupHashSet() public TwlBackupHashSet(bool isLegacy = false)
{ {
banner = new byte[HASH_SIZE]; banner = new byte[HASH_SIZE];
header = new byte[HASH_SIZE]; header = new byte[HASH_SIZE];
section = new byte[NUM_OF_SECTION][]; section = isLegacy ?
new byte[NUM_OF_LEGACY_SECTION][] : new byte[NUM_OF_SECTION][];
for (int i = 0; i < section.Length; i++) for (int i = 0; i < section.Length; i++)
{ {
section[i] = new byte[HASH_SIZE]; section[i] = new byte[HASH_SIZE];
@ -35,7 +37,8 @@ namespace TwlBackupBlock
/// </summary> /// </summary>
public class SignatureBody : AbstractBody public class SignatureBody : AbstractBody
{ {
public const int SIGNATURE_SIZE = 1024; public const int SIGNATURE_SIZE = 1248;
public const int LEGACY_SIGNATURE_SIZE = 1024;
public const int ECC_SIGN_SIZE = 60; public const int ECC_SIGN_SIZE = 60;
public const int ECC_CERT_SIZE = 384; public const int ECC_CERT_SIZE = 384;

View File

@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Diagnostics;
namespace TwlBackupBlock
{
/// <summary>
/// ヘッダブロック中のTMDReserved。
/// Normal, Legacy 共に共通。
/// </summary>
public class TmdReserved
{
private const int TMD_RESERVED_SIZE = 62;
public const int RESERVED8_SIZE = 3;
public const int PARENTAL_CONTROL_SIZE = 16;
public const int RESERVED_SIZE = 30;
public UInt32 publicSaveSize;
public UInt32 privateSaveSize;
public UInt32 reserved32;
public Byte flags;
public readonly Byte[] reserved8;
public readonly Byte[] parentalControl;
public readonly Byte[] reserved;
public TmdReserved()
{
reserved8 = new Byte[RESERVED8_SIZE];
parentalControl = new Byte[PARENTAL_CONTROL_SIZE];
reserved = new Byte[RESERVED_SIZE];
}
public byte[] GetBytes()
{
byte[] bytes = new byte[TMD_RESERVED_SIZE];
using (var ms = new MemoryStream(bytes))
using (var bw = new BinaryWriter(ms))
{
bw.Write(publicSaveSize);
bw.Write(privateSaveSize);
bw.Write(reserved32);
bw.Write(flags);
bw.Write(reserved8);
bw.Write(parentalControl);
bw.Write(reserved);
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
}
return bytes;
}
public void SetBytes(byte[] bytes)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (bytes.Length != TMD_RESERVED_SIZE)
{
string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", TMD_RESERVED_SIZE, bytes.Length);
throw new ArgumentException("bytes", message);
}
using (var ms = new MemoryStream(bytes))
using (var br = new ExtBinaryReader(ms))
{
br.Read(ref publicSaveSize);
br.Read(ref privateSaveSize);
br.Read(ref reserved32);
br.Read(ref flags);
br.Read(reserved8);
br.Read(parentalControl);
br.Read(reserved);
Debug.Assert(ms.Position == TMD_RESERVED_SIZE);
}
}
}
}

View File

@ -58,6 +58,7 @@
<Compile Include="AesCmac.cs" /> <Compile Include="AesCmac.cs" />
<Compile Include="Body.cs" /> <Compile Include="Body.cs" />
<Compile Include="ExtBinaryReader.cs" /> <Compile Include="ExtBinaryReader.cs" />
<Compile Include="LegacyHeaderBody.cs" />
<Compile Include="Properties\Resources.Designer.cs"> <Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@ -68,6 +69,7 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon> <DependentUpon>Settings.settings</DependentUpon>
</Compile> </Compile>
<Compile Include="TmdReserved.cs" />
<Compile Include="Utility.cs" /> <Compile Include="Utility.cs" />
<Compile Include="AbstractBody.cs" /> <Compile Include="AbstractBody.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -13,6 +13,16 @@ namespace TwlBackupBlock
/// </summary> /// </summary>
public class Utility public class Utility
{ {
public const int MAX_CONTENTS = 8;
public enum SectionIndex
{
TMD,
CONTENT,
PUBLIC_SAVE = CONTENT + MAX_CONTENTS,
SUB_BANNER,
PRIVATE_SAVE
};
private const int KEY_SIZE = 16; private const int KEY_SIZE = 16;
private const int ROUND_SCALE = 16; private const int ROUND_SCALE = 16;
@ -21,8 +31,10 @@ namespace TwlBackupBlock
private const int AES_SIGN_HEADER_SIZE = 32; private const int AES_SIGN_HEADER_SIZE = 32;
private const int BANNER_SIZE = 16 * 1024; private const int BANNER_SIZE = 16 * 1024;
private const int HEADER_SIZE = 160; private const int HEADER_SIZE = 240;
private const int SIGNATURE_SIZE = 1024; private const int SIGNATURE_SIZE = 1248;
private const int LEGACY_HEADER_SIZE = 160;
private const int LEGACY_SIGNATURE_SIZE = 1024;
private const int ENCRYPT_BANNER_SIZE = BANNER_SIZE + AES_SIGN_HEADER_SIZE; private const int ENCRYPT_BANNER_SIZE = BANNER_SIZE + AES_SIGN_HEADER_SIZE;
private const int ENCRYPT_HEADER_SIZE = HEADER_SIZE + AES_SIGN_HEADER_SIZE; private const int ENCRYPT_HEADER_SIZE = HEADER_SIZE + AES_SIGN_HEADER_SIZE;
@ -74,14 +86,16 @@ namespace TwlBackupBlock
blocks.signature.body = new SignatureBody(DecryptBlock(br, SIGNATURE_SIZE, key, out blocks.signature.mac, out blocks.signature.iv)); blocks.signature.body = new SignatureBody(DecryptBlock(br, SIGNATURE_SIZE, key, out blocks.signature.mac, out blocks.signature.iv));
int TMD_SIZE = (int)headerBody.fileSizes[0]; // TORIAEZU
int CONTENT_SIZE = (int)headerBody.fileSizes[1]; // TODO : 複数コンテンツ対応
int SAVE_DATA_SIZE = (int)headerBody.fileSizes[2]; int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[3]; int CONTENT_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT];
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.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)); blocks.content.body = new Body(DecryptBlock(br, CONTENT_SIZE, key, out blocks.content.mac, out blocks.content.iv));
blocks.saveData.body = new Body(DecryptBlock(br, SAVE_DATA_SIZE, key, out blocks.saveData.mac, out blocks.saveData.iv)); 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)); blocks.subBanner.body = new Body(DecryptBlock(br, SUB_BANNER_SIZE, key, out blocks.subBanner.mac, out blocks.subBanner.iv));
Debug.Assert(ms.Position == data.Length); Debug.Assert(ms.Position == data.Length);
@ -386,13 +400,14 @@ namespace TwlBackupBlock
return false; return false;
} }
int TMD_SIZE = (int)headerBody.fileSizes[0]; // TODO : 複数コンテンツ対応
int CONTENT_SIZE = (int)headerBody.fileSizes[1]; int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
int SAVE_DATA_SIZE = (int)headerBody.fileSizes[2]; int CONTENT_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.CONTENT];
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[3]; 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(CONTENT_SIZE, ROUND_SCALE) +
RoundUp(SAVE_DATA_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) + RoundUp(PUBLIC_SAVE_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) +
AES_SIGN_HEADER_SIZE * 4; AES_SIGN_HEADER_SIZE * 4;
if (data.Length - ms.Position != restSize) if (data.Length - ms.Position != restSize)
{ {
@ -405,7 +420,7 @@ namespace TwlBackupBlock
Console.WriteLine("TMDブロックのMACが一致しません"); Console.WriteLine("TMDブロックのMACが一致しません");
return false; return false;
} }
if (!CheckHash(blocks.tmd, signatureBody.digest.section[0])) if (!CheckHash(blocks.tmd, signatureBody.digest.section[(int)SectionIndex.TMD]))
{ {
Console.WriteLine("TMDブロックのハッシュが一致しません"); Console.WriteLine("TMDブロックのハッシュが一致しません");
return false; return false;
@ -416,18 +431,18 @@ namespace TwlBackupBlock
Console.WriteLine("コンテンツブロックのMACが一致しません"); Console.WriteLine("コンテンツブロックのMACが一致しません");
return false; return false;
} }
if (!CheckHash(blocks.content, signatureBody.digest.section[1])) if (!CheckHash(blocks.content, signatureBody.digest.section[(int)SectionIndex.CONTENT]))
{ {
Console.WriteLine("コンテンツブロックのハッシュが一致しません"); Console.WriteLine("コンテンツブロックのハッシュが一致しません");
return false; return false;
} }
blocks.saveData.body = new Body(DecryptBlock(br, SAVE_DATA_SIZE, aesCbcKey, out blocks.saveData.mac, out blocks.saveData.iv)); 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)) if (!CheckMac(blocks.saveData, aesCmacKey, blocks.saveData.mac))
{ {
Console.WriteLine("publicセーブデータブロックのMACが一致しません"); Console.WriteLine("publicセーブデータブロックのMACが一致しません");
return false; return false;
} }
if (!CheckHash(blocks.saveData, signatureBody.digest.section[2])) if (!CheckHash(blocks.saveData, signatureBody.digest.section[(int)SectionIndex.PUBLIC_SAVE]))
{ {
Console.WriteLine("publicセーブデータブロックのハッシュが一致しません"); Console.WriteLine("publicセーブデータブロックのハッシュが一致しません");
return false; return false;
@ -438,7 +453,7 @@ namespace TwlBackupBlock
Console.WriteLine("サブバナーブロックの内容とMACが一致しません"); Console.WriteLine("サブバナーブロックの内容とMACが一致しません");
return false; return false;
} }
if (!CheckHash(blocks.subBanner, signatureBody.digest.section[3])) if (!CheckHash(blocks.subBanner, signatureBody.digest.section[(int)SectionIndex.SUB_BANNER]))
{ {
Console.WriteLine("サブバナーブロックのハッシュが一致しません"); Console.WriteLine("サブバナーブロックのハッシュが一致しません");
return false; return false;