mirror of
https://github.com/rvtr/ctr_test_tools.git
synced 2025-06-19 00:55:31 -04:00

SignatureBody に WithPrivateSave 形式の処理の追加。 LegacyHeaderBody の削除。 git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_test_tools@34 6b0af911-cb57-b745-895f-eec5701120e1
233 lines
7.0 KiB
C#
233 lines
7.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
|
|
namespace TwlBackupBlock
|
|
{
|
|
/// <summary>
|
|
/// 署名ブロック中のハッシュセット。
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// コンストラクタ。
|
|
/// </summary>
|
|
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];
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 署名ブロックのデータ本体。
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定したバイトを取得します。
|
|
/// </summary>
|
|
/// <param name="index">取得したいバイトのインデックス。</param>
|
|
/// <returns><paramref name="index"/>で指定したバイト</returns>
|
|
public byte ReadByte(int index)
|
|
{
|
|
if (index < 0 || index >= signatureSize)
|
|
{
|
|
throw new ArgumentException("index");
|
|
}
|
|
// TODO 処理が遅ければ効率化
|
|
byte[] bytes = GetBytes();
|
|
return bytes[index];
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定したバイトを書き換えます。
|
|
/// </summary>
|
|
/// <param name="index">書き換えたいバイトのインデックス。</param>
|
|
/// <param name="b">上書きに使うバイト。</param>
|
|
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);
|
|
}
|
|
}
|
|
}
|