Remove deprecated classes

This commit is contained in:
Alex Barney 2021-11-03 23:22:04 -07:00
parent 0a8fb8a5c0
commit 2793648d37
6 changed files with 0 additions and 864 deletions

View file

@ -10,32 +10,6 @@ namespace LibHac.FsSystem
{ {
public static class StorageExtensions public static class StorageExtensions
{ {
[Obsolete("The standard Span-based IStorage methods should be used instead.")]
public static Result Read(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset)
{
ValidateStorageParameters(buffer, offset, count, bufferOffset);
return storage.Read(offset, buffer.AsSpan(bufferOffset, count));
}
[Obsolete("The standard Span-based IStorage methods should be used instead.")]
public static Result Write(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset)
{
ValidateStorageParameters(buffer, offset, count, bufferOffset);
return storage.Write(offset, buffer.AsSpan(bufferOffset, count));
}
// todo: remove this method when the above Read and Write methods are removed
// (Hopefully they're still above, or else someone didn't listen)
// ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
private static void ValidateStorageParameters(byte[] buffer, long offset, int count, int bufferOffset)
// ReSharper restore ParameterOnlyUsedForPreconditionCheck.Local
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Argument must be non-negative.");
if (bufferOffset < 0) throw new ArgumentOutOfRangeException(nameof(bufferOffset), "Argument must be non-negative.");
}
public static IStorage Slice(this IStorage storage, long start) public static IStorage Slice(this IStorage storage, long start)
{ {
storage.GetSize(out long length).ThrowIfFailure(); storage.GetSize(out long length).ThrowIfFailure();

View file

@ -1,213 +0,0 @@
using System;
using System.IO;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Kernel;
namespace LibHac
{
[Obsolete("This class has been deprecated. LibHac.Loader.KipReader should be used instead.")]
public class Kip
{
private const int HeaderSize = 0x100;
public KipHeader Header { get; }
public int[] SectionOffsets { get; } = new int[6];
public int Size { get; }
private IStorage Storage { get; }
public Kip(IStorage storage)
{
Header = new KipHeader(storage);
Size = HeaderSize;
for (int index = 0; index < Header.Sections.Length; index++)
{
int sectionSize = Header.Sections[index].CompressedSize;
SectionOffsets[index] = Size;
Size += sectionSize;
}
Storage = storage.Slice(0, Size);
}
public IStorage OpenSection(int index)
{
if (index < 0 || index > 5)
{
throw new ArgumentOutOfRangeException(nameof(index), "Section index must be between 0-5");
}
return Storage.Slice(SectionOffsets[index], Header.Sections[index].CompressedSize);
}
public byte[] DecompressSection(int index)
{
IStorage compStorage = OpenSection(index);
compStorage.GetSize(out long compressedSize).ThrowIfFailure();
byte[] compressed = new byte[compressedSize];
compStorage.Read(0, compressed).ThrowIfFailure();
return DecompressBlz(compressed);
}
public IStorage OpenRawFile() => Storage;
private static byte[] DecompressBlz(byte[] compressed)
{
int additionalSize = BitConverter.ToInt32(compressed, compressed.Length - 4);
int headerSize = BitConverter.ToInt32(compressed, compressed.Length - 8);
int totalCompSize = BitConverter.ToInt32(compressed, compressed.Length - 12);
byte[] decompressed = new byte[totalCompSize + additionalSize];
int inOffset = totalCompSize - headerSize;
int outOffset = totalCompSize + additionalSize;
while (outOffset > 0)
{
byte control = compressed[--inOffset];
for (int i = 0; i < 8; i++)
{
if ((control & 0x80) != 0)
{
if (inOffset < 2) throw new InvalidDataException("KIP1 decompression out of bounds!");
inOffset -= 2;
ushort segmentValue = BitConverter.ToUInt16(compressed, inOffset);
int segmentSize = ((segmentValue >> 12) & 0xF) + 3;
int segmentOffset = (segmentValue & 0x0FFF) + 3;
if (outOffset < segmentSize)
{
// Kernel restricts segment copy to stay in bounds.
segmentSize = outOffset;
}
outOffset -= segmentSize;
for (int j = 0; j < segmentSize; j++)
{
decompressed[outOffset + j] = decompressed[outOffset + j + segmentOffset];
}
}
else
{
// Copy directly.
if (inOffset < 1) throw new InvalidDataException("KIP1 decompression out of bounds!");
decompressed[--outOffset] = compressed[--inOffset];
}
control <<= 1;
if (outOffset == 0) return decompressed;
}
}
return decompressed;
}
}
public class KipHeader
{
public string Magic { get; }
public string Name { get; }
public ulong TitleId { get; }
public int ProcessCategory { get; }
public byte MainThreadPriority { get; }
public byte DefaultCore { get; }
public byte Field1E { get; }
public byte Flags { get; }
public KipSectionHeader[] Sections { get; } = new KipSectionHeader[6];
public byte[] Capabilities { get; }
public KipHeader(IStorage storage)
{
var reader = new BinaryReader(storage.AsStream());
Magic = reader.ReadAscii(4);
if (Magic != "KIP1")
{
throw new InvalidDataException("Invalid KIP file!");
}
Name = reader.ReadAsciiZ(0xC);
reader.BaseStream.Position = 0x10;
TitleId = reader.ReadUInt64();
ProcessCategory = reader.ReadInt32();
MainThreadPriority = reader.ReadByte();
DefaultCore = reader.ReadByte();
Field1E = reader.ReadByte();
Flags = reader.ReadByte();
for (int i = 0; i < Sections.Length; i++)
{
Sections[i] = new KipSectionHeader(reader);
}
Capabilities = reader.ReadBytes(0x20);
}
}
public class KipSectionHeader
{
public int OutOffset { get; }
public int DecompressedSize { get; }
public int CompressedSize { get; }
public int Attribute { get; }
public KipSectionHeader(BinaryReader reader)
{
OutOffset = reader.ReadInt32();
DecompressedSize = reader.ReadInt32();
CompressedSize = reader.ReadInt32();
Attribute = reader.ReadInt32();
}
}
public class Ini1
{
public KipReader[] Kips { get; }
public string Magic { get; }
public int Size { get; }
public int KipCount { get; }
private IStorage Storage { get; }
public Ini1(IStorage storage)
{
Storage = storage;
var reader = new BinaryReader(Storage.AsStream());
Magic = reader.ReadAscii(4);
if (Magic != "INI1")
{
throw new InvalidDataException("Invalid INI1 file!");
}
Size = reader.ReadInt32();
KipCount = reader.ReadInt32();
Kips = new KipReader[KipCount];
int offset = 0x10;
for (int i = 0; i < KipCount; i++)
{
using var sharedStorage = new SharedRef<IStorage>(Storage.Slice(offset));
Kips[i] = new KipReader();
Kips[i].Initialize(in sharedStorage).ThrowIfFailure();
offset += Kips[i].GetFileSize();
}
}
}
}

View file

@ -1,190 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace LibHac
{
[Obsolete("This class has been deprecated. LibHac.Ns.ApplicationControlProperty should be used instead.")]
public class Nacp
{
public NacpDescription[] Descriptions { get; } = new NacpDescription[0x10];
public string Isbn { get; }
public byte StartupUserAccount { get; }
public byte UserAccountSwitchLock { get; }
public byte AocRegistrationType { get; }
public int AttributeFlag { get; }
public uint SupportedLanguageFlag { get; }
public uint ParentalControlFlag { get; }
public byte Screenshot { get; }
public byte VideoCapture { get; }
public byte DataLossConfirmation { get; }
public byte PlayLogPolicy { get; }
public ulong PresenceGroupId { get; }
public sbyte[] RatingAge { get; } = new sbyte[32];
public string DisplayVersion { get; }
public ulong AddOnContentBaseId { get; }
public ulong SaveDataOwnerId { get; }
public long UserAccountSaveDataSize { get; }
public long UserAccountSaveDataJournalSize { get; }
public long DeviceSaveDataSize { get; }
public long DeviceSaveDataJournalSize { get; }
public long BcatDeliveryCacheStorageSize { get; }
public string ApplicationErrorCodeCategory { get; }
public ulong[] LocalCommunicationId { get; } = new ulong[8];
public byte LogoType { get; }
public byte LogoHandling { get; }
public byte RuntimeAddOnContentInstall { get; }
public byte[] Reserved00 { get; }
public byte CrashReport { get; }
public byte Hdcp { get; }
public ulong SeedForPseudoDeviceId { get; }
public string BcatPassphrase { get; }
public byte Reserved01 { get; }
public byte[] Reserved02 { get; }
public long UserAccountSaveDataSizeMax { get; }
public long UserAccountSaveDataJournalSizeMax { get; }
public long DeviceSaveDataSizeMax { get; }
public long DeviceSaveDataJournalSizeMax { get; }
public long TemporaryStorageSize { get; }
public long CacheStorageSize { get; }
public long CacheStorageJournalSize { get; }
public long CacheStorageDataAndJournalSizeMax { get; }
public short CacheStorageIndex { get; }
public byte[] Reserved03 { get; }
public List<ulong> PlayLogQueryableApplicationId { get; } = new List<ulong>();
public byte PlayLogQueryCapability { get; }
public byte RepairFlag { get; }
public byte ProgramIndex { get; }
public long TotalSaveDataSize { get; }
public long UserTotalSaveDataSize { get; }
public long DeviceTotalSaveDataSize { get; }
public Nacp() { }
public Nacp(Stream file)
{
long start = file.Position;
var reader = new BinaryReader(file);
for (int i = 0; i < 16; i++)
{
Descriptions[i] = new NacpDescription(reader, i);
}
Isbn = reader.ReadUtf8Z(37);
reader.BaseStream.Position = start + 0x3025;
StartupUserAccount = reader.ReadByte();
UserAccountSwitchLock = reader.ReadByte();
AocRegistrationType = reader.ReadByte();
AttributeFlag = reader.ReadInt32();
SupportedLanguageFlag = reader.ReadUInt32();
ParentalControlFlag = reader.ReadUInt32();
Screenshot = reader.ReadByte();
VideoCapture = reader.ReadByte();
DataLossConfirmation = reader.ReadByte();
PlayLogPolicy = reader.ReadByte();
PresenceGroupId = reader.ReadUInt64();
for (int i = 0; i < RatingAge.Length; i++)
{
RatingAge[i] = reader.ReadSByte();
}
DisplayVersion = reader.ReadUtf8Z(16);
reader.BaseStream.Position = start + 0x3070;
AddOnContentBaseId = reader.ReadUInt64();
SaveDataOwnerId = reader.ReadUInt64();
UserAccountSaveDataSize = reader.ReadInt64();
UserAccountSaveDataJournalSize = reader.ReadInt64();
DeviceSaveDataSize = reader.ReadInt64();
DeviceSaveDataJournalSize = reader.ReadInt64();
BcatDeliveryCacheStorageSize = reader.ReadInt64();
ApplicationErrorCodeCategory = reader.ReadUtf8Z(8);
reader.BaseStream.Position = start + 0x30B0;
for (int i = 0; i < LocalCommunicationId.Length; i++)
{
LocalCommunicationId[i] = reader.ReadUInt64();
}
LogoType = reader.ReadByte();
LogoHandling = reader.ReadByte();
RuntimeAddOnContentInstall = reader.ReadByte();
Reserved00 = reader.ReadBytes(3);
CrashReport = reader.ReadByte();
Hdcp = reader.ReadByte();
SeedForPseudoDeviceId = reader.ReadUInt64();
BcatPassphrase = reader.ReadUtf8Z(65);
reader.BaseStream.Position = start + 0x3141;
Reserved01 = reader.ReadByte();
Reserved02 = reader.ReadBytes(6);
UserAccountSaveDataSizeMax = reader.ReadInt64();
UserAccountSaveDataJournalSizeMax = reader.ReadInt64();
DeviceSaveDataSizeMax = reader.ReadInt64();
DeviceSaveDataJournalSizeMax = reader.ReadInt64();
TemporaryStorageSize = reader.ReadInt64();
CacheStorageSize = reader.ReadInt64();
CacheStorageJournalSize = reader.ReadInt64();
CacheStorageDataAndJournalSizeMax = reader.ReadInt64();
CacheStorageIndex = reader.ReadInt16();
Reserved03 = reader.ReadBytes(6);
for (int i = 0; i < 16; i++)
{
ulong value = reader.ReadUInt64();
if (value != 0) PlayLogQueryableApplicationId.Add(value);
}
PlayLogQueryCapability = reader.ReadByte();
RepairFlag = reader.ReadByte();
ProgramIndex = reader.ReadByte();
UserTotalSaveDataSize = UserAccountSaveDataSize + UserAccountSaveDataJournalSize;
DeviceTotalSaveDataSize = DeviceSaveDataSize + DeviceSaveDataJournalSize;
TotalSaveDataSize = UserTotalSaveDataSize + DeviceTotalSaveDataSize;
}
}
public class NacpDescription
{
public string Title { get; }
public string Developer { get; }
public TitleLanguage Language;
public NacpDescription() { }
public NacpDescription(BinaryReader reader, int index)
{
Language = (TitleLanguage)index;
long start = reader.BaseStream.Position;
Title = reader.ReadUtf8Z();
reader.BaseStream.Position = start + 0x200;
Developer = reader.ReadUtf8Z();
reader.BaseStream.Position = start + 0x300;
}
}
public enum TitleLanguage
{
AmericanEnglish = 0,
BritishEnglish,
Japanese,
French,
German,
LatinAmericanSpanish,
Spanish,
Italian,
Dutch,
CanadianFrench,
Portuguese,
Russian,
Korean,
Taiwanese,
Chinese
}
}

View file

@ -1,116 +0,0 @@
using System;
using System.Collections;
using System.IO;
using LibHac.Fs;
using LibHac.FsSystem;
namespace LibHac
{
[Obsolete("This class has been deprecated. LibHac.Loader.NsoReader should be used instead.")]
public class Nso
{
public NsoSection[] Sections { get; }
public RodataRelativeExtent[] RodataRelativeExtents { get; }
public uint BssSize { get; }
public byte[] BuildId { get; } = new byte[0x20];
private IStorage Storage { get; }
public Nso(IStorage storage)
{
Storage = storage;
var reader = new BinaryReader(Storage.AsStream());
if (reader.ReadAscii(4) != "NSO0")
throw new InvalidDataException("NSO magic is incorrect!");
reader.ReadUInt32(); // Version
reader.ReadUInt32(); // Reserved/Unused
var flags = new BitArray(new[] { (int)reader.ReadUInt32() });
var textSection = new NsoSection(Storage);
var rodataSection = new NsoSection(Storage);
var dataSection = new NsoSection(Storage);
textSection.IsCompressed = flags[0];
rodataSection.IsCompressed = flags[1];
dataSection.IsCompressed = flags[2];
textSection.CheckHash = flags[3];
rodataSection.CheckHash = flags[4];
dataSection.CheckHash = flags[5];
textSection.ReadSegmentHeader(reader);
reader.ReadUInt32(); // Module offset (TODO)
rodataSection.ReadSegmentHeader(reader);
reader.ReadUInt32(); // Module file size
dataSection.ReadSegmentHeader(reader);
BssSize = reader.ReadUInt32();
reader.Read(BuildId, 0, 0x20);
textSection.CompressedSize = reader.ReadUInt32();
rodataSection.CompressedSize = reader.ReadUInt32();
dataSection.CompressedSize = reader.ReadUInt32();
reader.ReadBytes(0x1C); // Padding
RodataRelativeExtents = new[]
{
new RodataRelativeExtent(reader), new RodataRelativeExtent(reader), new RodataRelativeExtent(reader)
};
reader.Read(textSection.Hash, 0, 0x20);
reader.Read(rodataSection.Hash, 0, 0x20);
reader.Read(dataSection.Hash, 0, 0x20);
Sections = new[] { textSection, rodataSection, dataSection };
reader.Close();
}
public class NsoSection
{
private IStorage Storage { get; }
public bool IsCompressed { get; set; }
public bool CheckHash { get; set; }
public uint FileOffset { get; set; }
public uint MemoryOffset { get; set; }
public uint DecompressedSize { get; set; }
public uint CompressedSize { get; set; }
public byte[] Hash { get; } = new byte[0x20];
public NsoSection(IStorage storage)
{
Storage = storage;
}
public IStorage OpenSection()
{
return Storage.Slice(FileOffset, CompressedSize);
}
public byte[] DecompressSection()
{
byte[] compressed = new byte[CompressedSize];
OpenSection().Read(0, compressed).ThrowIfFailure();
if (IsCompressed)
return Lz4.Decompress(compressed, (int)DecompressedSize);
else
return compressed;
}
internal void ReadSegmentHeader(BinaryReader reader)
{
FileOffset = reader.ReadUInt32();
MemoryOffset = reader.ReadUInt32();
DecompressedSize = reader.ReadUInt32();
}
}
public class RodataRelativeExtent
{
public uint RegionRodataOffset { get; }
public uint RegionSize { get; }
public RodataRelativeExtent(BinaryReader reader)
{
RegionRodataOffset = reader.ReadUInt32();
RegionSize = reader.ReadUInt32();
}
}
}
}

View file

@ -1,122 +0,0 @@
using System;
using System.IO;
using LibHac.Common.Keys;
using LibHac.Fs;
using LibHac.FsSystem;
namespace LibHac
{
[Obsolete("This class has been deprecated. LibHac.Boot.Package1 should be used instead.")]
public class Package1
{
private const uint Pk11Magic = 0x31314B50; // PK11
public byte[] BuildHash { get; }
public string BuildDate { get; }
public int Field1E { get; }
public int Pk11Size { get; }
public byte[] Counter { get; }
public int KeyRevision { get; }
public Pk11 Pk11 { get; }
private IStorage Storage { get; }
public Package1(KeySet keySet, IStorage storage)
{
Storage = storage;
var reader = new BinaryReader(storage.AsStream());
BuildHash = reader.ReadBytes(0x10);
BuildDate = reader.ReadAscii(0xE);
Field1E = reader.ReadUInt16();
reader.BaseStream.Position = 0x3FE0;
Pk11Size = reader.ReadInt32();
reader.BaseStream.Position += 0xC;
Counter = reader.ReadBytes(0x10);
// Try decrypting the PK11 blob with all known package1 keys
IStorage encStorage = Storage.Slice(0x4000, Pk11Size);
byte[] decBuffer = new byte[0x10];
for (int i = 0; i < 0x20; i++)
{
var dec = new Aes128CtrStorage(encStorage, keySet.Package1Keys[i].DataRo.ToArray(), Counter, true);
dec.Read(0, decBuffer).ThrowIfFailure();
if (BitConverter.ToUInt32(decBuffer, 0) == Pk11Magic)
{
KeyRevision = i;
Pk11 = new Pk11(new CachedStorage(dec, 4, true));
return;
}
}
throw new InvalidDataException("Failed to decrypt PK11! Is the correct key present?");
}
public IStorage OpenDecryptedPackage()
{
IStorage[] storages = { OpenPackage1Ldr(), Pk11.OpenDecryptedPk11() };
return new ConcatenationStorage(storages, true);
}
public IStorage OpenPackage1Ldr() => Storage.Slice(0, 0x4000);
}
public class Pk11
{
private const int DataOffset = 0x20;
public string Magic { get; }
public int[] SectionSizes { get; } = new int[3];
public int[] SectionOffsets { get; } = new int[3];
private IStorage Storage { get; }
public Pk11(IStorage storage)
{
Storage = storage;
var reader = new BinaryReader(storage.AsStream());
Magic = reader.ReadAscii(4);
SectionSizes[0] = reader.ReadInt32();
SectionOffsets[0] = reader.ReadInt32();
reader.BaseStream.Position += 4;
SectionSizes[1] = reader.ReadInt32();
SectionOffsets[1] = reader.ReadInt32();
SectionSizes[2] = reader.ReadInt32();
SectionOffsets[2] = reader.ReadInt32();
SectionOffsets[0] = DataOffset;
SectionOffsets[1] = SectionOffsets[0] + SectionSizes[0];
SectionOffsets[2] = SectionOffsets[1] + SectionSizes[1];
}
public IStorage OpenSection(int index)
{
if (index < 0 || index > 2)
{
throw new ArgumentOutOfRangeException(nameof(index), "Section index must be one of: 0, 1, 2");
}
return Storage.Slice(SectionOffsets[index], SectionSizes[index]);
}
public IStorage OpenDecryptedPk11() => Storage;
public IStorage OpenWarmboot() => OpenSection(GetWarmbootSection());
public IStorage OpenNxBootloader() => OpenSection(GetNxBootloaderSection());
public IStorage OpenSecureMonitor() => OpenSection(GetSecureMonitorSection());
// todo: Handle the old layout from before 2.0.0
private int GetWarmbootSection() => 0;
private int GetNxBootloaderSection() => 1;
private int GetSecureMonitorSection() => 2;
}
}

View file

@ -1,197 +0,0 @@
using System;
using System.IO;
using LibHac.Common.Keys;
using LibHac.Fs;
using LibHac.FsSystem;
namespace LibHac
{
[Obsolete("This class has been deprecated. LibHac.Boot.Package2StorageReader should be used instead.")]
public class Package2
{
private const uint Pk21Magic = 0x31324B50; // PK21
public Package2Header Header { get; }
public int KeyRevision { get; }
public byte[] Key { get; }
public int PackageSize { get; }
public int HeaderVersion { get; }
private IStorage Storage { get; }
public Package2(KeySet keySet, IStorage storage)
{
Storage = storage;
IStorage headerStorage = Storage.Slice(0, 0x200);
KeyRevision = FindKeyGeneration(keySet, headerStorage);
Key = keySet.Package2Keys[KeyRevision].DataRo.ToArray();
Header = new Package2Header(headerStorage, keySet, KeyRevision);
PackageSize = BitConverter.ToInt32(Header.Counter, 0) ^ BitConverter.ToInt32(Header.Counter, 8) ^
BitConverter.ToInt32(Header.Counter, 12);
HeaderVersion = Header.Counter[4] ^ Header.Counter[6] ^ Header.Counter[7];
if (PackageSize != 0x200 + Header.SectionSizes[0] + Header.SectionSizes[1] + Header.SectionSizes[2])
{
throw new InvalidDataException("Package2 Header is corrupt!");
}
}
public IStorage OpenDecryptedPackage()
{
if (Header.SectionSizes[1] == 0)
{
IStorage[] storages = { OpenHeaderPart1(), OpenHeaderPart2(), OpenKernel() };
return new ConcatenationStorage(storages, true);
}
else
{
IStorage[] storages = { OpenHeaderPart1(), OpenHeaderPart2(), OpenKernel(), OpenIni1() };
return new ConcatenationStorage(storages, true);
}
}
private IStorage OpenHeaderPart1()
{
return Storage.Slice(0, 0x110);
}
private IStorage OpenHeaderPart2()
{
IStorage encStorage = Storage.Slice(0x110, 0xF0);
// The counter starts counting at 0x100, but the block at 0x100 isn't encrypted.
// Increase the counter by one and start decrypting at 0x110.
byte[] counter = new byte[0x10];
Array.Copy(Header.Counter, counter, 0x10);
Utilities.IncrementByteArray(counter);
return new CachedStorage(new Aes128CtrStorage(encStorage, Key, counter, true), 0x4000, 4, true);
}
public IStorage OpenKernel()
{
int offset = 0x200;
IStorage encStorage = Storage.Slice(offset, Header.SectionSizes[0]);
return new CachedStorage(new Aes128CtrStorage(encStorage, Key, Header.SectionCounters[0], true), 0x4000, 4, true);
}
public IStorage OpenIni1()
{
// Handle 8.0.0+ INI1 embedded within Kernel
// Todo: Figure out how to better deal with this once newer versions are released
if (Header.SectionSizes[1] == 0)
{
IStorage kernelStorage = OpenKernel();
var reader = new BinaryReader(kernelStorage.AsStream());
reader.BaseStream.Position = 0x168;
int embeddedIniOffset = (int)reader.ReadInt64();
reader.BaseStream.Position = embeddedIniOffset + 4;
int size = reader.ReadInt32();
return kernelStorage.Slice(embeddedIniOffset, size);
}
int offset = 0x200 + Header.SectionSizes[0];
IStorage encStorage = Storage.Slice(offset, Header.SectionSizes[1]);
return new CachedStorage(new Aes128CtrStorage(encStorage, Key, Header.SectionCounters[1], true), 0x4000, 4, true);
}
private int FindKeyGeneration(KeySet keySet, IStorage storage)
{
byte[] counter = new byte[0x10];
byte[] decBuffer = new byte[0x10];
storage.Read(0x100, counter).ThrowIfFailure();
for (int i = 0; i < 0x20; i++)
{
var dec = new Aes128CtrStorage(storage.Slice(0x100), keySet.Package2Keys[i].DataRo.ToArray(), counter,
false);
dec.Read(0x50, decBuffer).ThrowIfFailure();
if (BitConverter.ToUInt32(decBuffer, 0) == Pk21Magic)
{
return i;
}
}
throw new InvalidDataException("Failed to decrypt package2! Is the correct key present?");
}
}
public class Package2Header
{
public byte[] Signature { get; }
public byte[] Counter { get; }
public byte[][] SectionCounters { get; } = new byte[4][];
public int[] SectionSizes { get; } = new int[4];
public int[] SectionOffsets { get; } = new int[4];
public byte[][] SectionHashes { get; } = new byte[4][];
public string Magic { get; }
public int BaseOffset { get; }
public int VersionMax { get; }
public int VersionMin { get; }
public Validity SignatureValidity { get; }
public Package2Header(IStorage storage, KeySet keySet, int keyGeneration)
{
var reader = new BinaryReader(storage.AsStream());
byte[] key = keySet.Package2Keys[keyGeneration].DataRo.ToArray();
Signature = reader.ReadBytes(0x100);
byte[] sigData = reader.ReadBytes(0x100);
SignatureValidity = CryptoOld.Rsa2048PssVerify(sigData, Signature, keySet.Package2SigningKeyParams.Modulus);
reader.BaseStream.Position -= 0x100;
Counter = reader.ReadBytes(0x10);
Stream headerStream = new CachedStorage(new Aes128CtrStorage(storage.Slice(0x100), key, Counter, true), 0x4000, 4, true).AsStream();
headerStream.Position = 0x10;
reader = new BinaryReader(headerStream);
for (int i = 0; i < 4; i++)
{
SectionCounters[i] = reader.ReadBytes(0x10);
}
Magic = reader.ReadAscii(4);
BaseOffset = reader.ReadInt32();
reader.BaseStream.Position += 4;
VersionMax = reader.ReadByte();
VersionMin = reader.ReadByte();
reader.BaseStream.Position += 2;
for (int i = 0; i < 4; i++)
{
SectionSizes[i] = reader.ReadInt32();
}
for (int i = 0; i < 4; i++)
{
SectionOffsets[i] = reader.ReadInt32();
}
for (int i = 0; i < 4; i++)
{
SectionHashes[i] = reader.ReadBytes(0x20);
}
}
}
}