diff --git a/src/LibHac/FsSystem/StorageExtensions.cs b/src/LibHac/FsSystem/StorageExtensions.cs index 6cb0d58e..3b929a70 100644 --- a/src/LibHac/FsSystem/StorageExtensions.cs +++ b/src/LibHac/FsSystem/StorageExtensions.cs @@ -10,32 +10,6 @@ namespace LibHac.FsSystem { 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) { storage.GetSize(out long length).ThrowIfFailure(); diff --git a/src/LibHac/Kip.cs b/src/LibHac/Kip.cs deleted file mode 100644 index 5d06fe72..00000000 --- a/src/LibHac/Kip.cs +++ /dev/null @@ -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(Storage.Slice(offset)); - - Kips[i] = new KipReader(); - Kips[i].Initialize(in sharedStorage).ThrowIfFailure(); - - offset += Kips[i].GetFileSize(); - } - } - } -} diff --git a/src/LibHac/Nacp.cs b/src/LibHac/Nacp.cs deleted file mode 100644 index f71d6b62..00000000 --- a/src/LibHac/Nacp.cs +++ /dev/null @@ -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 PlayLogQueryableApplicationId { get; } = new List(); - 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 - } -} diff --git a/src/LibHac/Nso.cs b/src/LibHac/Nso.cs deleted file mode 100644 index fa379b72..00000000 --- a/src/LibHac/Nso.cs +++ /dev/null @@ -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(); - } - } - } -} diff --git a/src/LibHac/Package1.cs b/src/LibHac/Package1.cs deleted file mode 100644 index da8d9468..00000000 --- a/src/LibHac/Package1.cs +++ /dev/null @@ -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; - } -} diff --git a/src/LibHac/Package2.cs b/src/LibHac/Package2.cs deleted file mode 100644 index 00e683cc..00000000 --- a/src/LibHac/Package2.cs +++ /dev/null @@ -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); - } - } - } -}