LibHac/hactoolnet/Program.cs
Alex Barney 3d50085e22
Use Storage throughout the library instead of Stream (#18)
*Create an IStorage interface and Storage abstract class to use instead of Stream

* Improve AES-XTS performance by ~16x

* Double AES-CTR performance: 800 MB/s -> 1600 MB/s on a 6700K

* Add AES-XTS tests

* Add AES benchmark and AES-CTR writing

* Add support for a hashed FAT in save files

* Add option to export decrypted NCA

* Allow opening decrypted package1 and package2

* Make sure romfs disposal can cascade all the way down

* Validate NCA, NPDM and package2 signatures
2018-11-18 23:20:34 -05:00

155 lines
5.1 KiB
C#

using System;
using System.IO;
using System.Text;
using LibHac;
namespace hactoolnet
{
public static class Program
{
public static void Main(string[] args)
{
try
{
Run(args);
}
catch (MissingKeyException ex)
{
string name = ex.Type == KeyType.Title ? $"Title key for rights ID {ex.Name}" : ex.Name;
Console.WriteLine($"\nERROR: {ex.Message}\nA required key is missing.\nKey name: {name}\n");
}
catch (Exception ex)
{
Console.WriteLine($"\nERROR: {ex.Message}\n");
Console.WriteLine("Additional information:");
Console.WriteLine(ex.GetType().FullName);
Console.WriteLine(ex.StackTrace);
}
}
private static void Run(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
var ctx = new Context();
ctx.Options = CliParser.Parse(args);
if (ctx.Options == null) return;
using (var logger = new ProgressBar())
{
ctx.Logger = logger;
OpenKeyset(ctx);
if (ctx.Options.RunCustom)
{
CustomTask(ctx);
return;
}
RunTask(ctx);
}
}
private static void RunTask(Context ctx)
{
switch (ctx.Options.InFileType)
{
case FileType.Nca:
ProcessNca.Process(ctx);
break;
case FileType.Pfs0:
case FileType.Nsp:
ProcessNsp.Process(ctx);
break;
case FileType.Romfs:
ProcessRomfs.Process(ctx);
break;
case FileType.Nax0:
break;
case FileType.SwitchFs:
ProcessSwitchFs.Process(ctx);
break;
case FileType.Save:
ProcessSave.Process(ctx);
break;
case FileType.Xci:
ProcessXci.Process(ctx);
break;
case FileType.Keygen:
ProcessKeygen(ctx);
break;
case FileType.Pk11:
ProcessPackage.ProcessPk11(ctx);
break;
case FileType.Pk21:
ProcessPackage.ProcessPk21(ctx);
break;
case FileType.Kip1:
ProcessKip.ProcessKip1(ctx);
break;
case FileType.Ini1:
ProcessKip.ProcessIni1(ctx);
break;
case FileType.Bench:
ProcessBench.Process(ctx);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private static void OpenKeyset(Context ctx)
{
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string homeKeyFile = Path.Combine(home, ".switch", "prod.keys");
string homeTitleKeyFile = Path.Combine(home, ".switch", "title.keys");
string homeConsoleKeyFile = Path.Combine(home, ".switch", "console.keys");
string keyFile = ctx.Options.Keyfile;
string titleKeyFile = ctx.Options.TitleKeyFile;
string consoleKeyFile = ctx.Options.ConsoleKeyFile;
if (keyFile == null && File.Exists(homeKeyFile))
{
keyFile = homeKeyFile;
}
if (titleKeyFile == null && File.Exists(homeTitleKeyFile))
{
titleKeyFile = homeTitleKeyFile;
}
if (consoleKeyFile == null && File.Exists(homeConsoleKeyFile))
{
consoleKeyFile = homeConsoleKeyFile;
}
ctx.Keyset = ExternalKeys.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile, ctx.Logger);
if (ctx.Options.SdSeed != null)
{
ctx.Keyset.SetSdSeed(ctx.Options.SdSeed.ToBytes());
}
if (ctx.Options.InFileType == FileType.Keygen && ctx.Options.OutDir != null)
{
string dir = ctx.Options.OutDir;
Directory.CreateDirectory(dir);
File.WriteAllText(Path.Combine(dir, "prod.keys"), ExternalKeys.PrintCommonKeys(ctx.Keyset));
File.WriteAllText(Path.Combine(dir, "console.keys"), ExternalKeys.PrintUniqueKeys(ctx.Keyset));
File.WriteAllText(Path.Combine(dir, "title.keys"), ExternalKeys.PrintTitleKeys(ctx.Keyset));
}
}
private static void ProcessKeygen(Context ctx)
{
Console.WriteLine(ExternalKeys.PrintCommonKeys(ctx.Keyset));
}
// For running random stuff
// ReSharper disable once UnusedParameter.Local
private static void CustomTask(Context ctx)
{
}
}
}