diff --git a/TwlBkpCheck/Windows/TWLBackupBlock/HeaderBody.cs b/TwlBkpCheck/Windows/TWLBackupBlock/HeaderBody.cs index 9a9336a..e95b1ce 100644 --- a/TwlBkpCheck/Windows/TWLBackupBlock/HeaderBody.cs +++ b/TwlBkpCheck/Windows/TWLBackupBlock/HeaderBody.cs @@ -23,6 +23,10 @@ namespace TwlBackupBlock // for WithPrivateSave public const int RESERVED_SIZE_FOR_WPS = 12; + // for Legacy + public const int RESERVED_SIZE_FOR_LEGACY = 4; + public const int NUM_OF_SECTION_LEGACY = 4; + public UInt32 signature; public UInt16 companyCode; public UInt16 version; @@ -41,6 +45,10 @@ namespace TwlBackupBlock public UInt32 privateSaveForWPS; public readonly Byte[] reservedForWPS; + // for Legacy + public UInt32 contentIdForLegacy; + public UInt16 contentIndexForLegacy; + private BkpType type; private int headerSize; @@ -72,12 +80,19 @@ namespace TwlBackupBlock uniqueId = new Byte[UNIQUE_ID_SIZE]; hardwareId = new Byte[HARDWARE_ID_SIZE]; - fileSizes = new UInt32[NUM_OF_SECTION]; - contentId = new UInt32[MAX_CONTENTS]; - contentIndex = new UInt16[MAX_CONTENTS]; + if (type != BkpType.LEGACY) + { + fileSizes = new UInt32[NUM_OF_SECTION]; + contentId = new UInt32[MAX_CONTENTS]; + contentIndex = new UInt16[MAX_CONTENTS]; + reserved = new Byte[RESERVED_SIZE]; + } + else + { + fileSizes = new UInt32[NUM_OF_SECTION_LEGACY]; + reserved = new Byte[RESERVED_SIZE_FOR_LEGACY]; + } tmdReserved = new TmdReserved(); - reserved = new Byte[RESERVED_SIZE]; - if (type == BkpType.WITH_PRIVATE_SAVE) { reservedForWPS = new Byte[RESERVED_SIZE_FOR_WPS]; @@ -154,7 +169,6 @@ namespace TwlBackupBlock using (var ms = new MemoryStream(bytes)) using (var bw = new BinaryWriter(ms)) { - // TODO : Legacy 対応 bw.Write(signature); bw.Write(companyCode); bw.Write(version); @@ -166,16 +180,33 @@ namespace TwlBackupBlock { bw.Write(e); } - foreach (UInt32 e in contentId) + if (type != BkpType.LEGACY) { - bw.Write(e); + foreach (UInt32 e in contentId) + { + bw.Write(e); + } } - foreach (UInt16 e in contentIndex) + else { - bw.Write(e); + bw.Write(contentIdForLegacy); + } + if (type != BkpType.LEGACY) + { + foreach (UInt16 e in contentIndex) + { + bw.Write(e); + } } bw.Write(tmdReserved.GetBytes()); - bw.Write(headerVersion); + if (type == BkpType.LEGACY) + { + bw.Write(contentIndexForLegacy); + } + if (type != BkpType.LEGACY) + { + bw.Write(headerVersion); + } bw.Write(reserved); if (type == BkpType.WITH_PRIVATE_SAVE) { @@ -204,7 +235,6 @@ namespace TwlBackupBlock using (var ms = new MemoryStream(bytes)) using (var br = new ExtBinaryReader(ms)) { - // TODO : Legacy 対応 br.Read(ref signature); br.Read(ref companyCode); br.Read(ref version); @@ -213,14 +243,31 @@ namespace TwlBackupBlock br.Read(ref titleId); br.Read(ref requiredSize); br.Read(fileSizes); - br.Read(contentId); - br.Read(contentIndex); + if (type != BkpType.LEGACY) + { + br.Read(contentId); + } + else + { + br.Read(ref contentIdForLegacy); + } + if (type != BkpType.LEGACY) + { + br.Read(contentIndex); + } { byte[] tmdReservedBytes = new byte[TMD_RESERVED_SIZE]; br.Read(tmdReservedBytes); tmdReserved.SetBytes(tmdReservedBytes); } - br.Read(ref headerVersion); + if (type == BkpType.LEGACY) + { + br.Read(ref contentIndexForLegacy); + } + if (type != BkpType.LEGACY) + { + br.Read(ref headerVersion); + } br.Read(reserved); if (type == BkpType.WITH_PRIVATE_SAVE) { diff --git a/TwlBkpCheck/Windows/TWLBackupBlock/Utility.cs b/TwlBkpCheck/Windows/TWLBackupBlock/Utility.cs index c5e97d6..003d59f 100644 --- a/TwlBkpCheck/Windows/TWLBackupBlock/Utility.cs +++ b/TwlBkpCheck/Windows/TWLBackupBlock/Utility.cs @@ -23,6 +23,17 @@ namespace TwlBackupBlock PRIVATE_SAVE }; + // いまいち・・・ + public const int MAX_CONTENTS_LEGACY = 1; + public enum SectionIndexLegacy + { + TMD, + CONTENT, + PUBLIC_SAVE = CONTENT + MAX_CONTENTS_LEGACY, + SUB_BANNER, + PRIVATE_SAVE + }; + private const int KEY_SIZE = 16; private const int ROUND_SCALE = 16; @@ -41,8 +52,10 @@ namespace TwlBackupBlock 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_EX_HEADER_SIZE = EX_HEADER_SIZE + AES_SIGN_HEADER_SIZE; + private const int ENCRYPT_LEGACY_HEADER_SIZE = LEGACY_HEADER_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; + private const int ENCRYPT_LEGACY_SIGNATURE_SIZE = LEGACY_SIGNATURE_SIZE + AES_SIGN_HEADER_SIZE; /// /// バックアップデータをブロックに分割して復号化をおこないます。 @@ -53,17 +66,13 @@ namespace TwlBackupBlock /// 分割、復号化されたブロック。 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; + int contentsNum = MAX_CONTENTS; + int indexPublicSave = (int)SectionIndexLegacy.PUBLIC_SAVE; + int indexSubBanner = (int)SectionIndexLegacy.SUB_BANNER; switch (type) { @@ -80,6 +89,16 @@ namespace TwlBackupBlock encryptHeaderSize = ENCRYPT_EX_HEADER_SIZE; encryptSignatureSize = ENCRYPT_EX_SIGNATURE_SIZE; break; + + case BkpType.LEGACY: + headerSize = LEGACY_HEADER_SIZE; + signatureSize = LEGACY_SIGNATURE_SIZE; + encryptHeaderSize = ENCRYPT_LEGACY_HEADER_SIZE; + encryptSignatureSize = ENCRYPT_LEGACY_SIGNATURE_SIZE; + contentsNum = MAX_CONTENTS_LEGACY; + indexPublicSave = (int)SectionIndexLegacy.PUBLIC_SAVE; + indexSubBanner = (int)SectionIndexLegacy.SUB_BANNER; + break; } if (data == null) @@ -122,15 +141,14 @@ namespace TwlBackupBlock blocks.signature.body = new SignatureBody( DecryptBlock(br, signatureSize, key, out blocks.signature.mac, out blocks.signature.iv), type); - // TODO : Legacy 対応 int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD]; - int[] CONTENT_SIZE = new int[MAX_CONTENTS]; - for (int i = 0; i < MAX_CONTENTS; i++) + int[] CONTENT_SIZE = new int[contentsNum]; + for (int i = 0; i < contentsNum; 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 PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[indexPublicSave]; + int SUB_BANNER_SIZE = (int)headerBody.fileSizes[indexSubBanner]; int PRIVATE_SAVE_SIZE = 0; if (type == BkpType.WITH_PRIVATE_SAVE) { @@ -138,7 +156,7 @@ namespace TwlBackupBlock } 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 < contentsNum; i++) { if (CONTENT_SIZE[i] > 0) { @@ -393,17 +411,13 @@ namespace TwlBackupBlock /// 検証に成功した場合はtrue。それ以外の場合はfalse。 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; + int contentsNum = MAX_CONTENTS; + int indexPublicSave = (int)SectionIndex.PUBLIC_SAVE; + int indexSubBanner = (int)SectionIndex.SUB_BANNER; switch (type) { @@ -420,6 +434,16 @@ namespace TwlBackupBlock encryptHeaderSize = ENCRYPT_EX_HEADER_SIZE; encryptSignatureSize = ENCRYPT_EX_SIGNATURE_SIZE; break; + + case BkpType.LEGACY: + headerSize = LEGACY_HEADER_SIZE; + signatureSize = LEGACY_SIGNATURE_SIZE; + encryptHeaderSize = ENCRYPT_LEGACY_HEADER_SIZE; + encryptSignatureSize = ENCRYPT_LEGACY_SIGNATURE_SIZE; + contentsNum = MAX_CONTENTS_LEGACY; + indexPublicSave = (int)SectionIndexLegacy.PUBLIC_SAVE; + indexSubBanner = (int)SectionIndexLegacy.SUB_BANNER; + break; } if (data == null) @@ -492,13 +516,13 @@ namespace TwlBackupBlock // TODO : Legacy 対応 int TMD_SIZE = (int)headerBody.fileSizes[(int)SectionIndex.TMD]; - int[] CONTENT_SIZE = new int[MAX_CONTENTS]; - for (int i = 0; i < MAX_CONTENTS; i++) + int[] CONTENT_SIZE = new int[contentsNum]; + for (int i = 0; i < contentsNum; 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 PUBLIC_SAVE_SIZE = (int)headerBody.fileSizes[indexPublicSave]; + int SUB_BANNER_SIZE = (int)headerBody.fileSizes[indexSubBanner]; int PRIVATE_SAVE_SIZE = 0; if (type == BkpType.WITH_PRIVATE_SAVE) { @@ -508,7 +532,7 @@ namespace TwlBackupBlock int restSize = RoundUp(TMD_SIZE, ROUND_SCALE) + RoundUp(PUBLIC_SAVE_SIZE, ROUND_SCALE) + RoundUp(SUB_BANNER_SIZE, ROUND_SCALE) + AES_SIGN_HEADER_SIZE * 3; - for (int i = 0; i < MAX_CONTENTS; i++) + for (int i = 0; i < contentsNum; i++) { if (CONTENT_SIZE[i] > 0) { @@ -536,7 +560,7 @@ namespace TwlBackupBlock Console.WriteLine("TMDブロックのハッシュが一致しません"); return false; } - for (int i = 0; i < MAX_CONTENTS; i++) + for (int i = 0; i < contentsNum; i++) { if (CONTENT_SIZE[i] > 0) { @@ -560,7 +584,7 @@ namespace TwlBackupBlock Console.WriteLine("publicセーブデータブロックのMACが一致しません"); return false; } - if (!CheckHash(blocks.publicSave, signatureBody.digest.section[(int)SectionIndex.PUBLIC_SAVE])) + if (!CheckHash(blocks.publicSave, signatureBody.digest.section[indexPublicSave])) { Console.WriteLine("publicセーブデータブロックのハッシュが一致しません"); return false; @@ -571,7 +595,7 @@ namespace TwlBackupBlock Console.WriteLine("サブバナーブロックの内容とMACが一致しません"); return false; } - if (!CheckHash(blocks.subBanner, signatureBody.digest.section[(int)SectionIndex.SUB_BANNER])) + if (!CheckHash(blocks.subBanner, signatureBody.digest.section[indexSubBanner])) { Console.WriteLine("サブバナーブロックのハッシュが一致しません"); return false;