mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add NCA2 support
This commit is contained in:
parent
56c4554d81
commit
c267826dd1
5 changed files with 63 additions and 5 deletions
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LibHac.IO.RomFs;
|
||||
|
@ -7,6 +8,9 @@ namespace LibHac.IO.NcaUtils
|
|||
{
|
||||
public class Nca : IDisposable
|
||||
{
|
||||
private const int HeaderSize = 0xc00;
|
||||
private const int HeaderSectorSize = 0x200;
|
||||
|
||||
public NcaHeader Header { get; }
|
||||
public string NcaId { get; set; }
|
||||
public string Filename { get; set; }
|
||||
|
@ -334,9 +338,9 @@ namespace LibHac.IO.NcaUtils
|
|||
return new NcaHeader(new BinaryReader(OpenHeaderStorage().AsStream()), Keyset);
|
||||
}
|
||||
|
||||
private CachedStorage OpenHeaderStorage()
|
||||
public IStorage OpenHeaderStorage()
|
||||
{
|
||||
long size = 0xc00;
|
||||
long size = HeaderSize;
|
||||
|
||||
// Encrypted portion continues until the first section
|
||||
if (Sections.Any(x => x != null))
|
||||
|
@ -344,7 +348,42 @@ namespace LibHac.IO.NcaUtils
|
|||
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);
|
||||
IStorage header = new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(0, size), Keyset.HeaderKey, HeaderSectorSize, true), 1, true);
|
||||
int version = ReadHeaderVersion(header);
|
||||
|
||||
if (version == 2)
|
||||
{
|
||||
header = OpenNca2Header(size);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private int ReadHeaderVersion(IStorage header)
|
||||
{
|
||||
if (Header != null)
|
||||
{
|
||||
return Header.Version;
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<byte> buf = stackalloc byte[1];
|
||||
header.Read(buf, 0x203);
|
||||
return buf[0] - '0';
|
||||
}
|
||||
}
|
||||
|
||||
private IStorage OpenNca2Header(long size)
|
||||
{
|
||||
var sources = new List<IStorage>();
|
||||
sources.Add(new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(0, 0x400), Keyset.HeaderKey, HeaderSectorSize, true), 1, true));
|
||||
|
||||
for (int i = 0x400; i < size; i += HeaderSectorSize)
|
||||
{
|
||||
sources.Add(new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(i, HeaderSectorSize), Keyset.HeaderKey, HeaderSectorSize, true), 1, true));
|
||||
}
|
||||
|
||||
return new ConcatenationStorage(sources, true);
|
||||
}
|
||||
|
||||
private void DecryptKeyArea(Keyset keyset)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace LibHac.IO.NcaUtils
|
||||
{
|
||||
|
@ -7,6 +8,7 @@ namespace LibHac.IO.NcaUtils
|
|||
public byte[] Signature1; // RSA-PSS signature over header with fixed key.
|
||||
public byte[] Signature2; // RSA-PSS signature over header with key in NPDM.
|
||||
public string Magic;
|
||||
public int Version;
|
||||
public DistributionType Distribution; // System vs gamecard.
|
||||
public ContentType ContentType;
|
||||
public byte CryptoType; // Which keyblob (field 1)
|
||||
|
@ -33,7 +35,12 @@ namespace LibHac.IO.NcaUtils
|
|||
Signature1 = reader.ReadBytes(0x100);
|
||||
Signature2 = reader.ReadBytes(0x100);
|
||||
Magic = reader.ReadAscii(4);
|
||||
if (Magic != "NCA3") throw new InvalidDataException("Not an NCA3 file");
|
||||
|
||||
if (!Magic.StartsWith("NCA") || Magic[3] < '0' || Magic[3] > '9')
|
||||
throw new InvalidDataException("Unable to decrypt NCA header, or the file is not an NCA file.");
|
||||
|
||||
Version = Magic[3] - '0';
|
||||
if (Version != 2 && Version != 3) throw new NotSupportedException($"NCA version {Version} is not supported.");
|
||||
|
||||
reader.BaseStream.Position -= 4;
|
||||
SignatureData = reader.ReadBytes(0x200);
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace hactoolnet
|
|||
new CliOption("section1dir", 1, (o, a) => o.SectionOutDir[1] = a[0]),
|
||||
new CliOption("section2dir", 1, (o, a) => o.SectionOutDir[2] = a[0]),
|
||||
new CliOption("section3dir", 1, (o, a) => o.SectionOutDir[3] = a[0]),
|
||||
new CliOption("header", 1, (o, a) => o.HeaderOut = a[0]),
|
||||
new CliOption("exefs", 1, (o, a) => o.ExefsOut = a[0]),
|
||||
new CliOption("exefsdir", 1, (o, a) => o.ExefsOutDir = a[0]),
|
||||
new CliOption("romfs", 1, (o, a) => o.RomfsOut = a[0]),
|
||||
|
@ -169,6 +170,7 @@ namespace hactoolnet
|
|||
sb.AppendLine(" --titlekeys <file> Load title keys from an external file.");
|
||||
sb.AppendLine("NCA options:");
|
||||
sb.AppendLine(" --plaintext <file> Specify file path for saving a decrypted copy of the NCA.");
|
||||
sb.AppendLine(" --header <file> Specify Header file path.");
|
||||
sb.AppendLine(" --section0 <file> Specify Section 0 file path.");
|
||||
sb.AppendLine(" --section1 <file> Specify Section 1 file path.");
|
||||
sb.AppendLine(" --section2 <file> Specify Section 2 file path.");
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace hactoolnet
|
|||
public string ConsoleKeyFile;
|
||||
public string[] SectionOut = new string[4];
|
||||
public string[] SectionOutDir = new string[4];
|
||||
public string HeaderOut;
|
||||
public string ExefsOut;
|
||||
public string ExefsOutDir;
|
||||
public string RomfsOut;
|
||||
|
|
|
@ -15,6 +15,15 @@ namespace hactoolnet
|
|||
using (IStorage file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
||||
{
|
||||
var nca = new Nca(ctx.Keyset, file, false);
|
||||
|
||||
if (ctx.Options.HeaderOut != null)
|
||||
{
|
||||
using (var outHeader = new FileStream(ctx.Options.HeaderOut, FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
nca.OpenHeaderStorage().Slice(0, 0xc00).CopyToStream(outHeader);
|
||||
}
|
||||
}
|
||||
|
||||
nca.ValidateMasterHashes();
|
||||
nca.ParseNpdm();
|
||||
|
||||
|
|
Loading…
Reference in a new issue