mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add save file signing capability
This commit is contained in:
parent
e651eb731c
commit
087008f7f4
6 changed files with 47 additions and 4 deletions
4
KEYS.md
4
KEYS.md
|
@ -95,6 +95,8 @@ bis_key_source_01 = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
bis_key_source_02 = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
bis_key_source_02 = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
bis_kek_source = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
bis_kek_source = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
|
|
||||||
|
save_mac_kek_source = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
|
save_mac_key_source = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
```
|
```
|
||||||
|
|
||||||
### Console-unique keys
|
### Console-unique keys
|
||||||
|
@ -141,6 +143,8 @@ bis_kek_source
|
||||||
bis_key_source_00
|
bis_key_source_00
|
||||||
bis_key_source_01
|
bis_key_source_01
|
||||||
bis_key_source_02
|
bis_key_source_02
|
||||||
|
save_mac_kek_source
|
||||||
|
save_mac_key_source
|
||||||
|
|
||||||
header_key
|
header_key
|
||||||
xci_header_key
|
xci_header_key
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace LibHac.Savefile
|
||||||
{
|
{
|
||||||
public Header Header { get; }
|
public Header Header { get; }
|
||||||
private RemapStream FileRemap { get; }
|
private RemapStream FileRemap { get; }
|
||||||
|
public SharedStreamSource SavefileSource { get; }
|
||||||
public SharedStreamSource FileRemapSource { get; }
|
public SharedStreamSource FileRemapSource { get; }
|
||||||
private RemapStream MetaRemap { get; }
|
private RemapStream MetaRemap { get; }
|
||||||
public SharedStreamSource MetaRemapSource { get; }
|
public SharedStreamSource MetaRemapSource { get; }
|
||||||
|
@ -39,12 +40,15 @@ namespace LibHac.Savefile
|
||||||
|
|
||||||
public Savefile(Keyset keyset, Stream file, IProgressReport logger = null)
|
public Savefile(Keyset keyset, Stream file, IProgressReport logger = null)
|
||||||
{
|
{
|
||||||
using (var reader = new BinaryReader(file, Encoding.Default, true))
|
SavefileSource = new SharedStreamSource(file);
|
||||||
|
|
||||||
|
using (var reader = new BinaryReader(SavefileSource.CreateStream(), Encoding.Default, true))
|
||||||
{
|
{
|
||||||
Header = new Header(keyset, reader, logger);
|
Header = new Header(keyset, reader, logger);
|
||||||
var layout = Header.Layout;
|
FsLayout layout = Header.Layout;
|
||||||
|
|
||||||
FileRemap = new RemapStream(
|
FileRemap = new RemapStream(
|
||||||
new SubStream(file, layout.FileMapDataOffset, layout.FileMapDataSize),
|
SavefileSource.CreateStream(layout.FileMapDataOffset, layout.FileMapDataSize),
|
||||||
Header.FileMapEntries, Header.FileRemap.MapSegmentCount);
|
Header.FileMapEntries, Header.FileRemap.MapSegmentCount);
|
||||||
|
|
||||||
FileRemapSource = new SharedStreamSource(FileRemap);
|
FileRemapSource = new SharedStreamSource(FileRemap);
|
||||||
|
@ -220,6 +224,25 @@ namespace LibHac.Savefile
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool SignHeader(Keyset keyset)
|
||||||
|
{
|
||||||
|
if (keyset.SaveMacKey.IsEmpty()) return false;
|
||||||
|
|
||||||
|
var data = new byte[0x200];
|
||||||
|
var cmac = new byte[0x10];
|
||||||
|
|
||||||
|
var headerStream = SavefileSource.CreateStream();
|
||||||
|
headerStream.Position = 0x100;
|
||||||
|
headerStream.Read(data, 0, 0x200);
|
||||||
|
|
||||||
|
Crypto.CalculateAesCmac(keyset.SaveMacKey, data, 0, cmac, 0, 0x200);
|
||||||
|
|
||||||
|
headerStream.Position = 0;
|
||||||
|
headerStream.Write(cmac, 0, 0x10);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SavefileExtensions
|
public static class SavefileExtensions
|
||||||
|
|
|
@ -65,6 +65,7 @@ Switch FS options:
|
||||||
Savefile options:
|
Savefile options:
|
||||||
--outdir <dir> Specify directory path to save contents to.
|
--outdir <dir> Specify directory path to save contents to.
|
||||||
--debugoutdir <dir> Specify directory path to save intermediate data to for debugging.
|
--debugoutdir <dir> Specify directory path to save intermediate data to for debugging.
|
||||||
|
--sign Sign the save file. (Requires device_key in key file)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace hactoolnet
|
||||||
new CliOption("listapps", 0, (o, a) => o.ListApps = true),
|
new CliOption("listapps", 0, (o, a) => o.ListApps = true),
|
||||||
new CliOption("listtitles", 0, (o, a) => o.ListTitles = true),
|
new CliOption("listtitles", 0, (o, a) => o.ListTitles = true),
|
||||||
new CliOption("listromfs", 0, (o, a) => o.ListRomFs = true),
|
new CliOption("listromfs", 0, (o, a) => o.ListRomFs = true),
|
||||||
|
new CliOption("sign", 0, (o, a) => o.SignSave = true),
|
||||||
new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(a[0])),
|
new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(a[0])),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -194,6 +195,7 @@ namespace hactoolnet
|
||||||
sb.AppendLine("Savefile options:");
|
sb.AppendLine("Savefile options:");
|
||||||
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.");
|
||||||
|
sb.AppendLine(" --sign Sign the save file. (Requires device_key in key file)");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace hactoolnet
|
||||||
public bool ListApps;
|
public bool ListApps;
|
||||||
public bool ListTitles;
|
public bool ListTitles;
|
||||||
public bool ListRomFs;
|
public bool ListRomFs;
|
||||||
|
public bool SignSave;
|
||||||
public ulong TitleId;
|
public ulong TitleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ namespace hactoolnet
|
||||||
|
|
||||||
private static void ProcessSave(Context ctx)
|
private static void ProcessSave(Context ctx)
|
||||||
{
|
{
|
||||||
using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read))
|
using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.ReadWrite))
|
||||||
{
|
{
|
||||||
var save = new Savefile(ctx.Keyset, file, ctx.Logger);
|
var save = new Savefile(ctx.Keyset, file, ctx.Logger);
|
||||||
|
|
||||||
|
@ -129,6 +129,18 @@ namespace hactoolnet
|
||||||
|
|
||||||
save.JournalStreamSource.CreateStream().WriteAllBytes(Path.Combine(dir, "L3_0_SaveData"), ctx.Logger);
|
save.JournalStreamSource.CreateStream().WriteAllBytes(Path.Combine(dir, "L3_0_SaveData"), ctx.Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.Options.SignSave)
|
||||||
|
{
|
||||||
|
if (save.SignHeader(ctx.Keyset))
|
||||||
|
{
|
||||||
|
ctx.Logger.LogMessage("Successfully signed save file");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx.Logger.LogMessage("Unable to sign save file. Do you have all the required keys?");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue