using System; using System.IO; using System.Diagnostics; namespace TwlBackupBlock { /// /// 署名ブロック中のハッシュセット。 /// public class TwlBackupHashSet { public const int HASH_SIZE = 32; public const int NUM_OF_SECTION_NORMAL = 11; public const int NUM_OF_SECTION_EX = 12; public const int NUM_OF_SECTION_LEGACY = 4; public readonly byte[] banner; public readonly byte[] header; public readonly byte[][] section; private BkpType type; /// /// コンストラクタ。 /// public TwlBackupHashSet(BkpType type) { this.type = type; banner = new byte[HASH_SIZE]; header = new byte[HASH_SIZE]; if (this.type == BkpType.NORMAL) { section = new byte[NUM_OF_SECTION_NORMAL][]; } else if (this.type == BkpType.WITH_PRIVATE_SAVE) { section = new byte[NUM_OF_SECTION_EX][]; } else if (this.type == BkpType.LEGACY) { section = new byte[NUM_OF_SECTION_LEGACY][]; } for (int i = 0; i < section.Length; i++) { section[i] = new byte[HASH_SIZE]; } } } /// /// 署名ブロックのデータ本体。 /// public class SignatureBody : AbstractBody { public const int SIGNATURE_SIZE_NORMAL = 1248; public const int SIGNATURE_SIZE_EX = 1280; public const int SIGNATURE_SIZE_LEGACY = 1024; public const int ECC_SIGN_SIZE = 60; public const int ECC_CERT_SIZE = 384; public readonly TwlBackupHashSet digest; public readonly byte[] sign; public readonly byte[][] cert; public UInt32 reserved; private BkpType type; private int signatureSize; public SignatureBody(byte[] data, BkpType type) { this.type = type; switch (this.type) { case BkpType.NORMAL: signatureSize = SIGNATURE_SIZE_NORMAL; break; case BkpType.WITH_PRIVATE_SAVE: signatureSize = SIGNATURE_SIZE_EX; break; case BkpType.LEGACY: signatureSize = SIGNATURE_SIZE_LEGACY; break; } if (data == null) { throw new ArgumentNullException("data"); } if (data.Length != signatureSize) { string message = string.Format("data.Length % {0} != 0 (data.Length:{1})", signatureSize, data.Length); throw new ArgumentException("data", message); } digest = new TwlBackupHashSet(this.type); sign = new byte[ECC_SIGN_SIZE]; cert = new byte[2][]; for (int i = 0; i < cert.Length; i++) { cert[i] = new byte[ECC_CERT_SIZE]; } SetBytes(data); } public override byte this[int index] { get { if (index < 0 || index >= signatureSize) { throw new ArgumentException("index"); } return ReadByte(index); } set { if (index < 0 || index >= signatureSize) { throw new ArgumentException("index"); } WriteByte(index, value); } } public override int Length { get { return signatureSize; } } /// /// 指定したバイトを取得します。 /// /// 取得したいバイトのインデックス。 /// で指定したバイト public byte ReadByte(int index) { if (index < 0 || index >= signatureSize) { throw new ArgumentException("index"); } // TODO 処理が遅ければ効率化 byte[] bytes = GetBytes(); return bytes[index]; } /// /// 指定したバイトを書き換えます。 /// /// 書き換えたいバイトのインデックス。 /// 上書きに使うバイト。 public void WriteByte(int index, byte b) { if (index < 0 || index >= signatureSize) { throw new ArgumentException("index"); } // TODO 処理が遅ければ効率化 byte[] bytes = GetBytes(); bytes[index] = b; SetBytes(bytes); } public override byte[] GetBytes() { byte[] bytes = new byte[signatureSize]; using (var ms = new MemoryStream(bytes)) using (var bw = new BinaryWriter(ms)) { bw.Write(digest.banner); bw.Write(digest.header); foreach (var e in digest.section) { bw.Write(e); } bw.Write(sign); foreach (var e in cert) { bw.Write(e); } bw.Write(reserved); Debug.Assert(ms.Position == signatureSize); } return bytes; } public override void SetBytes(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } if (bytes.Length != signatureSize) { string message = string.Format("bytes.Length != {0} (bytes.Length:{1})", signatureSize, bytes.Length); throw new ArgumentException("bytes", message); } using (var ms = new MemoryStream(bytes)) using (var br = new ExtBinaryReader(ms)) { br.Read(digest.banner); br.Read(digest.header); foreach (var e in digest.section) { br.Read(e); } br.Read(sign); foreach (var e in cert) { br.Read(e); } br.Read(ref reserved); Debug.Assert(ms.Position == signatureSize); } } public override object Clone() { return new SignatureBody(GetBytes(), type); } } }