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;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using LibHac.IO.RomFs;
|
using LibHac.IO.RomFs;
|
||||||
|
@ -7,6 +8,9 @@ namespace LibHac.IO.NcaUtils
|
||||||
{
|
{
|
||||||
public class Nca : IDisposable
|
public class Nca : IDisposable
|
||||||
{
|
{
|
||||||
|
private const int HeaderSize = 0xc00;
|
||||||
|
private const int HeaderSectorSize = 0x200;
|
||||||
|
|
||||||
public NcaHeader Header { get; }
|
public NcaHeader Header { get; }
|
||||||
public string NcaId { get; set; }
|
public string NcaId { get; set; }
|
||||||
public string Filename { get; set; }
|
public string Filename { get; set; }
|
||||||
|
@ -334,9 +338,9 @@ namespace LibHac.IO.NcaUtils
|
||||||
return new NcaHeader(new BinaryReader(OpenHeaderStorage().AsStream()), Keyset);
|
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
|
// Encrypted portion continues until the first section
|
||||||
if (Sections.Any(x => x != null))
|
if (Sections.Any(x => x != null))
|
||||||
|
@ -344,7 +348,42 @@ namespace LibHac.IO.NcaUtils
|
||||||
size = Sections.Where(x => x != null).Min(x => x.Offset);
|
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)
|
private void DecryptKeyArea(Keyset keyset)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace LibHac.IO.NcaUtils
|
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[] Signature1; // RSA-PSS signature over header with fixed key.
|
||||||
public byte[] Signature2; // RSA-PSS signature over header with key in NPDM.
|
public byte[] Signature2; // RSA-PSS signature over header with key in NPDM.
|
||||||
public string Magic;
|
public string Magic;
|
||||||
|
public int Version;
|
||||||
public DistributionType Distribution; // System vs gamecard.
|
public DistributionType Distribution; // System vs gamecard.
|
||||||
public ContentType ContentType;
|
public ContentType ContentType;
|
||||||
public byte CryptoType; // Which keyblob (field 1)
|
public byte CryptoType; // Which keyblob (field 1)
|
||||||
|
@ -33,7 +35,12 @@ namespace LibHac.IO.NcaUtils
|
||||||
Signature1 = reader.ReadBytes(0x100);
|
Signature1 = reader.ReadBytes(0x100);
|
||||||
Signature2 = reader.ReadBytes(0x100);
|
Signature2 = reader.ReadBytes(0x100);
|
||||||
Magic = reader.ReadAscii(4);
|
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;
|
reader.BaseStream.Position -= 4;
|
||||||
SignatureData = reader.ReadBytes(0x200);
|
SignatureData = reader.ReadBytes(0x200);
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace hactoolnet
|
||||||
new CliOption("section1dir", 1, (o, a) => o.SectionOutDir[1] = a[0]),
|
new CliOption("section1dir", 1, (o, a) => o.SectionOutDir[1] = a[0]),
|
||||||
new CliOption("section2dir", 1, (o, a) => o.SectionOutDir[2] = 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("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("exefs", 1, (o, a) => o.ExefsOut = a[0]),
|
||||||
new CliOption("exefsdir", 1, (o, a) => o.ExefsOutDir = a[0]),
|
new CliOption("exefsdir", 1, (o, a) => o.ExefsOutDir = a[0]),
|
||||||
new CliOption("romfs", 1, (o, a) => o.RomfsOut = 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(" --titlekeys <file> Load title keys from an external file.");
|
||||||
sb.AppendLine("NCA options:");
|
sb.AppendLine("NCA options:");
|
||||||
sb.AppendLine(" --plaintext <file> Specify file path for saving a decrypted copy of the NCA.");
|
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(" --section0 <file> Specify Section 0 file path.");
|
||||||
sb.AppendLine(" --section1 <file> Specify Section 1 file path.");
|
sb.AppendLine(" --section1 <file> Specify Section 1 file path.");
|
||||||
sb.AppendLine(" --section2 <file> Specify Section 2 file path.");
|
sb.AppendLine(" --section2 <file> Specify Section 2 file path.");
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace hactoolnet
|
||||||
public string ConsoleKeyFile;
|
public string ConsoleKeyFile;
|
||||||
public string[] SectionOut = new string[4];
|
public string[] SectionOut = new string[4];
|
||||||
public string[] SectionOutDir = new string[4];
|
public string[] SectionOutDir = new string[4];
|
||||||
|
public string HeaderOut;
|
||||||
public string ExefsOut;
|
public string ExefsOut;
|
||||||
public string ExefsOutDir;
|
public string ExefsOutDir;
|
||||||
public string RomfsOut;
|
public string RomfsOut;
|
||||||
|
|
|
@ -15,6 +15,15 @@ namespace hactoolnet
|
||||||
using (IStorage file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
using (IStorage file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
||||||
{
|
{
|
||||||
var nca = new Nca(ctx.Keyset, file, false);
|
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.ValidateMasterHashes();
|
||||||
nca.ParseNpdm();
|
nca.ParseNpdm();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue