ctr_test_tools/TwlBkpCheck/Windows/FalsifyTwlBackup/Falsify.cs
n2460 78f20ab988 FalsifyTwlBackup:改ざん項目の追加。
Category 関数で書きだしたかどうかを返すようにした。

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@41 6b0af911-cb57-b745-895f-eec5701120e1
2011-11-01 02:27:59 +00:00

447 lines
19 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 指定されたbyteサイズで、0のみのbyte列を作成します。
/// </summary>
/// <param name="dataSize">作成するデータのサイズ[単位:byte]</param>
/// <returns>作成したデータのbyte列</returns>
// 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;
}
/// <summary>
/// データの差し替えを行います。
/// </summary>
/// <param name="dataBlocks">上書き対象となるデータ本体</param>
/// <param name="impData">上書きする不正データ</param>
static void ReplaceImproperData(AbstractBody dataBlocks, byte[] impData)
{
for (int i = 0; i < impData.Length; i++)
{
if (i < dataBlocks.Length) // 上書き先のデータサイズを超えませんように
{
dataBlocks[i] = impData[i];
}
}
return;
}
/// <summary>
/// ※未使用
/// 暗号化に使用するIVを作成します。
/// AES方式で、ブロックサイズはAES_BLOCK_SIZE[bit]と同じです。
/// </summary>
/// <returns>生成したivのbyte列</returns>
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;
}
/// <summary>
/// 署名のハッシュセットを変更します。
/// </summary>
/// <param name="dataBlocks">変更対象となる署名ブロックを有するBlocks</param>
/// <param name="hash">新しいハッシュ値</param>
/// <param name="section">変更するブロックセクション</param>
static void ChangeHashSet(Blocks dataBlocks, byte[] hash, int section, BkpType type)
{
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:
if (type != BkpType.LEGACY)
{
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.PUBLIC_SAVE], 0);
}
else
{
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndexLegacy.PUBLIC_SAVE], 0);
}
break;
case SECTION_SUB_BANNER:
if (type != BkpType.LEGACY)
{
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndex.SUB_BANNER], 0);
}
else
{
hash.CopyTo(signature.digest.section[(int)Utility.SectionIndexLegacy.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;
}
}
}
/// <summary>
/// byte列を結合します。
/// </summary>
/// <param name="front">前半部分に来るbyte列</param>
/// <param name="rear">後半部分に来るbyte列</param>
/// <returns>連結後のbyte列</returns>
static byte[] MergeByteArray(byte[] front, byte[] rear)
{
return front.Concat(rear).ToArray();
}
/// <summary>
/// byte列をbinファイルに出力します。
/// </summary>
/// <param name="improperNo">ファイル名となる改ざんパターンの番号</param>
/// <param name="outFolderPath">出力ディレクトリのパス</param>
/// <param name="data">ファイルに出力するデータ</param>
static void OutputFalsifiedData(int improperNo, string outFolderPath, byte[] data)
{
string outFalsifiedDataPath = Convert.ToString(improperNo) + EXTENSION; // ファイル名を改ざん番号から生成
outFalsifiedDataPath = Path.Combine(outFolderPath, outFalsifiedDataPath); // 出力ディレクトリとファイル名を結合
File.WriteAllBytes(outFalsifiedDataPath, data); // 出力
}
/// <summary>
/// データ本体とMACとIVをひとつのブロックに結合します。
/// 必要に応じて不正データを挿入します。
/// </summary>
/// <param name="dataBlocks">暗号化するBlockを持つBlocks</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 section, Properties prop, byte[] impData, int insertPos, byte[] byteMac, byte[] byteHash = null)
{
byte[] encryptedBlock = new byte[0];
// (データ本体の前に不正データ挿入)
if (insertPos >= FRONT_BANNER && insertPos <= FRONT_PRIVATE_SAVE)
{
if (section == insertPos - FRONT_BANNER)
{
encryptedBlock = MergeByteArray(encryptedBlock, impData);
}
}
// データ本体を暗号化
encryptedBlock = MergeByteArray(encryptedBlock, dataBlocks[section].body.GetBytes()); // bodyを暗号化
// (データ本体の後に不正データ挿入)
if (insertPos >= REAR_BANNER && insertPos <= REAR_PRIVATE_SAVE)
{
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 (prop.bkpType != BkpType.WITH_PRIVATE_SAVE)
{
if (section == SECTION_SUB_BANNER && insertPos == REAR_DATA)
{
encryptedBlock = MergeByteArray(encryptedBlock, impData);
}
}
else
{
if (section == SECTION_PRIVATE_SAVE && insertPos == REAR_DATA)
{
encryptedBlock = MergeByteArray(encryptedBlock, impData);
}
}
return encryptedBlock;
}
/// <summary>
/// 各ブロックを暗号化した後、1つの byte 列に結合します。
/// </summary>
/// <param name="dataBlocks">暗号化するデータ</param>
/// <param name="prop">バックアップデータに関するインスタンス</param>
/// <param name="impData">不正データ</param>
/// <param name="insertPos">不正データを挿入する位置</param>
/// <param name="chgMacHash">ハッシュセット更新の有無</param>
/// <returns>全てのBlockを暗号化し、連結したbyte列</returns>
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, prop.bkpType); // ハッシュセットを更新
}
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 : 改ざんに使用する不正データ
//------------------------------------------------------------
/// <summary>
/// パターン番号に応じた改ざんを実行
/// </summary>
/// <param name="improperNo"></param>
/// <param name="prop"></param>
/// <param name="improperData"></param>
/// <returns>改ざんファイルを生成したかどうか</returns>
static bool FalsifyingData(int improperNo, Properties prop, byte[] improperData)
{
if (MIN_OF_CAT100 <= improperNo && improperNo <= MAX_OF_CAT100)
{
return FalsifyingDataCategory1xx(improperNo, prop, improperData);
}
else if (MIN_OF_CAT200 <= improperNo && improperNo <= MAX_OF_CAT200)
{
return FalsifyingDataCategory2xx(improperNo, prop, improperData);
}
else if (MIN_OF_CAT300 <= improperNo && improperNo <= MAX_OF_CAT300)
{
return FalsifyingDataCategory3xx(improperNo, prop, improperData);
}
else if (MIN_OF_CAT400 <= improperNo && improperNo <= MAX_OF_CAT400)
{
return FalsifyingDataCategory4xx(improperNo, prop, improperData);
}
else if (MIN_OF_CAT500 <= improperNo && improperNo <= MAX_OF_CAT500)
{
return FalsifyingDataCategory5xx(improperNo, prop, improperData);
}
else
{
return FalsifyingDataCategory9xx(improperNo, prop, improperData);
}
}
// static void SwitchFalsifyingPattern(int falsifyingType, Properties prop)
//------------------------------------------------------------
// 作成する改ざんデータのパターンを決定。
// [in] int falsifyingMode : 出力する改ざんデータパターン
// [in] Properties prop : バックアップデータに関するインスタンス
//------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="falsifyingMode"></param>
/// <param name="prop"></param>
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++)
{
if (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++)
{
if (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++)
{
if (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++)
{
if (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++)
{
if (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++)
{
if (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);
if (FalsifyingData(falsifyingMode, prop, improperData))
{
Console.WriteLine(" Complete falsifying No.{0}.\n", falsifyingMode);
}
else
{
Console.WriteLine(" No.{0} isn't support by specified type.\n", falsifyingMode);
}
break;
}
}
}
}