mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add package1 support. Update usage
This commit is contained in:
parent
49a1f0b5a4
commit
8022d193df
6 changed files with 158 additions and 4 deletions
|
@ -49,6 +49,8 @@ namespace LibHac
|
||||||
|
|
||||||
_decryptor = new Aes128CtrTransform(key, counter ?? new byte[0x10], CryptChunkSize);
|
_decryptor = new Aes128CtrTransform(key, counter ?? new byte[0x10], CryptChunkSize);
|
||||||
Counter = _decryptor.Counter;
|
Counter = _decryptor.Counter;
|
||||||
|
|
||||||
|
baseStream.Position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -76,6 +78,8 @@ namespace LibHac
|
||||||
_decryptor = new Aes128CtrTransform(key, initialCounter, CryptChunkSize);
|
_decryptor = new Aes128CtrTransform(key, initialCounter, CryptChunkSize);
|
||||||
Counter = _decryptor.Counter;
|
Counter = _decryptor.Counter;
|
||||||
UpdateCounter(_counterOffset + base.Position);
|
UpdateCounter(_counterOffset + base.Position);
|
||||||
|
|
||||||
|
baseStream.Position = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCounter(long offset)
|
private void UpdateCounter(long offset)
|
||||||
|
|
113
LibHac/Package1.cs
Normal file
113
LibHac/Package1.cs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using LibHac.Streams;
|
||||||
|
|
||||||
|
namespace LibHac
|
||||||
|
{
|
||||||
|
public class Package1
|
||||||
|
{
|
||||||
|
private const uint Pk11Magic = 0x31314B50; // PK11
|
||||||
|
|
||||||
|
public byte[] BuildHash { get; }
|
||||||
|
public string BuildDate { get; }
|
||||||
|
public int Field1E { get; }
|
||||||
|
public int Pk11Size { get; }
|
||||||
|
public byte[] Counter { get; }
|
||||||
|
public int KeyRevision { get; }
|
||||||
|
public Pk11 Pk11 { get; }
|
||||||
|
|
||||||
|
private SharedStreamSource StreamSource { get; }
|
||||||
|
|
||||||
|
public Package1(Keyset keyset, Stream stream)
|
||||||
|
{
|
||||||
|
StreamSource = new SharedStreamSource(stream);
|
||||||
|
var reader = new BinaryReader(stream);
|
||||||
|
|
||||||
|
BuildHash = reader.ReadBytes(0x10);
|
||||||
|
BuildDate = reader.ReadAscii(0xE);
|
||||||
|
Field1E = reader.ReadUInt16();
|
||||||
|
|
||||||
|
reader.BaseStream.Position = 0x3FE0;
|
||||||
|
Pk11Size = reader.ReadInt32();
|
||||||
|
|
||||||
|
reader.BaseStream.Position += 0xC;
|
||||||
|
Counter = reader.ReadBytes(0x10);
|
||||||
|
|
||||||
|
// Try decrypting the PK11 blob with all known package1 keys
|
||||||
|
Stream encStream = StreamSource.CreateStream(0x4000, Pk11Size);
|
||||||
|
var decBuffer = new byte[0x10];
|
||||||
|
|
||||||
|
for (int i = 0; i < 0x20; i++)
|
||||||
|
{
|
||||||
|
var dec = new Aes128CtrStream(encStream, keyset.package1_keys[i], Counter);
|
||||||
|
dec.Read(decBuffer, 0, 0x10);
|
||||||
|
|
||||||
|
if (BitConverter.ToUInt32(decBuffer, 0) == Pk11Magic)
|
||||||
|
{
|
||||||
|
KeyRevision = i;
|
||||||
|
|
||||||
|
dec.Position = 0;
|
||||||
|
Pk11 = new Pk11(new RandomAccessSectorStream(dec));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidDataException("Failed to decrypt PK11! Is the correct key present?");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream OpenPackage1Ldr() => StreamSource.CreateStream(0, 0x4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Pk11
|
||||||
|
{
|
||||||
|
private const int DataOffset = 0x20;
|
||||||
|
|
||||||
|
public string Magic { get; }
|
||||||
|
public int[] SectionSizes { get; } = new int[3];
|
||||||
|
public int[] SectionOffsets { get; } = new int[3];
|
||||||
|
|
||||||
|
private SharedStreamSource StreamSource { get; }
|
||||||
|
|
||||||
|
public Pk11(Stream stream)
|
||||||
|
{
|
||||||
|
StreamSource = new SharedStreamSource(stream);
|
||||||
|
var reader = new BinaryReader(stream);
|
||||||
|
|
||||||
|
Magic = reader.ReadAscii(4);
|
||||||
|
SectionSizes[0] = reader.ReadInt32();
|
||||||
|
SectionOffsets[0] = reader.ReadInt32();
|
||||||
|
|
||||||
|
reader.BaseStream.Position += 4;
|
||||||
|
SectionSizes[1] = reader.ReadInt32();
|
||||||
|
SectionOffsets[1] = reader.ReadInt32();
|
||||||
|
SectionSizes[2] = reader.ReadInt32();
|
||||||
|
SectionOffsets[2] = reader.ReadInt32();
|
||||||
|
|
||||||
|
SectionOffsets[0] = DataOffset;
|
||||||
|
SectionOffsets[1] = SectionOffsets[0] + SectionSizes[0];
|
||||||
|
SectionOffsets[2] = SectionOffsets[1] + SectionSizes[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream OpenSection(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index > 2)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index), "Section index must be one of: 0, 1, 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
return StreamSource.CreateStream(SectionOffsets[index], SectionSizes[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream OpenDecryptedPk11() => StreamSource.CreateStream();
|
||||||
|
|
||||||
|
public Stream OpenWarmboot() => OpenSection(GetWarmbootSection());
|
||||||
|
public Stream OpenNxBootloader() => OpenSection(GetNxBootloaderSection());
|
||||||
|
public Stream OpenSecureMonitor() => OpenSection(GetSecureMonitorSection());
|
||||||
|
|
||||||
|
// todo: Handle the old layout from before 2.0.0
|
||||||
|
private int GetWarmbootSection() => 0;
|
||||||
|
private int GetNxBootloaderSection() => 1;
|
||||||
|
private int GetSecureMonitorSection() => 2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ Options:
|
||||||
-r, --raw Keep raw data, don't unpack.
|
-r, --raw Keep raw data, don't unpack.
|
||||||
-y, --verify Verify hashes.
|
-y, --verify Verify hashes.
|
||||||
-k, --keyset Load keys from an external file.
|
-k, --keyset Load keys from an external file.
|
||||||
-t, --intype=type Specify input file type [nca, xci, switchfs, save, keygen]
|
-t, --intype=type Specify input file type [nca, xci, romfs, pk11, switchfs, save, keygen]
|
||||||
--titlekeys <file> Load title keys from an external file.
|
--titlekeys <file> Load title keys from an external file.
|
||||||
NCA options:
|
NCA options:
|
||||||
--section0 <file> Specify Section 0 file path.
|
--section0 <file> Specify Section 0 file path.
|
||||||
|
@ -34,6 +34,9 @@ NCA options:
|
||||||
--romfsdir <dir> Specify RomFS directory path.
|
--romfsdir <dir> Specify RomFS directory path.
|
||||||
--listromfs List files in RomFS.
|
--listromfs List files in RomFS.
|
||||||
--basenca Set Base NCA to use with update partitions.
|
--basenca Set Base NCA to use with update partitions.
|
||||||
|
RomFS options:
|
||||||
|
--romfsdir <dir> Specify RomFS directory path.
|
||||||
|
--listromfs List files in RomFS.
|
||||||
XCI options:
|
XCI options:
|
||||||
--rootdir <dir> Specify root XCI directory path.
|
--rootdir <dir> Specify root XCI directory path.
|
||||||
--updatedir <dir> Specify update XCI directory path.
|
--updatedir <dir> Specify update XCI directory path.
|
||||||
|
@ -46,6 +49,8 @@ XCI options:
|
||||||
--romfs <file> Specify main RomFS file path.
|
--romfs <file> Specify main RomFS file path.
|
||||||
--romfsdir <dir> Specify main RomFS directory path.
|
--romfsdir <dir> Specify main RomFS directory path.
|
||||||
--nspout <file> Specify file for the created NSP.
|
--nspout <file> Specify file for the created NSP.
|
||||||
|
Package1 options:
|
||||||
|
--outdir <dir> Specify Package1 directory path.
|
||||||
Switch FS options:
|
Switch FS options:
|
||||||
--sdseed <seed> Set console unique seed for SD card NAX0 encryption.
|
--sdseed <seed> Set console unique seed for SD card NAX0 encryption.
|
||||||
--listapps List application info.
|
--listapps List application info.
|
||||||
|
|
|
@ -146,7 +146,7 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" -r, --raw Keep raw data, don\'t unpack.");
|
sb.AppendLine(" -r, --raw Keep raw data, don\'t unpack.");
|
||||||
sb.AppendLine(" -y, --verify Verify hashes.");
|
sb.AppendLine(" -y, --verify Verify hashes.");
|
||||||
sb.AppendLine(" -k, --keyset Load keys from an external file.");
|
sb.AppendLine(" -k, --keyset Load keys from an external file.");
|
||||||
sb.AppendLine(" -t, --intype=type Specify input file type [nca, xci, switchfs, save, keygen]");
|
sb.AppendLine(" -t, --intype=type Specify input file type [nca, xci, romfs, pk11, switchfs, save, keygen]");
|
||||||
sb.AppendLine(" --titlekeys <file> Load title keys from an external file.");
|
sb.AppendLine(" --titlekeys <file> Load title keys from an external file.");
|
||||||
sb.AppendLine("NCA options:");
|
sb.AppendLine("NCA options:");
|
||||||
sb.AppendLine(" --section0 <file> Specify Section 0 file path.");
|
sb.AppendLine(" --section0 <file> Specify Section 0 file path.");
|
||||||
|
@ -163,6 +163,9 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" --romfsdir <dir> Specify RomFS directory path.");
|
sb.AppendLine(" --romfsdir <dir> Specify RomFS directory path.");
|
||||||
sb.AppendLine(" --listromfs List files in RomFS.");
|
sb.AppendLine(" --listromfs List files in RomFS.");
|
||||||
sb.AppendLine(" --basenca Set Base NCA to use with update partitions.");
|
sb.AppendLine(" --basenca Set Base NCA to use with update partitions.");
|
||||||
|
sb.AppendLine("RomFS options:");
|
||||||
|
sb.AppendLine(" --romfsdir <dir> Specify RomFS directory path.");
|
||||||
|
sb.AppendLine(" --listromfs List files in RomFS.");
|
||||||
sb.AppendLine("XCI options:");
|
sb.AppendLine("XCI options:");
|
||||||
sb.AppendLine(" --rootdir <dir> Specify root XCI directory path.");
|
sb.AppendLine(" --rootdir <dir> Specify root XCI directory path.");
|
||||||
sb.AppendLine(" --updatedir <dir> Specify update XCI directory path.");
|
sb.AppendLine(" --updatedir <dir> Specify update XCI directory path.");
|
||||||
|
@ -175,6 +178,8 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" --romfs <file> Specify main RomFS file path.");
|
sb.AppendLine(" --romfs <file> Specify main RomFS file path.");
|
||||||
sb.AppendLine(" --romfsdir <dir> Specify main RomFS directory path.");
|
sb.AppendLine(" --romfsdir <dir> Specify main RomFS directory path.");
|
||||||
sb.AppendLine(" --nspout <file> Specify file for the created NSP.");
|
sb.AppendLine(" --nspout <file> Specify file for the created NSP.");
|
||||||
|
sb.AppendLine("Package1 options:");
|
||||||
|
sb.AppendLine(" --outdir <dir> Specify Package1 directory path.");
|
||||||
sb.AppendLine("Switch FS options:");
|
sb.AppendLine("Switch FS options:");
|
||||||
sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption.");
|
sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption.");
|
||||||
sb.AppendLine(" --listapps List application info.");
|
sb.AppendLine(" --listapps List application info.");
|
||||||
|
@ -190,7 +195,6 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" --outdir <dir> Specify directory path to save contents to.");
|
sb.AppendLine(" --outdir <dir> Specify directory path to save contents to.");
|
||||||
sb.AppendLine(" --debugoutdir <dir> Specify directory path to save intermediate data to for debugging.");
|
sb.AppendLine(" --debugoutdir <dir> Specify directory path to save intermediate data to for debugging.");
|
||||||
|
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ namespace hactoolnet
|
||||||
Xci,
|
Xci,
|
||||||
SwitchFs,
|
SwitchFs,
|
||||||
Save,
|
Save,
|
||||||
Keygen
|
Keygen,
|
||||||
|
Pk11
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Context
|
internal class Context
|
||||||
|
|
|
@ -52,6 +52,9 @@ namespace hactoolnet
|
||||||
case FileType.Keygen:
|
case FileType.Keygen:
|
||||||
ProcessKeygen(ctx);
|
ProcessKeygen(ctx);
|
||||||
break;
|
break;
|
||||||
|
case FileType.Pk11:
|
||||||
|
ProcessPk11(ctx);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
@ -509,6 +512,30 @@ namespace hactoolnet
|
||||||
Console.WriteLine(ExternalKeys.PrintKeys(ctx.Keyset));
|
Console.WriteLine(ExternalKeys.PrintKeys(ctx.Keyset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ProcessPk11(Context ctx)
|
||||||
|
{
|
||||||
|
using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
var package1 = new Package1(ctx.Keyset, file);
|
||||||
|
string outDir = ctx.Options.OutDir;
|
||||||
|
|
||||||
|
if (outDir != null)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(outDir);
|
||||||
|
|
||||||
|
package1.Pk11.OpenWarmboot().WriteAllBytes(Path.Combine(outDir, "Warmboot.bin"), ctx.Logger);
|
||||||
|
package1.Pk11.OpenNxBootloader().WriteAllBytes(Path.Combine(outDir, "NX_Bootloader.bin"), ctx.Logger);
|
||||||
|
package1.Pk11.OpenSecureMonitor().WriteAllBytes(Path.Combine(outDir, "Secure_Monitor.bin"), ctx.Logger);
|
||||||
|
|
||||||
|
using (var decFile = new FileStream(Path.Combine(outDir, "Decrypted.bin"), FileMode.Create))
|
||||||
|
{
|
||||||
|
package1.OpenPackage1Ldr().CopyTo(decFile);
|
||||||
|
package1.Pk11.OpenDecryptedPk11().CopyTo(decFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For running random stuff
|
// For running random stuff
|
||||||
// ReSharper disable once UnusedParameter.Local
|
// ReSharper disable once UnusedParameter.Local
|
||||||
private static void CustomTask(Context ctx)
|
private static void CustomTask(Context ctx)
|
||||||
|
|
Loading…
Reference in a new issue