mirror of
https://github.com/rvtr/ctr_test_tools.git
synced 2025-10-31 13:41:24 -04:00
TWLBackupBlock:WPS形式の時も復号化及び検証が行えるようにした。
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@35 6b0af911-cb57-b745-895f-eec5701120e1
This commit is contained in:
parent
76257fc66c
commit
dbd09789ba
@ -32,22 +32,56 @@ namespace TwlBackupBlock
|
|||||||
|
|
||||||
private const int BANNER_SIZE = 16 * 1024;
|
private const int BANNER_SIZE = 16 * 1024;
|
||||||
private const int HEADER_SIZE = 240;
|
private const int HEADER_SIZE = 240;
|
||||||
private const int SIGNATURE_SIZE = 1248;
|
private const int EX_HEADER_SIZE = 256;
|
||||||
private const int LEGACY_HEADER_SIZE = 160;
|
private const int LEGACY_HEADER_SIZE = 160;
|
||||||
|
private const int SIGNATURE_SIZE = 1248;
|
||||||
|
private const int EX_SIGNATURE_SIZE = 1280;
|
||||||
private const int LEGACY_SIGNATURE_SIZE = 1024;
|
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;
|
||||||
|
private const int ENCRYPT_EX_HEADER_SIZE = EX_HEADER_SIZE + AES_SIGN_HEADER_SIZE;
|
||||||
private const int ENCRYPT_SIGNATURE_SIZE = SIGNATURE_SIZE + AES_SIGN_HEADER_SIZE;
|
private const int ENCRYPT_SIGNATURE_SIZE = SIGNATURE_SIZE + AES_SIGN_HEADER_SIZE;
|
||||||
|
private const int ENCRYPT_EX_SIGNATURE_SIZE = EX_SIGNATURE_SIZE + AES_SIGN_HEADER_SIZE;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// バックアップデータをブロックに分割して復号化をおこないます。
|
/// バックアップデータをブロックに分割して復号化をおこないます。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">バックアップデータ。</param>
|
/// <param name="data">バックアップデータ。</param>
|
||||||
/// <param name="key">データ本体の復号鍵。</param>
|
/// <param name="key">データ本体の復号鍵。</param>
|
||||||
|
/// <param name="type">バックアップデータの形式。</param>
|
||||||
/// <returns>分割、復号化されたブロック。</returns>
|
/// <returns>分割、復号化されたブロック。</returns>
|
||||||
public static Blocks DecryptBackupData(byte[] data, byte[] key)
|
public static Blocks DecryptBackupData(byte[] data, byte[] key, BkpType type)
|
||||||
{
|
{
|
||||||
|
// TODO : Legacy 対応
|
||||||
|
if (type == BkpType.LEGACY)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Legacy には未対応です。");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int headerSize = 0;
|
||||||
|
int signatureSize = 0;
|
||||||
|
int encryptHeaderSize = 0;
|
||||||
|
int encryptSignatureSize = 0;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case BkpType.NORMAL:
|
||||||
|
headerSize = HEADER_SIZE;
|
||||||
|
signatureSize = SIGNATURE_SIZE;
|
||||||
|
encryptHeaderSize = ENCRYPT_HEADER_SIZE;
|
||||||
|
encryptSignatureSize = ENCRYPT_SIGNATURE_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BkpType.WITH_PRIVATE_SAVE:
|
||||||
|
headerSize = EX_HEADER_SIZE;
|
||||||
|
signatureSize = EX_SIGNATURE_SIZE;
|
||||||
|
encryptHeaderSize = ENCRYPT_EX_HEADER_SIZE;
|
||||||
|
encryptSignatureSize = ENCRYPT_EX_SIGNATURE_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("data");
|
throw new ArgumentNullException("data");
|
||||||
@ -57,7 +91,7 @@ namespace TwlBackupBlock
|
|||||||
throw new ArgumentNullException("key");
|
throw new ArgumentNullException("key");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int minDataSize = ENCRYPT_BANNER_SIZE + ENCRYPT_HEADER_SIZE + ENCRYPT_SIGNATURE_SIZE;
|
int minDataSize = ENCRYPT_BANNER_SIZE + encryptHeaderSize + encryptSignatureSize;
|
||||||
if (data.Length < minDataSize)
|
if (data.Length < minDataSize)
|
||||||
{
|
{
|
||||||
string message = string.Format("data.Length < {0} (data.Length:{1})", data, minDataSize);
|
string message = string.Format("data.Length < {0} (data.Length:{1})", data, minDataSize);
|
||||||
@ -76,7 +110,8 @@ namespace TwlBackupBlock
|
|||||||
using (var br = new BinaryReader(ms))
|
using (var br = new BinaryReader(ms))
|
||||||
{
|
{
|
||||||
blocks.banner.body = new Body(DecryptBlock(br, BANNER_SIZE, key, out blocks.banner.mac, out blocks.banner.iv));
|
blocks.banner.body = new Body(DecryptBlock(br, BANNER_SIZE, key, out blocks.banner.mac, out blocks.banner.iv));
|
||||||
HeaderBody headerBody = new HeaderBody(DecryptBlock(br, HEADER_SIZE, key, out blocks.header.mac, out blocks.header.iv));
|
HeaderBody headerBody = new HeaderBody(
|
||||||
|
DecryptBlock(br, headerSize, key, out blocks.header.mac, out blocks.header.iv), type);
|
||||||
blocks.header.body = headerBody;
|
blocks.header.body = headerBody;
|
||||||
|
|
||||||
if (!CheckSignature(headerBody))
|
if (!CheckSignature(headerBody))
|
||||||
@ -84,9 +119,10 @@ namespace TwlBackupBlock
|
|||||||
throw new Exception("ヘッダブロックのシグネチャが正しくありません");
|
throw new Exception("ヘッダブロックのシグネチャが正しくありません");
|
||||||
}
|
}
|
||||||
|
|
||||||
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, signatureSize, key, out blocks.signature.mac, out blocks.signature.iv), type);
|
||||||
|
|
||||||
// TODO : Legacy, WPS 対応
|
// TODO : Legacy 対応
|
||||||
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
|
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
|
||||||
int[] CONTENT_SIZE = new int[MAX_CONTENTS];
|
int[] CONTENT_SIZE = new int[MAX_CONTENTS];
|
||||||
for (int i = 0; i < MAX_CONTENTS; i++)
|
for (int i = 0; i < MAX_CONTENTS; i++)
|
||||||
@ -95,6 +131,11 @@ namespace TwlBackupBlock
|
|||||||
}
|
}
|
||||||
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
|
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
|
||||||
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
|
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
|
||||||
|
int PRIVATE_SAVE_SIZE = 0;
|
||||||
|
if (type == BkpType.WITH_PRIVATE_SAVE)
|
||||||
|
{
|
||||||
|
PRIVATE_SAVE_SIZE = (int)headerBody.privateSaveForWPS;
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
||||||
for (int i = 0; i < MAX_CONTENTS; i++)
|
for (int i = 0; i < MAX_CONTENTS; i++)
|
||||||
@ -108,8 +149,12 @@ namespace TwlBackupBlock
|
|||||||
blocks.content[i].body = null;
|
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.publicSave.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, key, out blocks.publicSave.mac, out blocks.publicSave.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));
|
||||||
|
if (type == BkpType.WITH_PRIVATE_SAVE)
|
||||||
|
{
|
||||||
|
blocks.privateSave.body = new Body(DecryptBlock(br, PRIVATE_SAVE_SIZE, key, out blocks.privateSave.mac, out blocks.privateSave.iv));
|
||||||
|
}
|
||||||
|
|
||||||
Debug.Assert(ms.Position == data.Length);
|
Debug.Assert(ms.Position == data.Length);
|
||||||
}
|
}
|
||||||
@ -344,9 +389,39 @@ namespace TwlBackupBlock
|
|||||||
/// <param name="data">検証にかけるバックアップデータ。</param>
|
/// <param name="data">検証にかけるバックアップデータ。</param>
|
||||||
/// <param name="aesCbcKey">データ本体の暗号鍵。</param>
|
/// <param name="aesCbcKey">データ本体の暗号鍵。</param>
|
||||||
/// <param name="aesCmacKey">MACの鍵。</param>
|
/// <param name="aesCmacKey">MACの鍵。</param>
|
||||||
|
/// <param name="type">バックアップの形式。</param>
|
||||||
/// <returns>検証に成功した場合はtrue。それ以外の場合はfalse。</returns>
|
/// <returns>検証に成功した場合はtrue。それ以外の場合はfalse。</returns>
|
||||||
public static bool Verify(byte[] data, byte[] aesCbcKey, byte[] aesCmacKey)
|
public static bool Verify(byte[] data, byte[] aesCbcKey, byte[] aesCmacKey, BkpType type)
|
||||||
{
|
{
|
||||||
|
// TODO : Legacy 対応
|
||||||
|
if (type == BkpType.LEGACY)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Legacy には未対応です。");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int headerSize = 0;
|
||||||
|
int signatureSize = 0;
|
||||||
|
int encryptHeaderSize = 0;
|
||||||
|
int encryptSignatureSize = 0;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case BkpType.NORMAL:
|
||||||
|
headerSize = HEADER_SIZE;
|
||||||
|
signatureSize = SIGNATURE_SIZE;
|
||||||
|
encryptHeaderSize = ENCRYPT_HEADER_SIZE;
|
||||||
|
encryptSignatureSize = ENCRYPT_SIGNATURE_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BkpType.WITH_PRIVATE_SAVE:
|
||||||
|
headerSize = EX_HEADER_SIZE;
|
||||||
|
signatureSize = EX_SIGNATURE_SIZE;
|
||||||
|
encryptHeaderSize = ENCRYPT_EX_HEADER_SIZE;
|
||||||
|
encryptSignatureSize = ENCRYPT_EX_SIGNATURE_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("data");
|
throw new ArgumentNullException("data");
|
||||||
@ -362,7 +437,7 @@ namespace TwlBackupBlock
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int minDataSize = ENCRYPT_BANNER_SIZE + ENCRYPT_HEADER_SIZE + ENCRYPT_SIGNATURE_SIZE;
|
int minDataSize = ENCRYPT_BANNER_SIZE + encryptHeaderSize + encryptSignatureSize;
|
||||||
if (data.Length < minDataSize)
|
if (data.Length < minDataSize)
|
||||||
{
|
{
|
||||||
Console.WriteLine("バックアップファイルサイズがバナー+ヘッダ+署名ブロック未満です");
|
Console.WriteLine("バックアップファイルサイズがバナー+ヘッダ+署名ブロック未満です");
|
||||||
@ -376,9 +451,11 @@ namespace TwlBackupBlock
|
|||||||
using (var br = new BinaryReader(ms))
|
using (var br = new BinaryReader(ms))
|
||||||
{
|
{
|
||||||
blocks.banner.body = new Body(DecryptBlock(br, BANNER_SIZE, aesCbcKey, out blocks.banner.mac, out blocks.banner.iv));
|
blocks.banner.body = new Body(DecryptBlock(br, BANNER_SIZE, aesCbcKey, out blocks.banner.mac, out blocks.banner.iv));
|
||||||
HeaderBody headerBody = new HeaderBody(DecryptBlock(br, HEADER_SIZE, aesCbcKey, out blocks.header.mac, out blocks.header.iv));
|
HeaderBody headerBody = new HeaderBody(
|
||||||
|
DecryptBlock(br, headerSize, aesCbcKey, out blocks.header.mac, out blocks.header.iv), type);
|
||||||
blocks.header.body = headerBody;
|
blocks.header.body = headerBody;
|
||||||
SignatureBody signatureBody = new SignatureBody(DecryptBlock(br, SIGNATURE_SIZE, aesCbcKey, out blocks.signature.mac, out blocks.signature.iv));
|
SignatureBody signatureBody = new SignatureBody(
|
||||||
|
DecryptBlock(br, signatureSize, aesCbcKey, out blocks.signature.mac, out blocks.signature.iv), type);
|
||||||
blocks.signature.body = signatureBody;
|
blocks.signature.body = signatureBody;
|
||||||
|
|
||||||
if (!CheckMac(blocks.header, aesCmacKey, blocks.header.mac))
|
if (!CheckMac(blocks.header, aesCmacKey, blocks.header.mac))
|
||||||
@ -413,7 +490,7 @@ namespace TwlBackupBlock
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : 複数コンテンツ対応
|
// TODO : Legacy 対応
|
||||||
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
|
int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD];
|
||||||
int[] CONTENT_SIZE = new int[MAX_CONTENTS];
|
int[] CONTENT_SIZE = new int[MAX_CONTENTS];
|
||||||
for (int i = 0; i < MAX_CONTENTS; i++)
|
for (int i = 0; i < MAX_CONTENTS; i++)
|
||||||
@ -422,6 +499,11 @@ namespace TwlBackupBlock
|
|||||||
}
|
}
|
||||||
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
|
int PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.PUBLIC_SAVE];
|
||||||
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
|
int SUB_BANNER_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.SUB_BANNER];
|
||||||
|
int PRIVATE_SAVE_SIZE = 0;
|
||||||
|
if (type == BkpType.WITH_PRIVATE_SAVE)
|
||||||
|
{
|
||||||
|
PRIVATE_SAVE_SIZE = (int)headerBody.privateSaveForWPS;
|
||||||
|
}
|
||||||
|
|
||||||
int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) +
|
int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) +
|
||||||
RoundUp(PUBLIC_SAVE_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) +
|
RoundUp(PUBLIC_SAVE_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) +
|
||||||
@ -433,6 +515,11 @@ namespace TwlBackupBlock
|
|||||||
restSize += RoundUp(CONTENT_SIZE[i], ROUND_SCALE) + AES_SIGN_HEADER_SIZE;
|
restSize += RoundUp(CONTENT_SIZE[i], ROUND_SCALE) + AES_SIGN_HEADER_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (type == BkpType.WITH_PRIVATE_SAVE)
|
||||||
|
{
|
||||||
|
restSize += RoundUp(PRIVATE_SAVE_SIZE, ROUND_SCALE) + AES_SIGN_HEADER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.Length - ms.Position != restSize)
|
if (data.Length - ms.Position != restSize)
|
||||||
{
|
{
|
||||||
Console.WriteLine("TMD、コンテンツ、publicセーブデータ、サブバナーブロックサイズが実際のサイズと一致しません");
|
Console.WriteLine("TMD、コンテンツ、publicセーブデータ、サブバナーブロックサイズが実際のサイズと一致しません");
|
||||||
@ -467,13 +554,13 @@ namespace TwlBackupBlock
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocks.saveData.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, aesCbcKey, out blocks.saveData.mac, out blocks.saveData.iv));
|
blocks.publicSave.body = new Body(DecryptBlock(br, PUBLIC_SAVE_SIZE, aesCbcKey, out blocks.publicSave.mac, out blocks.publicSave.iv));
|
||||||
if (!CheckMac(blocks.saveData, aesCmacKey, blocks.saveData.mac))
|
if (!CheckMac(blocks.publicSave, aesCmacKey, blocks.publicSave.mac))
|
||||||
{
|
{
|
||||||
Console.WriteLine("publicセーブデータブロックのMACが一致しません");
|
Console.WriteLine("publicセーブデータブロックのMACが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CheckHash(blocks.saveData, signatureBody.digest.section[(int)SectionIndex.PUBLIC_SAVE]))
|
if (!CheckHash(blocks.publicSave, signatureBody.digest.section[(int)SectionIndex.PUBLIC_SAVE]))
|
||||||
{
|
{
|
||||||
Console.WriteLine("publicセーブデータブロックのハッシュが一致しません");
|
Console.WriteLine("publicセーブデータブロックのハッシュが一致しません");
|
||||||
return false;
|
return false;
|
||||||
@ -489,6 +576,21 @@ namespace TwlBackupBlock
|
|||||||
Console.WriteLine("サブバナーブロックのハッシュが一致しません");
|
Console.WriteLine("サブバナーブロックのハッシュが一致しません");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// WITH_PRIVATE_SAVE の時は private save も対象
|
||||||
|
if (type == BkpType.WITH_PRIVATE_SAVE)
|
||||||
|
{
|
||||||
|
blocks.privateSave.body = new Body(DecryptBlock(br, PRIVATE_SAVE_SIZE, aesCbcKey, out blocks.privateSave.mac, out blocks.privateSave.iv));
|
||||||
|
if (!CheckMac(blocks.privateSave, aesCmacKey, blocks.privateSave.mac))
|
||||||
|
{
|
||||||
|
Console.WriteLine("privateセーブデータブロックの内容とMACが一致しません");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!CheckHash(blocks.privateSave, signatureBody.digest.section[(int)SectionIndex.PRIVATE_SAVE]))
|
||||||
|
{
|
||||||
|
Console.WriteLine("privateセーブデータブロックのハッシュが一致しません");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Debug.Assert(ms.Position == data.Length);
|
Debug.Assert(ms.Position == data.Length);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user