hactoolnet: add nax0 support

This commit is contained in:
Alex Barney 2019-12-27 15:11:36 -07:00
parent d68062c8b4
commit 496250f094
4 changed files with 87 additions and 1 deletions

View file

@ -12,7 +12,7 @@ namespace LibHac.FsSystem
private int BlockSize { get; }
private OpenMode Mode { get; }
private AesXtsFileHeader Header { get; }
public AesXtsFileHeader Header { get; }
private IStorage BaseStorage { get; }
internal const int HeaderLength = 0x4000;

View file

@ -272,6 +272,10 @@ namespace hactoolnet
sb.AppendLine(" --listfiles List files in save file.");
sb.AppendLine(" --repack <dir> Replaces the contents of the save data with the specified directory.");
sb.AppendLine(" --replacefile <filename in save> <file> Replaces a file in the save data");
sb.AppendLine("NAX0 options:");
sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption.");
sb.AppendLine(" --sdpath <path> Set relative path for NAX0 key derivation (ex: /registered/000000FF/cafebabecafebabecafebabecafebabe.nca).");
sb.AppendLine(" --plaintext Specify file path to save decrypted contents.");
sb.AppendLine("NDV0 (Delta) options:");
sb.AppendLine(" Input delta patch can be a delta NCA file or a delta fragment file.");
sb.AppendLine(" --basefile <file> Specify base file path.");

View file

@ -0,0 +1,81 @@
using System;
using System.Linq;
using System.Text;
using LibHac;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using static hactoolnet.Print;
namespace hactoolnet
{
internal static class ProcessNax0
{
public static void Process(Context ctx)
{
byte[][] keys = ctx.Keyset.SdCardKeys;
using var baseFile = new LocalFile(ctx.Options.InFile, OpenMode.Read);
AesXtsFile xtsFile = null;
int contentType = 0;
for (int i = 0; i < keys.Length; i++)
{
byte[] kekSource = keys[i].AsSpan(0, 0x10).ToArray();
byte[] validationKey = keys[i].AsSpan(0x10, 0x10).ToArray();
try
{
xtsFile = new AesXtsFile(OpenMode.Read, baseFile, ctx.Options.SdPath, kekSource, validationKey, 0x4000);
contentType = i;
break;
}
catch (HorizonResultException) { }
}
if (xtsFile == null)
{
ctx.Logger.LogMessage($"Error: NAX0 key derivation failed. Check SD card seed and relative path.");
return;
}
ctx.Logger.LogMessage(xtsFile.Print(contentType));
if (string.IsNullOrWhiteSpace(ctx.Options.PlaintextOut)) return;
xtsFile.AsStorage().WriteAllBytes(ctx.Options.PlaintextOut, ctx.Logger);
ctx.Logger.LogMessage($"Saved Decrypted NAX0 Content to {ctx.Options.PlaintextOut}...");
}
private static string Print(this AesXtsFile xtsFile, int contentType)
{
int colLen = 36;
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("NAX0:");
AesXtsFileHeader header = xtsFile.Header;
uint magic = header.Magic;
PrintItem(sb, colLen, " Magic:", Util.GetUtf8String(SpanHelpers.AsReadOnlyByteSpan(ref magic)));
PrintItem(sb, colLen, " Content Type:", GetContentType(contentType));
PrintItem(sb, colLen, " Content Size:", $"{header.Size:x12}");
PrintItem(sb, colLen, " Header HMAC:", header.Signature);
PrintItem(sb, colLen, " Encrypted Keys:", header.EncryptedKey1.Concat(header.EncryptedKey2).ToArray());
PrintItem(sb, colLen, " Decrypted Keys:", header.DecryptedKey1.Concat(header.DecryptedKey2).ToArray());
return sb.ToString();
}
private static string GetContentType(int type) => type switch
{
0 => "Save",
1 => "NCA",
2 => "Custom storage",
_ => "Unknown"
};
}
}

View file

@ -126,6 +126,7 @@ namespace hactoolnet
ProcessFsBuild.ProcessRomFs(ctx);
break;
case FileType.Nax0:
ProcessNax0.Process(ctx);
break;
case FileType.SwitchFs:
ProcessSwitchFs.Process(ctx);