From 7f016f875bd99c7aa9a4c5a0059eaab7d110a075 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 28 Aug 2018 13:22:19 -0500 Subject: [PATCH] Fix regression caused by decrypting multiple AES blocks at a time --- hactoolnet/Program.cs | 29 +++++----- libhac/Aes128CtrStream.cs | 6 ++ libhac/Nca.cs | 63 ++++++++++----------- libhac/XTSSharp/RandomAccessSectorStream.cs | 2 +- libhac/XTSSharp/SectorStream.cs | 2 +- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/hactoolnet/Program.cs b/hactoolnet/Program.cs index 6c192c9d..1b6a7609 100644 --- a/hactoolnet/Program.cs +++ b/hactoolnet/Program.cs @@ -379,29 +379,26 @@ namespace hactoolnet private static void ProcessRomFs(Context ctx, Romfs romfs) { - using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read)) + if (ctx.Options.ListRomFs) { - if (ctx.Options.ListRomFs) + foreach (var romfsFile in romfs.Files) { - foreach (var romfsFile in romfs.Files) - { - ctx.Logger.LogMessage(romfsFile.FullPath); - } + ctx.Logger.LogMessage(romfsFile.FullPath); } + } - if (ctx.Options.RomfsOut != null) + if (ctx.Options.RomfsOut != null) + { + using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite)) { - using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite)) - { - var romfsStream = romfs.OpenRawStream(); - romfsStream.CopyStream(outFile, romfsStream.Length, ctx.Logger); - } + var romfsStream = romfs.OpenRawStream(); + romfsStream.CopyStream(outFile, romfsStream.Length, ctx.Logger); } + } - if (ctx.Options.RomfsOutDir != null) - { - romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger); - } + if (ctx.Options.RomfsOutDir != null) + { + romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger); } } diff --git a/libhac/Aes128CtrStream.cs b/libhac/Aes128CtrStream.cs index 3c169eef..bf45e0c6 100644 --- a/libhac/Aes128CtrStream.cs +++ b/libhac/Aes128CtrStream.cs @@ -134,5 +134,11 @@ namespace libhac return _decryptor.TransformBlock(_tempBuffer, 0, bytesRead, buffer, offset); } + + protected override void ValidateSizeMultiple(long value) + { + if (value % 0x10 != 0) + throw new ArgumentException($"Value needs to be a multiple of {SectorSize}"); + } } } diff --git a/libhac/Nca.cs b/libhac/Nca.cs index a42edbbe..a8f10b08 100644 --- a/libhac/Nca.cs +++ b/libhac/Nca.cs @@ -87,62 +87,59 @@ namespace libhac long offset = sect.Offset; long size = sect.Size; - if (!raw) - { - switch (sect.Header.Type) - { - case SectionType.Pfs0: - offset = sect.Offset + sect.Pfs0.Superblock.Pfs0Offset; - size = sect.Pfs0.Superblock.Pfs0Size; - break; - case SectionType.Romfs: - offset = sect.Offset + sect.Header.Romfs.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1].LogicalOffset; - size = sect.Header.Romfs.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1].HashDataSize; - break; - case SectionType.Bktr: - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - var sectionStream = StreamSource.CreateStream(offset, size); + Stream rawStream = StreamSource.CreateStream(offset, size); switch (sect.Header.CryptType) { case SectionCryptType.None: - return sectionStream; + break; case SectionCryptType.XTS: break; case SectionCryptType.CTR: - return new RandomAccessSectorStream(new Aes128CtrStream(sectionStream, DecryptedKeys[2], offset, sect.Header.Ctr), false); + rawStream = new RandomAccessSectorStream(new Aes128CtrStream(rawStream, DecryptedKeys[2], offset, sect.Header.Ctr), false); + break; case SectionCryptType.BKTR: - var patchStream = new RandomAccessSectorStream( - new BktrCryptoStream(sectionStream, DecryptedKeys[2], 0, size, offset, sect.Header.Ctr, sect.Header.Bktr), + rawStream = new RandomAccessSectorStream( + new BktrCryptoStream(rawStream, DecryptedKeys[2], 0, size, offset, sect.Header.Ctr, sect.Header.Bktr), false); if (BaseNca == null) { - return patchStream; + return rawStream; } else { - var dataLevel = sect.Header.Bktr.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1]; - var baseSect = BaseNca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs); if (baseSect == null) throw new InvalidDataException("Base NCA has no RomFS section"); var baseStream = BaseNca.OpenSection(baseSect.SectionNum, true); - var virtStreamRaw = new Bktr(patchStream, baseStream, sect); - - if (raw) return virtStreamRaw; - var virtStream = new SubStream(virtStreamRaw, dataLevel.LogicalOffset, dataLevel.HashDataSize); - return virtStream; + rawStream = new Bktr(rawStream, baseStream, sect); } + break; default: throw new ArgumentOutOfRangeException(); } - return sectionStream; + if (raw) return rawStream; + + switch (sect.Header.Type) + { + case SectionType.Pfs0: + offset = sect.Pfs0.Superblock.Pfs0Offset; + size = sect.Pfs0.Superblock.Pfs0Size; + break; + case SectionType.Romfs: + offset = sect.Header.Romfs.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1].LogicalOffset; + size = sect.Header.Romfs.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1].HashDataSize; + break; + case SectionType.Bktr: + offset = sect.Header.Bktr.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1].LogicalOffset; + size = sect.Header.Bktr.IvfcHeader.LevelHeaders[Romfs.IvfcMaxLevel - 1].HashDataSize; + break; + default: + throw new ArgumentOutOfRangeException(); + } + return new SubStream(rawStream, offset, size); + } public void SetBaseNca(Nca baseNca) => BaseNca = baseNca; diff --git a/libhac/XTSSharp/RandomAccessSectorStream.cs b/libhac/XTSSharp/RandomAccessSectorStream.cs index 8384266a..b01f6c9c 100644 --- a/libhac/XTSSharp/RandomAccessSectorStream.cs +++ b/libhac/XTSSharp/RandomAccessSectorStream.cs @@ -334,7 +334,7 @@ namespace libhac.XTSSharp _bufferDirty = false; _currentBufferSize = sector.Length; CacheHits++; - _s.Position += _bufferSize; + _s.Position += _currentBufferSize; return; } } diff --git a/libhac/XTSSharp/SectorStream.cs b/libhac/XTSSharp/SectorStream.cs index 4a95809f..1b450a60 100644 --- a/libhac/XTSSharp/SectorStream.cs +++ b/libhac/XTSSharp/SectorStream.cs @@ -145,7 +145,7 @@ namespace libhac.XTSSharp /// Validates that the size is a multiple of the sector size /// // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local - private void ValidateSizeMultiple(long value) + protected virtual void ValidateSizeMultiple(long value) { if (value % SectorSize != 0) throw new ArgumentException(string.Format("Value needs to be a multiple of {0}", SectorSize));