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