mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
hactoolnet: add nax0 support
This commit is contained in:
parent
d68062c8b4
commit
496250f094
4 changed files with 87 additions and 1 deletions
|
@ -12,7 +12,7 @@ namespace LibHac.FsSystem
|
||||||
private int BlockSize { get; }
|
private int BlockSize { get; }
|
||||||
private OpenMode Mode { get; }
|
private OpenMode Mode { get; }
|
||||||
|
|
||||||
private AesXtsFileHeader Header { get; }
|
public AesXtsFileHeader Header { get; }
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
|
|
||||||
internal const int HeaderLength = 0x4000;
|
internal const int HeaderLength = 0x4000;
|
||||||
|
|
|
@ -272,6 +272,10 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" --listfiles List files in save file.");
|
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(" --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(" --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("NDV0 (Delta) options:");
|
||||||
sb.AppendLine(" Input delta patch can be a delta NCA file or a delta fragment file.");
|
sb.AppendLine(" Input delta patch can be a delta NCA file or a delta fragment file.");
|
||||||
sb.AppendLine(" --basefile <file> Specify base file path.");
|
sb.AppendLine(" --basefile <file> Specify base file path.");
|
||||||
|
|
81
src/hactoolnet/ProcessNax0.cs
Normal file
81
src/hactoolnet/ProcessNax0.cs
Normal 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"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -126,6 +126,7 @@ namespace hactoolnet
|
||||||
ProcessFsBuild.ProcessRomFs(ctx);
|
ProcessFsBuild.ProcessRomFs(ctx);
|
||||||
break;
|
break;
|
||||||
case FileType.Nax0:
|
case FileType.Nax0:
|
||||||
|
ProcessNax0.Process(ctx);
|
||||||
break;
|
break;
|
||||||
case FileType.SwitchFs:
|
case FileType.SwitchFs:
|
||||||
ProcessSwitchFs.Process(ctx);
|
ProcessSwitchFs.Process(ctx);
|
||||||
|
|
Loading…
Reference in a new issue