diff --git a/TwlBkpCheck/Windows/FalsifyTwlBackup/Falsify.cs b/TwlBkpCheck/Windows/FalsifyTwlBackup/Falsify.cs
new file mode 100644
index 0000000..1ce4a65
--- /dev/null
+++ b/TwlBkpCheck/Windows/FalsifyTwlBackup/Falsify.cs
@@ -0,0 +1,403 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using TwlBackupBlock;
+
+namespace FalsifyTwlBackup
+{
+partial class Program
+{
+ ///
+ /// 指定されたbyteサイズで、0のみのbyte列を作成します。
+ ///
+ /// 作成するデータのサイズ[単位:byte]
+ /// 作成したデータのbyte列
+ // TODO 不正データの作成方法を選べるようにしてもいいかも
+ static byte[] CreateImproperData(int dataSize)
+ {
+ byte[] data = new byte[dataSize];
+ for (int i = 0; i < data.Length; i++)
+ {
+ //data[i] = (byte)(i);
+ data[i] = 0;
+ }
+ return data;
+ }
+
+ ///
+ /// データの差し替えを行います。
+ ///
+ /// 上書き対象となるデータ本体
+ /// 上書きする不正データ
+ static void ReplaceImproperData(AbstractBody dataBlocks, byte[] impData)
+ {
+ for (int i = 0; i < impData.Length; i++)
+ {
+ if (i < dataBlocks.Length) // 上書き先のデータサイズを超えませんように
+ {
+ dataBlocks[i] = impData[i];
+ }
+ }
+ return;
+ }
+
+ ///
+ /// ※未使用
+ /// 暗号化に使用するIVを作成します。
+ /// AES方式で、ブロックサイズはAES_BLOCK_SIZE[bit]と同じです。
+ ///
+ /// 生成したivのbyte列
+ static byte[] GenerateNewIv()
+ {
+ // 暗号化用IV作成
+ /*
+ * [参考] C#(.NET Framework)のAESを使ってファイルを暗号化してみる
+ * http://hibara.sblo.jp/article/43505136.html
+ */
+ System.Security.Cryptography.AesCryptoServiceProvider
+ aes = new System.Security.Cryptography.AesCryptoServiceProvider();
+ aes.BlockSize = AES_BLOCK_SIZE; // AESはブロックサイズ、キー長ともに16byte
+ aes.GenerateIV(); // IVの設定(ブロックサイズと同サイズ = 16byte)
+ byte[] byteIV = aes.IV; // IVをバイト列に
+ return byteIV;
+ }
+
+ ///
+ /// 署名のハッシュセットを変更します。
+ ///
+ /// 変更対象となる署名ブロックを有するBlocks
+ /// 新しいハッシュ値
+ /// 変更するブロックセクション
+ static void ChangeHashSet(Blocks dataBlocks, byte[] hash, int section)
+ {
+ Debug.Assert((section <= BLOCK_NUM - 1) && (section >= 0));
+
+ SignatureBody signature;
+ signature = (SignatureBody)dataBlocks.signature.body;
+ if (SECTION_CONTENT <= section && section < SECTION_CONTENT + MAX_CONTENTS)
+ {
+ 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 SECTION_HEADER:
+ hash.CopyTo(signature.digest.header, 0);
+ break;
+
+ case SECTION_TMD:
+ hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.TMD], 0);
+ break;
+
+ case SECTION_PUBLIC_SAVE:
+ hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PUBLIC_SAVE], 0);
+ break;
+
+ case SECTION_SUB_BANNER:
+ hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.SUB_BANNER], 0);
+ break;
+
+ case SECTION_PRIVATE_SAVE:
+ hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PRIVATE_SAVE], 0);
+ break;
+
+ default:
+ Debug.Assert(false);
+ break;
+ }
+ }
+ }
+
+ ///
+ /// byte列を結合します。
+ ///
+ /// 前半部分に来るbyte列
+ /// 後半部分に来るbyte列
+ /// 連結後のbyte列
+ static byte[] MergeByteArray(byte[] front, byte[] rear)
+ {
+ return front.Concat(rear).ToArray();
+ }
+
+ ///
+ /// byte列をbinファイルに出力します。
+ ///
+ /// ファイル名となる改ざんパターンの番号
+ /// 出力ディレクトリのパス
+ /// ファイルに出力するデータ
+ static void OutputFalsifiedData(int improperNo, string outFolderPath, byte[] data)
+ {
+ string outFalsifiedDataPath = Convert.ToString(improperNo) + EXTENSION; // ファイル名を改ざん番号から生成
+ outFalsifiedDataPath = Path.Combine(outFolderPath, outFalsifiedDataPath); // 出力ディレクトリとファイル名を結合
+ File.WriteAllBytes(outFalsifiedDataPath, data); // 出力
+ }
+
+ ///
+ /// データ本体とMACとIVをひとつのブロックに結合します。
+ /// 必要に応じて不正データを挿入します。
+ ///
+ /// 暗号化するBlockを持つBlocks
+ /// 暗号化するBlockのセクション
+ /// バックアップデータに関するインスタンス
+ /// 挿入する不正データ
+ /// 挿入する位置
+ /// 格納するMAC
+ /// MACを算出するためのハッシュ値
+ /// データ本体、MAC、IVを順に結合したbyte列
+ 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 (section == insertPos - FRONT_BANNER)
+ {
+ encryptedBlock = MergeByteArray(encryptedBlock, impData);
+ }
+ }
+
+ // データ本体を暗号化
+ encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[section].body.GetBytes()); // bodyを暗号化
+
+ // (データ本体の後に不正データ挿入)
+ if (insertPos >= REAR_BANNER && insertPos <= REAR_SUB_BANNER)
+ {
+ if (section == insertPos - REAR_BANNER)
+ {
+ encryptedBlock = MergeByteArray(encryptedBlock, impData);
+ }
+ }
+
+ if (byteHash != null)
+ {
+ byte[] buff = Utility.GetSha256(encryptedBlock); // 平文からSHA256ハッシュ算出
+ buff.CopyTo(byteHash, 0);
+ byteMac = Utility.GetAesCmac(byteHash, prop.macKeyData); // SHA256ハッシュからMACを算出
+ }
+
+ encryptedBlock = Utility.EncryptBody(encryptedBlock, prop.keyData, dataBlocks[section].iv); // データ本体を暗号化
+ encryptedBlock = MergeByteArray(encryptedBlock, byteMac); // MACを結合
+ encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[section].iv); // IVを結合
+
+ // (データブロックの後に不正データ挿入)
+ if (section == SECTION_SUB_BANNER && insertPos == REAR_DATA)
+ {
+ encryptedBlock = MergeByteArray(encryptedBlock, impData);
+ }
+
+ return encryptedBlock;
+ }
+
+ ///
+ /// 各ブロックを暗号化した後、1つの byte 列に結合します。
+ ///
+ /// 暗号化するデータ
+ /// バックアップデータに関するインスタンス
+ /// 不正データ
+ /// 不正データを挿入する位置
+ /// ハッシュセット更新の有無
+ /// 全てのBlockを暗号化し、連結したbyte列
+ static byte[] MergeEncryptBody(Blocks dataBlocks, Properties prop, byte[] impData, int insertPos, int chgMacHash)
+ {
+ byte[] outData = new byte[0];
+ byte[][] encryptedBlocks = new byte[BLOCK_NUM][];
+
+ byte[][] byteHash = new byte[BLOCK_NUM][];
+ byte[][] byteMac = new byte[BLOCK_NUM][];
+
+ //----------------------
+ // 各ブロックを暗号化
+ // ( MAC & HASH SET更新する場合 )
+ if (chgMacHash == CHG_MAC_AND_HASHSET)
+ {
+ for (int i = 0; i < BLOCK_NUM; i++) // 署名部以外を暗号化&byte列に結合
+ {
+ byteHash[i] = new byte[HASH_SIZE];
+ if (i != SECTION_SIGNATURE)
+ {
+ 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[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更新しない場合 )
+ else
+ {
+ for (int i = 0; i < BLOCK_NUM; i++)
+ {
+ if (dataBlocks[i].body != null)
+ {
+ encryptedBlocks[i] = EncryptBlock(dataBlocks, i, prop, impData, insertPos, dataBlocks[i].mac); // ブロックを暗号化&結合
+ }
+ else
+ {
+ encryptedBlocks[i] = null;
+ }
+ }
+ }
+
+ //----------------------
+ // 暗号化した各ブロックを結合
+ for (int i = 0; i < BLOCK_NUM; i++)
+ {
+ if (encryptedBlocks[i] != null)
+ {
+ outData = MergeByteArray(outData, encryptedBlocks[i]);
+ }
+ }
+ return outData;
+ }
+
+ // static void FalsifyingData(int improperNo, Properties prop, byte[] improperData)
+ //------------------------------------------------------------
+ // パターン番号に応じた改ざんを実行
+ // [in] int improperNo : 改ざんパターン番号
+ // [in] Properties prop : バックアップデータに関するインスタンス
+ // [in] byte[] improperData : 改ざんに使用する不正データ
+ //------------------------------------------------------------
+ ///
+ /// パターン番号に応じた改ざんを実行
+ ///
+ ///
+ ///
+ ///
+ static void FalsifyingData(int improperNo, Properties prop, byte[] improperData)
+ {
+ if (MIN_OF_CAT100 <= improperNo && improperNo <= MAX_OF_CAT100)
+ {
+ FalsifyingDataCategory1xx(improperNo, prop, improperData);
+ }
+ else if (MIN_OF_CAT200 <= improperNo && improperNo <= MAX_OF_CAT200)
+ {
+ FalsifyingDataCategory2xx(improperNo, prop, improperData);
+ }
+ else if (MIN_OF_CAT300 <= improperNo && improperNo <= MAX_OF_CAT300)
+ {
+ FalsifyingDataCategory3xx(improperNo, prop, improperData);
+ }
+ else if (MIN_OF_CAT400 <= improperNo && improperNo <= MAX_OF_CAT400)
+ {
+ FalsifyingDataCategory4xx(improperNo, prop, improperData);
+ }
+ else if (MIN_OF_CAT500 <= improperNo && improperNo <= MAX_OF_CAT500)
+ {
+ FalsifyingDataCategory5xx(improperNo, prop, improperData);
+ }
+ else
+ {
+ FalsifyingDataCategory9xx(improperNo, prop, improperData);
+ }
+ }
+
+ // static void SwitchFalsifyingPattern(int falsifyingType, Properties prop)
+ //------------------------------------------------------------
+ // 作成する改ざんデータのパターンを決定。
+ // [in] int falsifyingMode : 出力する改ざんデータパターン
+ // [in] Properties prop : バックアップデータに関するインスタンス
+ //------------------------------------------------------------
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ static void SwitchFalsifyingPattern(int falsifyingMode, Properties prop)
+ {
+ // 改ざんに使用する不正なデータ作成
+ byte[] improperData = CreateImproperData(IMPROPER_DATA_SIZE);
+
+ switch (falsifyingMode)
+ {
+ case MODE_ALL: // 全パターン
+ Console.WriteLine(" Falsifying \"all pattern\".");
+ for (int i = 0; i < NUM_OF_PATTERN.GetLength(0); i++)
+ {
+ for (int j = NUM_OF_PATTERN[i, 0]; j <= NUM_OF_PATTERN[i, 1]; j++)
+ {
+ FalsifyingData(j, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.", j);
+ }
+ Console.WriteLine(" Complete falsifying Cat.{0}.\n", NUM_OF_PATTERN[i, 0]);
+ }
+ break;
+
+ case MODE_CAT100: // 1xx系列全て
+ Console.WriteLine(" Falsifying category No.{0}.", NUM_OF_PATTERN[MODE_CAT100 - 1, 0]);
+ for (int i = 100; i <= MAX_OF_CAT100; i++)
+ {
+ FalsifyingData(i, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.", i);
+ }
+ Console.WriteLine(" Complete falsifying Cat.{0}.\n", NUM_OF_PATTERN[MODE_CAT100 - 1, 0]);
+ break;
+
+ case MODE_CAT200: // 2xx系列全て
+ Console.WriteLine(" Falsifying category No.{0}.", NUM_OF_PATTERN[MODE_CAT200 - 1, 0]);
+ for (int i = 200; i <= MAX_OF_CAT200; i++)
+ {
+ FalsifyingData(i, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.", i);
+ }
+ Console.WriteLine(" Complete falsifying Cat.{0}.\n", NUM_OF_PATTERN[MODE_CAT200 - 1, 0]);
+ break;
+
+ case MODE_CAT300: // 3xx系列全て
+ Console.WriteLine(" Falsifying category No.{0}.", NUM_OF_PATTERN[MODE_CAT300 - 1, 0]);
+ for (int i = 300; i <= MAX_OF_CAT300; i++)
+ {
+ FalsifyingData(i, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.", i);
+ }
+ Console.WriteLine(" Complete falsifying Cat.{0}.\n", NUM_OF_PATTERN[MODE_CAT300 - 1, 0]);
+ break;
+
+ case MODE_CAT400: // 4xx系列全て
+ Console.WriteLine(" Falsifying category No.{0}.", NUM_OF_PATTERN[MODE_CAT400 - 1, 0]);
+ for (int i = 400; i <= MAX_OF_CAT400; i++)
+ {
+ FalsifyingData(i, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.", i);
+ }
+ Console.WriteLine(" Complete falsifying Cat.{0}.\n", NUM_OF_PATTERN[MODE_CAT400 - 1, 0]);
+ break;
+
+ case MODE_CAT500: // 5xx系列全て
+ Console.WriteLine(" Falsifying category No.{0}.", NUM_OF_PATTERN[MODE_CAT500 - 1, 0]);
+ for (int i = 500; i <= MAX_OF_CAT500; i++)
+ {
+ FalsifyingData(i, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.", i);
+ }
+ Console.WriteLine(" Complete falsifying Cat.{0}.\n", NUM_OF_PATTERN[MODE_CAT500 - 1, 0]);
+ break;
+
+ default: // 1パターンのみを個別指定
+ Console.WriteLine(" Falsifying pattern No.{0}.", falsifyingMode);
+ FalsifyingData(falsifyingMode, prop, improperData);
+ Console.WriteLine(" Complete falsifying No.{0}.\n", falsifyingMode);
+ break;
+ }
+ }
+}
+}
diff --git a/TwlBkpCheck/Windows/FalsifyTwlBackup/FalsifyTwlBackup.csproj b/TwlBkpCheck/Windows/FalsifyTwlBackup/FalsifyTwlBackup.csproj
index c4dd1f8..23cf94b 100644
--- a/TwlBkpCheck/Windows/FalsifyTwlBackup/FalsifyTwlBackup.csproj
+++ b/TwlBkpCheck/Windows/FalsifyTwlBackup/FalsifyTwlBackup.csproj
@@ -49,6 +49,7 @@
+