diff --git a/libhac/Program.cs b/hactoolnet/Program.cs
similarity index 64%
rename from libhac/Program.cs
rename to hactoolnet/Program.cs
index 027df219..02166d93 100644
--- a/libhac/Program.cs
+++ b/hactoolnet/Program.cs
@@ -1,8 +1,9 @@
using System.IO;
+using libhac;
-namespace libhac
+namespace hactoolnet
{
- class Program
+ public static class Program
{
static void Main(string[] args)
{
@@ -10,11 +11,14 @@ namespace libhac
keyset.SetSdSeed(args[1].ToBytes());
var nax0 = new Nax0(keyset, args[2], args[3]);
+ var nca = new Nca(keyset, nax0.Stream);
+
using (var output = new FileStream(args[4], FileMode.Create))
using (var progress = new ProgressBar())
{
+ progress.LogMessage($"Title ID: {nca.TitleId:X8}");
progress.LogMessage($"Writing {args[4]}");
- Util.CopyStream(nax0.Stream, output, nax0.Stream.Length, progress);
+ nax0.Stream.CopyStream(output, nax0.Stream.Length, progress);
}
}
}
diff --git a/hactoolnet/hactoolnet.csproj b/hactoolnet/hactoolnet.csproj
new file mode 100644
index 00000000..e15691c0
--- /dev/null
+++ b/hactoolnet/hactoolnet.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.1
+
+
+
+
+
+
+
diff --git a/libhac.sln b/libhac.sln
index 46d847d6..4178fde8 100644
--- a/libhac.sln
+++ b/libhac.sln
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2026
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libhac", "libhac\libhac.csproj", "{FFCA6C31-D9D4-4ED8-A06D-0CC6B94422B8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libhac", "libhac\libhac.csproj", "{FFCA6C31-D9D4-4ED8-A06D-0CC6B94422B8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hactoolnet", "hactoolnet\hactoolnet.csproj", "{B1633A64-125F-40A3-9E15-654B4DE5FD98}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +17,10 @@ Global
{FFCA6C31-D9D4-4ED8-A06D-0CC6B94422B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFCA6C31-D9D4-4ED8-A06D-0CC6B94422B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFCA6C31-D9D4-4ED8-A06D-0CC6B94422B8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1633A64-125F-40A3-9E15-654B4DE5FD98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1633A64-125F-40A3-9E15-654B4DE5FD98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1633A64-125F-40A3-9E15-654B4DE5FD98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1633A64-125F-40A3-9E15-654B4DE5FD98}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/libhac/Nca.cs b/libhac/Nca.cs
new file mode 100644
index 00000000..aa5a0f72
--- /dev/null
+++ b/libhac/Nca.cs
@@ -0,0 +1,53 @@
+using System.IO;
+using libhac.XTSSharp;
+
+namespace libhac
+{
+ public class Nca
+ {
+ public byte[] Signature1 { get; set; } // RSA-PSS signature over header with fixed key.
+ public byte[] Signature2 { get; set; } // RSA-PSS signature over header with key in NPDM.
+ public string Magic { get; set; }
+ public byte Distribution { get; set; } // System vs gamecard.
+ public byte ContentType { get; set; }
+ public byte CryptoType { get; set; } // Which keyblob (field 1)
+ public byte KaekInd { get; set; } // Which kaek index?
+ public ulong NcaSize { get; set; } // Entire archive size.
+ public ulong TitleId { get; set; }
+ public uint SdkVersion { get; set; } // What SDK was this built with?
+ public byte CryptoType2 { get; set; } // Which keyblob (field 2)
+ public byte[] RightsId { get; set; }
+
+ public Nca(Keyset keyset, Stream stream)
+ {
+ ReadHeader(keyset, stream);
+ }
+
+ private void ReadHeader(Keyset keyset, Stream stream)
+ {
+ stream.Position = 0;
+ var xts = XtsAes128.Create(keyset.header_key);
+ var header = new RandomAccessSectorStream(new XtsSectorStream(stream, xts, 0x200));
+ var reader = new BinaryReader(header);
+
+ Signature1 = reader.ReadBytes(0x100);
+ Signature2 = reader.ReadBytes(0x100);
+ Magic = reader.ReadAscii(4);
+ if (Magic != "NCA3") throw new InvalidDataException("Not an NCA3 file");
+ Distribution = reader.ReadByte();
+ ContentType = reader.ReadByte();
+ CryptoType = reader.ReadByte();
+ KaekInd = reader.ReadByte();
+ NcaSize = reader.ReadUInt64();
+ TitleId = reader.ReadUInt64();
+ header.Position += 4;
+
+ SdkVersion = reader.ReadUInt32();
+ CryptoType2 = reader.ReadByte();
+ header.Position += 0xF;
+
+ RightsId = reader.ReadBytes(0x10);
+ header.Close();
+ }
+ }
+}
diff --git a/libhac/Util.cs b/libhac/Util.cs
index 3581219b..e566c856 100644
--- a/libhac/Util.cs
+++ b/libhac/Util.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Text;
namespace libhac
{
@@ -73,6 +74,12 @@ namespace libhac
}
}
+ public static string ReadAscii(this BinaryReader reader, int size)
+ {
+ return Encoding.ASCII.GetString(reader.ReadBytes(size), 0, size);
+ }
+
+
private static int HexToInt(char c)
{
switch (c)
diff --git a/libhac/libhac.csproj b/libhac/libhac.csproj
index 8cd3d078..7a9f5707 100644
--- a/libhac/libhac.csproj
+++ b/libhac/libhac.csproj
@@ -1,7 +1,7 @@
- Exe
+ Library
netcoreapp2.1
7.3