mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Get rid of old code
This commit is contained in:
parent
3e4dcd9466
commit
8861f25bc7
6 changed files with 41 additions and 358 deletions
|
@ -1,53 +0,0 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using DiscUtils.Fat;
|
||||
|
||||
namespace LibHac.Nand
|
||||
{
|
||||
public class NandPartition : IFileSystemOld
|
||||
{
|
||||
public FatFileSystem Fs { get; }
|
||||
|
||||
public NandPartition(FatFileSystem fileSystem)
|
||||
{
|
||||
Fs = fileSystem;
|
||||
}
|
||||
|
||||
public bool FileExists(string path)
|
||||
{
|
||||
return Fs.FileExists(path);
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string path)
|
||||
{
|
||||
return Fs.DirectoryExists(path);
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path, FileMode mode)
|
||||
{
|
||||
return Fs.OpenFile(path, mode);
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path, FileMode mode, FileAccess access)
|
||||
{
|
||||
return Fs.OpenFile(path, mode, access);
|
||||
}
|
||||
|
||||
public string[] GetFileSystemEntries(string path, string searchPattern)
|
||||
{
|
||||
return Fs.GetFileSystemEntries(path, searchPattern);
|
||||
}
|
||||
|
||||
public string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
string[] files = Fs.GetFiles(path, searchPattern, searchOption);
|
||||
string[] dirs = Fs.GetDirectories(path, searchPattern, searchOption);
|
||||
return files.Concat(dirs).ToArray();
|
||||
}
|
||||
|
||||
public string GetFullPath(string path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
public class FileSystem : IFileSystemOld
|
||||
{
|
||||
public string Root { get; }
|
||||
|
||||
public FileSystem(string rootDir)
|
||||
{
|
||||
Root = Path.GetFullPath(rootDir);
|
||||
}
|
||||
|
||||
public bool FileExists(string path)
|
||||
{
|
||||
return File.Exists(Path.Combine(Root, path));
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string path)
|
||||
{
|
||||
return Directory.Exists(Path.Combine(Root, path));
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path, FileMode mode)
|
||||
{
|
||||
return new FileStream(Path.Combine(Root, path), mode);
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path, FileMode mode, FileAccess access)
|
||||
{
|
||||
return new FileStream(Path.Combine(Root, path), mode, access);
|
||||
}
|
||||
|
||||
public string[] GetFileSystemEntries(string path, string searchPattern)
|
||||
{
|
||||
return Directory.GetFileSystemEntries(Path.Combine(Root, path), searchPattern);
|
||||
}
|
||||
|
||||
public string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
//return Directory.GetFileSystemEntries(Path.Combine(Root, path), searchPattern, searchOption);
|
||||
var result = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
result.AddRange(GetFileSystemEntries(Path.Combine(Root, path), searchPattern));
|
||||
}
|
||||
catch (UnauthorizedAccessException) { /* Skip this directory */ }
|
||||
|
||||
if (searchOption == SearchOption.TopDirectoryOnly)
|
||||
return result.ToArray();
|
||||
|
||||
string[] searchDirectories = Directory.GetDirectories(Path.Combine(Root, path));
|
||||
foreach (string search in searchDirectories)
|
||||
{
|
||||
try
|
||||
{
|
||||
result.AddRange(GetFileSystemEntries(search, searchPattern, searchOption));
|
||||
}
|
||||
catch (UnauthorizedAccessException) { /* Skip this result */ }
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public string GetFullPath(string path)
|
||||
{
|
||||
return Path.Combine(Root, path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
public interface IFileSystemOld
|
||||
{
|
||||
bool FileExists(string path);
|
||||
bool DirectoryExists(string path);
|
||||
Stream OpenFile(string path, FileMode mode);
|
||||
Stream OpenFile(string path, FileMode mode, FileAccess access);
|
||||
string[] GetFileSystemEntries(string path, string searchPattern);
|
||||
string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption);
|
||||
string GetFullPath(string path);
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using LibHac.IO;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
public class Nax0 : IDisposable
|
||||
{
|
||||
private const int SectorSize = 0x4000;
|
||||
|
||||
public byte[] Hmac { get; private set; }
|
||||
public byte[][] EncKeys { get; } = Util.CreateJaggedArray<byte[][]>(2, 0x10);
|
||||
public byte[][] Keys { get; } = Util.CreateJaggedArray<byte[][]>(2, 0x10);
|
||||
public byte[] Key { get; } = new byte[0x20];
|
||||
public long Length { get; private set; }
|
||||
public IStorage BaseStorage { get; }
|
||||
private bool LeaveOpen { get; }
|
||||
|
||||
public Nax0(Keyset keyset, IStorage storage, string sdPath, bool leaveOpen)
|
||||
{
|
||||
LeaveOpen = leaveOpen;
|
||||
ReadHeader(storage.AsStream());
|
||||
DeriveKeys(keyset, sdPath, storage);
|
||||
|
||||
BaseStorage = new CachedStorage(new Aes128XtsStorage(storage.Slice(SectorSize), Key, SectorSize, leaveOpen), 4, leaveOpen);
|
||||
}
|
||||
|
||||
private void ReadHeader(Stream stream)
|
||||
{
|
||||
var reader = new BinaryReader(stream);
|
||||
|
||||
Hmac = reader.ReadBytes(0x20);
|
||||
string magic = reader.ReadAscii(4);
|
||||
reader.BaseStream.Position += 4;
|
||||
if (magic != "NAX0") throw new InvalidDataException("Not an NAX0 file");
|
||||
EncKeys[0] = reader.ReadBytes(0x10);
|
||||
EncKeys[1] = reader.ReadBytes(0x10);
|
||||
Length = reader.ReadInt64();
|
||||
}
|
||||
|
||||
private void DeriveKeys(Keyset keyset, string sdPath, IStorage storage)
|
||||
{
|
||||
var validationHashKey = new byte[0x60];
|
||||
storage.Read(validationHashKey, 0x20);
|
||||
|
||||
// Try both the NCA and save key sources and pick the one that works
|
||||
for (int k = 0; k < 2; k++)
|
||||
{
|
||||
var naxSpecificKeys = Util.CreateJaggedArray<byte[][]>(2, 0x10);
|
||||
var hashKey = new byte[0x10];
|
||||
Array.Copy(keyset.SdCardKeys[k], hashKey, 0x10);
|
||||
|
||||
// Use the sd path to generate the kek for this NAX0
|
||||
var hash = new HMACSHA256(hashKey);
|
||||
byte[] sdPathBytes = Encoding.ASCII.GetBytes(sdPath);
|
||||
byte[] checksum = hash.ComputeHash(sdPathBytes, 0, sdPathBytes.Length);
|
||||
Array.Copy(checksum, 0, naxSpecificKeys[0], 0, 0x10);
|
||||
Array.Copy(checksum, 0x10, naxSpecificKeys[1], 0, 0x10);
|
||||
|
||||
// Decrypt this NAX0's keys
|
||||
Crypto.DecryptEcb(naxSpecificKeys[0], EncKeys[0], Keys[0], 0x10);
|
||||
Crypto.DecryptEcb(naxSpecificKeys[1], EncKeys[1], Keys[1], 0x10);
|
||||
Array.Copy(Keys[0], 0, Key, 0, 0x10);
|
||||
Array.Copy(Keys[1], 0, Key, 0x10, 0x10);
|
||||
|
||||
// Copy the decrypted keys into the NAX0 header and use that for the HMAC key
|
||||
// for validating that the keys are correct
|
||||
Array.Copy(Keys[0], 0, validationHashKey, 8, 0x10);
|
||||
Array.Copy(Keys[1], 0, validationHashKey, 0x18, 0x10);
|
||||
|
||||
var validationHash = new HMACSHA256(validationHashKey);
|
||||
byte[] validationMac = validationHash.ComputeHash(keyset.SdCardKeys[k], 0x10, 0x10);
|
||||
|
||||
if (Util.ArraysEqual(Hmac, validationMac))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("NAX0 key derivation failed.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!LeaveOpen)
|
||||
{
|
||||
BaseStorage?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using LibHac.IO;
|
||||
using LibHac.IO.Save;
|
||||
|
||||
|
@ -12,44 +11,23 @@ namespace LibHac
|
|||
public class SwitchFs : IDisposable
|
||||
{
|
||||
public Keyset Keyset { get; }
|
||||
public IFileSystemOld Fs { get; }
|
||||
public string ContentsDir { get; }
|
||||
public string SaveDir { get; }
|
||||
public IAttributeFileSystem BaseFs { get; }
|
||||
public AesXtsFileSystem Fs { get; }
|
||||
|
||||
public Dictionary<string, Nca> Ncas { get; } = new Dictionary<string, Nca>(StringComparer.OrdinalIgnoreCase);
|
||||
public Dictionary<string, SaveDataFileSystem> Saves { get; } = new Dictionary<string, SaveDataFileSystem>(StringComparer.OrdinalIgnoreCase);
|
||||
public Dictionary<ulong, Title> Titles { get; } = new Dictionary<ulong, Title>();
|
||||
public Dictionary<ulong, Application> Applications { get; } = new Dictionary<ulong, Application>();
|
||||
|
||||
public SwitchFs(Keyset keyset, IFileSystemOld fs)
|
||||
public SwitchFs(Keyset keyset, IAttributeFileSystem fs)
|
||||
{
|
||||
Fs = fs;
|
||||
BaseFs = fs;
|
||||
Keyset = keyset;
|
||||
|
||||
if (fs.DirectoryExists("Nintendo"))
|
||||
{
|
||||
ContentsDir = fs.GetFullPath(Path.Combine("Nintendo", "Contents"));
|
||||
SaveDir = fs.GetFullPath(Path.Combine("Nintendo", "save"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fs.DirectoryExists("Contents"))
|
||||
{
|
||||
ContentsDir = fs.GetFullPath("Contents");
|
||||
}
|
||||
var concatFs = new ConcatenationFileSystem(BaseFs);
|
||||
Fs = new AesXtsFileSystem(concatFs, keyset.SdCardKeys[1], 0x4000);
|
||||
|
||||
if (fs.DirectoryExists("save"))
|
||||
{
|
||||
SaveDir = fs.GetFullPath("save");
|
||||
}
|
||||
}
|
||||
|
||||
if (ContentsDir == null)
|
||||
{
|
||||
throw new DirectoryNotFoundException("Could not find \"Contents\" directory");
|
||||
}
|
||||
|
||||
OpenAllSaves();
|
||||
// OpenAllSaves();
|
||||
OpenAllNcas();
|
||||
ReadTitles();
|
||||
ReadControls();
|
||||
|
@ -58,88 +36,70 @@ namespace LibHac
|
|||
|
||||
private void OpenAllNcas()
|
||||
{
|
||||
string[] files = Fs.GetFileSystemEntries(ContentsDir, "*.nca", SearchOption.AllDirectories);
|
||||
IEnumerable<DirectoryEntry> files = Fs.OpenDirectory("/", OpenDirectoryMode.All).EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories);
|
||||
|
||||
foreach (string file in files)
|
||||
foreach (DirectoryEntry fileEntry in files)
|
||||
{
|
||||
Nca nca = null;
|
||||
try
|
||||
{
|
||||
bool isNax0;
|
||||
IStorage storage = OpenSplitNcaStorage(Fs, file);
|
||||
if (storage == null) continue;
|
||||
var storage = new FileStorage(Fs.OpenFile(fileEntry.FullPath, OpenMode.Read));
|
||||
|
||||
using (var reader = new BinaryReader(storage.AsStream(), Encoding.Default, true))
|
||||
{
|
||||
reader.BaseStream.Position = 0x20;
|
||||
isNax0 = reader.ReadUInt32() == 0x3058414E; // NAX0
|
||||
reader.BaseStream.Position = 0;
|
||||
}
|
||||
nca = new Nca(Keyset, storage, false);
|
||||
|
||||
if (isNax0)
|
||||
{
|
||||
string sdPath = "/" + Util.GetRelativePath(file, ContentsDir).Replace('\\', '/');
|
||||
var nax0 = new Nax0(Keyset, storage, sdPath, false);
|
||||
nca = new Nca(Keyset, nax0.BaseStorage, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nca = new Nca(Keyset, storage, false);
|
||||
}
|
||||
|
||||
nca.NcaId = Path.GetFileNameWithoutExtension(file);
|
||||
nca.NcaId = Path.GetFileNameWithoutExtension(fileEntry.Name);
|
||||
string extension = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca";
|
||||
nca.Filename = nca.NcaId + extension;
|
||||
}
|
||||
catch (MissingKeyException ex)
|
||||
{
|
||||
if (ex.Name == null)
|
||||
{ Console.WriteLine($"{ex.Message} File:\n{file}"); }
|
||||
{ Console.WriteLine($"{ex.Message} File:\n{fileEntry}"); }
|
||||
else
|
||||
{
|
||||
string name = ex.Type == KeyType.Title ? $"Title key for rights ID {ex.Name}" : ex.Name;
|
||||
Console.WriteLine($"{ex.Message}\nKey: {name}\nFile: {file}");
|
||||
Console.WriteLine($"{ex.Message}\nKey: {name}\nFile: {fileEntry}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"{ex.Message} File: {file}");
|
||||
Console.WriteLine($"{ex.Message} File: {fileEntry}");
|
||||
}
|
||||
|
||||
if (nca?.NcaId != null) Ncas.Add(nca.NcaId, nca);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenAllSaves()
|
||||
{
|
||||
if (SaveDir == null) return;
|
||||
//private void OpenAllSaves()
|
||||
//{
|
||||
// if (SaveDir == null) return;
|
||||
|
||||
string[] files = Fs.GetFileSystemEntries(SaveDir, "*");
|
||||
// string[] files = Fs.GetFileSystemEntries(SaveDir, "*");
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
SaveDataFileSystem save = null;
|
||||
string saveName = Path.GetFileNameWithoutExtension(file);
|
||||
// foreach (string file in files)
|
||||
// {
|
||||
// SaveDataFileSystem save = null;
|
||||
// string saveName = Path.GetFileNameWithoutExtension(file);
|
||||
|
||||
try
|
||||
{
|
||||
IStorage storage = Fs.OpenFile(file, FileMode.Open).AsStorage();
|
||||
// try
|
||||
// {
|
||||
// IStorage storage = Fs.OpenFile(file, FileMode.Open).AsStorage();
|
||||
|
||||
string sdPath = "/" + Util.GetRelativePath(file, SaveDir).Replace('\\', '/');
|
||||
var nax0 = new Nax0(Keyset, storage, sdPath, false);
|
||||
save = new SaveDataFileSystem(Keyset, nax0.BaseStorage, IntegrityCheckLevel.None, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"{ex.Message} File: {file}");
|
||||
}
|
||||
// string sdPath = "/" + Util.GetRelativePath(file, SaveDir).Replace('\\', '/');
|
||||
// var nax0 = new Nax0(Keyset, storage, sdPath, false);
|
||||
// save = new SaveDataFileSystem(Keyset, nax0.BaseStorage, IntegrityCheckLevel.None, true);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Console.WriteLine($"{ex.Message} File: {file}");
|
||||
// }
|
||||
|
||||
if (save != null && saveName != null)
|
||||
{
|
||||
Saves[saveName] = save;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (save != null && saveName != null)
|
||||
// {
|
||||
// Saves[saveName] = save;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
private void ReadTitles()
|
||||
{
|
||||
|
@ -232,49 +192,6 @@ namespace LibHac
|
|||
}
|
||||
}
|
||||
|
||||
internal static IStorage OpenSplitNcaStorage(IFileSystemOld fs, string path)
|
||||
{
|
||||
var files = new List<string>();
|
||||
var storages = new List<IStorage>();
|
||||
|
||||
if (fs.DirectoryExists(path))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
string partName = Path.Combine(path, $"{files.Count:D2}");
|
||||
if (!fs.FileExists(partName)) break;
|
||||
|
||||
files.Add(partName);
|
||||
}
|
||||
}
|
||||
else if (fs.FileExists(path))
|
||||
{
|
||||
if (Path.GetFileName(path) != "00")
|
||||
{
|
||||
return fs.OpenFile(path, FileMode.Open, FileAccess.Read).AsStorage();
|
||||
}
|
||||
files.Add(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileNotFoundException("Could not find the input file or directory");
|
||||
}
|
||||
|
||||
if (files.Count == 1)
|
||||
{
|
||||
return fs.OpenFile(files[0], FileMode.Open, FileAccess.Read).AsStorage();
|
||||
}
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
storages.Add(fs.OpenFile(file, FileMode.Open, FileAccess.Read).AsStorage());
|
||||
}
|
||||
|
||||
if (storages.Count == 0) return null; //todo
|
||||
|
||||
return new ConcatenationStorage(storages, true);
|
||||
}
|
||||
|
||||
private void DisposeNcas()
|
||||
{
|
||||
foreach (Nca nca in Ncas.Values)
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace hactoolnet
|
|||
{
|
||||
public static void Process(Context ctx)
|
||||
{
|
||||
var switchFs = new SwitchFs(ctx.Keyset, new FileSystem(ctx.Options.InFile));
|
||||
var switchFs = new SwitchFs(ctx.Keyset, new LocalFileSystem($"{ctx.Options.InFile}/Nintendo/Contents"));
|
||||
|
||||
if (ctx.Options.ListNcas)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue