mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Fix opening decrypted NCAs
Fixes an issue where the decrypted NCA could be incorrect if the first section didn't start at offset 0x4000
This commit is contained in:
parent
a1bdadb89b
commit
56c4554d81
3 changed files with 82 additions and 13 deletions
63
src/LibHac/IO/ConcatenationStorageBuilder.cs
Normal file
63
src/LibHac/IO/ConcatenationStorageBuilder.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibHac.IO
|
||||
{
|
||||
public class ConcatenationStorageBuilder
|
||||
{
|
||||
private List<ConcatenationStorageSegment> Segments { get; }
|
||||
|
||||
public ConcatenationStorageBuilder()
|
||||
{
|
||||
Segments = new List<ConcatenationStorageSegment>();
|
||||
}
|
||||
|
||||
public ConcatenationStorageBuilder(IEnumerable<ConcatenationStorageSegment> segments)
|
||||
{
|
||||
Segments = segments.ToList();
|
||||
}
|
||||
|
||||
public void Add(IStorage storage, long offset)
|
||||
{
|
||||
Segments.Add(new ConcatenationStorageSegment(storage, offset));
|
||||
}
|
||||
|
||||
public ConcatenationStorage Build()
|
||||
{
|
||||
List<ConcatenationStorageSegment> segments = Segments.OrderBy(x => x.Offset).ToList();
|
||||
var sources = new List<IStorage>();
|
||||
|
||||
long offset = 0;
|
||||
|
||||
foreach (ConcatenationStorageSegment segment in segments)
|
||||
{
|
||||
long paddingNeeded = segment.Offset - offset;
|
||||
|
||||
if (paddingNeeded < 0) throw new InvalidDataException("Builder has segments that overlap.");
|
||||
|
||||
if (paddingNeeded > 0)
|
||||
{
|
||||
sources.Add(new NullStorage(paddingNeeded));
|
||||
}
|
||||
|
||||
sources.Add(segment.Storage);
|
||||
offset = segment.Offset + segment.Storage.Length;
|
||||
}
|
||||
|
||||
return new ConcatenationStorage(sources, true);
|
||||
}
|
||||
}
|
||||
|
||||
public class ConcatenationStorageSegment
|
||||
{
|
||||
public IStorage Storage { get; }
|
||||
public long Offset { get; }
|
||||
|
||||
public ConcatenationStorageSegment(IStorage storage, long offset)
|
||||
{
|
||||
Storage = storage;
|
||||
Offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LibHac.IO.RomFs;
|
||||
|
@ -314,14 +313,15 @@ namespace LibHac.IO.NcaUtils
|
|||
|
||||
public IStorage OpenDecryptedNca()
|
||||
{
|
||||
var list = new List<IStorage> { OpenHeaderStorage() };
|
||||
var builder = new ConcatenationStorageBuilder();
|
||||
builder.Add(OpenHeaderStorage(), 0);
|
||||
|
||||
foreach (NcaSection section in Sections.Where(x => x != null).OrderBy(x => x.Offset))
|
||||
foreach (NcaSection section in Sections.Where(x => x != null))
|
||||
{
|
||||
list.Add(OpenRawStorage(section.SectionNum));
|
||||
builder.Add(OpenRawStorage(section.SectionNum), section.Offset);
|
||||
}
|
||||
|
||||
return new ConcatenationStorage(list, true);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
private NcaHeader DecryptHeader()
|
||||
|
@ -336,11 +336,13 @@ namespace LibHac.IO.NcaUtils
|
|||
|
||||
private CachedStorage OpenHeaderStorage()
|
||||
{
|
||||
int size = 0x4000;
|
||||
long size = 0xc00;
|
||||
|
||||
// Support reading headers that are only 0xC00 bytes long, but still return
|
||||
// the entire header if available.
|
||||
if (BaseStorage.Length >= 0xC00 && BaseStorage.Length < 0x4000) size = 0xC00;
|
||||
// Encrypted portion continues until the first section
|
||||
if (Sections.Any(x => x != null))
|
||||
{
|
||||
size = Sections.Where(x => x != null).Min(x => x.Offset);
|
||||
}
|
||||
|
||||
return new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(0, size), Keyset.HeaderKey, 0x200, true), 1, true);
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ namespace LibHac.IO.NcaUtils
|
|||
{
|
||||
public static class NcaExtensions
|
||||
{
|
||||
public static IStorage OpenStorage(this Nca nca, int index, IntegrityCheckLevel integrityCheckLevel, bool openRaw)
|
||||
public static IStorage OpenStorage(this Nca nca, int index, IntegrityCheckLevel integrityCheckLevel,
|
||||
bool openRaw)
|
||||
{
|
||||
if (openRaw) return nca.OpenRawStorage(index);
|
||||
return nca.OpenStorage(index, integrityCheckLevel);
|
||||
}
|
||||
|
||||
public static IStorage OpenStorage(this Nca nca, NcaSectionType type, IntegrityCheckLevel integrityCheckLevel, bool openRaw)
|
||||
public static IStorage OpenStorage(this Nca nca, NcaSectionType type, IntegrityCheckLevel integrityCheckLevel,
|
||||
bool openRaw)
|
||||
{
|
||||
if (openRaw) return nca.OpenRawStorage(type);
|
||||
return nca.OpenStorage(type, integrityCheckLevel);
|
||||
|
@ -23,7 +25,8 @@ namespace LibHac.IO.NcaUtils
|
|||
.WriteAllBytes(filename, logger);
|
||||
}
|
||||
|
||||
public static void ExtractSection(this Nca nca, int index, string outputDir, IntegrityCheckLevel integrityCheckLevel = IntegrityCheckLevel.None, IProgressReport logger = null)
|
||||
public static void ExtractSection(this Nca nca, int index, string outputDir,
|
||||
IntegrityCheckLevel integrityCheckLevel = IntegrityCheckLevel.None, IProgressReport logger = null)
|
||||
{
|
||||
if (index < 0 || index > 3) throw new IndexOutOfRangeException();
|
||||
if (!nca.SectionIsDecryptable(index)) return;
|
||||
|
@ -55,7 +58,8 @@ namespace LibHac.IO.NcaUtils
|
|||
NcaHashType hashType = sect.Header.HashType;
|
||||
if (hashType != NcaHashType.Sha256 && hashType != NcaHashType.Ivfc) return Validity.Unchecked;
|
||||
|
||||
var stream = nca.OpenStorage(index, IntegrityCheckLevel.IgnoreOnInvalid, false) as HierarchicalIntegrityVerificationStorage;
|
||||
var stream = nca.OpenStorage(index, IntegrityCheckLevel.IgnoreOnInvalid, false)
|
||||
as HierarchicalIntegrityVerificationStorage;
|
||||
if (stream == null) return Validity.Unchecked;
|
||||
|
||||
if (!quiet) logger?.LogMessage($"Verifying section {index}...");
|
||||
|
|
Loading…
Reference in a new issue