Add romfs superblock validation

This commit is contained in:
Alex Barney 2018-06-28 16:55:36 -05:00
parent 95ee755774
commit 3e6d2a7761
4 changed files with 88 additions and 9 deletions

View file

@ -30,7 +30,7 @@ namespace hactoolnet
static void ReadNca()
{
var keyset = ExternalKeys.ReadKeyFile("keys.txt", "titlekeys.txt");
using (var file = new FileStream("bf8b106a2e68df3c3f1694636423585a.nca", FileMode.Open, FileAccess.Read))
using (var file = new FileStream("671d172e7993ee033d1be25ee76378e3.nca", FileMode.Open, FileAccess.Read))
{
var nca = new Nca(keyset, file, false);
var romfs = nca.OpenSection(0, false);
@ -107,7 +107,7 @@ namespace hactoolnet
{
Console.WriteLine($" {nca.HasRightsId} {nca.NcaId} {nca.Header.ContentType}");
foreach (var sect in nca.Sections)
foreach (var sect in nca.Sections.Where(x => x != null))
{
Console.WriteLine($" {sect.SectionNum} {sect.Type} {sect.Header.CryptType} {sect.SuperblockHashValidity}");
}

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using libhac.XTSSharp;
@ -17,7 +16,7 @@ namespace libhac
public Stream Stream { get; private set; }
private bool KeepOpen { get; }
public List<NcaSection> Sections = new List<NcaSection>();
public NcaSection[] Sections { get; } = new NcaSection[4];
public Nca(Keyset keyset, Stream stream, bool keepOpen)
{
@ -47,14 +46,14 @@ namespace libhac
{
var section = ParseSection(i);
if (section == null) continue;
Sections.Add(section);
Sections[i] = section;
ValidateSuperblockHash(i);
}
}
public Stream OpenSection(int index, bool raw)
{
if (index >= Sections.Count) throw new ArgumentOutOfRangeException(nameof(index));
if (Sections[index] == null) throw new ArgumentOutOfRangeException(nameof(index));
var sect = Sections[index];
long offset = sect.Offset;
@ -83,7 +82,7 @@ namespace libhac
switch (sect.Header.CryptType)
{
case SectionCryptType.None:
break;
return new SubStream(Stream, offset, size);
case SectionCryptType.XTS:
break;
case SectionCryptType.CTR:
@ -144,7 +143,7 @@ namespace libhac
private void ValidateSuperblockHash(int index)
{
if (index >= Sections.Count) throw new ArgumentOutOfRangeException(nameof(index));
if (Sections[index] == null) throw new ArgumentOutOfRangeException(nameof(index));
var sect = Sections[index];
var stream = OpenSection(index, true);
@ -164,6 +163,10 @@ namespace libhac
size = pfs0.HashTableSize;
break;
case SectionType.Romfs:
var ivfc = sect.Header.Romfs.IvfcHeader;
expected = ivfc.MasterHash;
offset = (long)ivfc.LevelHeaders[0].LogicalOffset;
size = 1 << (int)ivfc.LevelHeaders[0].BlockSize;
break;
case SectionType.Bktr:
break;

View file

@ -101,6 +101,7 @@ namespace libhac
public NcaFsHeader(BinaryReader reader)
{
var start = reader.BaseStream.Position;
Field0 = reader.ReadByte();
Field1 = reader.ReadByte();
PartitionType = (SectionPartitionType)reader.ReadByte();
@ -128,7 +129,7 @@ namespace libhac
}
Ctr = reader.ReadBytes(8).Reverse().ToArray();
reader.BaseStream.Position += 184;
reader.BaseStream.Position = start + 512;
}
}

75
libhac/Substream.cs Normal file
View file

@ -0,0 +1,75 @@
using System;
using System.IO;
namespace libhac
{
public class SubStream : Stream
{
private Stream BaseStream { get; }
private long Offset { get; }
public SubStream(Stream baseStream, long offset, long length)
{
if (baseStream == null) throw new ArgumentNullException(nameof(baseStream));
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
if (!baseStream.CanSeek || !baseStream.CanRead) throw new NotSupportedException();
BaseStream = baseStream;
Length = length;
Offset = offset;
baseStream.Seek(offset, SeekOrigin.Current);
}
public override int Read(byte[] buffer, int offset, int count)
{
long remaining = Length - Position;
if (remaining <= 0) return 0;
if (remaining < count) count = (int)remaining;
return BaseStream.Read(buffer, offset, count);
}
public override long Length { get; }
public override bool CanRead => BaseStream.CanRead;
public override bool CanWrite => BaseStream.CanWrite;
public override bool CanSeek => BaseStream.CanSeek;
public override long Position
{
get => BaseStream.Position - Offset;
set
{
if (value < 0 || value >= Length)
throw new ArgumentOutOfRangeException(nameof(value));
BaseStream.Position = Offset + value;
}
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
Position = offset;
break;
case SeekOrigin.Current:
Position += offset;
break;
case SeekOrigin.End:
Position = Length - offset;
break;
}
return Position;
}
public override void SetLength(long value) => throw new NotSupportedException();
public override void Flush() => BaseStream.Flush();
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
}