mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add Savefile.CommitHeader method
This commit is contained in:
parent
f83a284b96
commit
7a7946a26c
4 changed files with 48 additions and 26 deletions
|
@ -21,6 +21,14 @@ namespace LibHac
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] ComputeSha256(byte[] data, int offset, int count)
|
||||||
|
{
|
||||||
|
using (SHA256 sha = SHA256.Create())
|
||||||
|
{
|
||||||
|
return sha.ComputeHash(data, offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void DecryptEcb(byte[] key, byte[] src, int srcIndex, byte[] dest, int destIndex, int length)
|
public static void DecryptEcb(byte[] key, byte[] src, int srcIndex, byte[] dest, int destIndex, int length)
|
||||||
{
|
{
|
||||||
using (Aes aes = Aes.Create())
|
using (Aes aes = Aes.Create())
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using LibHac.Streams;
|
||||||
|
|
||||||
namespace LibHac.Save
|
namespace LibHac.Save
|
||||||
{
|
{
|
||||||
|
@ -24,13 +25,17 @@ namespace LibHac.Save
|
||||||
public byte[] DuplexMasterA { get; }
|
public byte[] DuplexMasterA { get; }
|
||||||
public byte[] DuplexMasterB { get; }
|
public byte[] DuplexMasterB { get; }
|
||||||
|
|
||||||
|
public Stream MasterHash { get; }
|
||||||
|
|
||||||
public Validity SignatureValidity { get; }
|
public Validity SignatureValidity { get; }
|
||||||
public Validity HeaderHashValidity { get; }
|
public Validity HeaderHashValidity { get; }
|
||||||
|
|
||||||
public byte[] Data { get; }
|
public byte[] Data { get; }
|
||||||
|
|
||||||
public Header(Keyset keyset, BinaryReader reader)
|
public Header(Keyset keyset, SharedStreamSource streamSource)
|
||||||
{
|
{
|
||||||
|
var reader = new BinaryReader(streamSource.CreateStream());
|
||||||
|
|
||||||
reader.BaseStream.Position = 0;
|
reader.BaseStream.Position = 0;
|
||||||
Data = reader.ReadBytes(0x4000);
|
Data = reader.ReadBytes(0x4000);
|
||||||
reader.BaseStream.Position = 0;
|
reader.BaseStream.Position = 0;
|
||||||
|
@ -65,6 +70,8 @@ namespace LibHac.Save
|
||||||
reader.BaseStream.Position = Layout.IvfcMasterHashOffsetB;
|
reader.BaseStream.Position = Layout.IvfcMasterHashOffsetB;
|
||||||
MasterHashB = reader.ReadBytes((int)Layout.IvfcMasterHashSize);
|
MasterHashB = reader.ReadBytes((int)Layout.IvfcMasterHashSize);
|
||||||
|
|
||||||
|
MasterHash = streamSource.CreateStream(Layout.IvfcMasterHashOffsetA, Layout.IvfcMasterHashSize);
|
||||||
|
|
||||||
reader.BaseStream.Position = Layout.DuplexMasterOffsetA;
|
reader.BaseStream.Position = Layout.DuplexMasterOffsetA;
|
||||||
DuplexMasterA = reader.ReadBytes((int)Layout.DuplexMasterSize);
|
DuplexMasterA = reader.ReadBytes((int)Layout.DuplexMasterSize);
|
||||||
reader.BaseStream.Position = Layout.DuplexMasterOffsetB;
|
reader.BaseStream.Position = Layout.DuplexMasterOffsetB;
|
||||||
|
|
|
@ -28,33 +28,30 @@ namespace LibHac.Save
|
||||||
{
|
{
|
||||||
SavefileSource = new SharedStreamSource(file);
|
SavefileSource = new SharedStreamSource(file);
|
||||||
|
|
||||||
using (var reader = new BinaryReader(SavefileSource.CreateStream(), Encoding.Default, true))
|
Header = new Header(keyset, SavefileSource);
|
||||||
{
|
FsLayout layout = Header.Layout;
|
||||||
Header = new Header(keyset, reader);
|
|
||||||
FsLayout layout = Header.Layout;
|
|
||||||
|
|
||||||
DataRemapStorage = new RemapStorage(SavefileSource.CreateStream(layout.FileMapDataOffset, layout.FileMapDataSize),
|
DataRemapStorage = new RemapStorage(SavefileSource.CreateStream(layout.FileMapDataOffset, layout.FileMapDataSize),
|
||||||
Header.FileRemap, Header.FileMapEntries);
|
Header.FileRemap, Header.FileMapEntries);
|
||||||
|
|
||||||
DuplexData = InitDuplexStream(DataRemapStorage, Header);
|
DuplexData = InitDuplexStream(DataRemapStorage, Header);
|
||||||
|
|
||||||
MetaRemapStorage = new RemapStorage(DuplexData, Header.MetaRemap, Header.MetaMapEntries);
|
MetaRemapStorage = new RemapStorage(DuplexData, Header.MetaRemap, Header.MetaMapEntries);
|
||||||
|
|
||||||
Stream journalTable = MetaRemapStorage.OpenStream(layout.JournalTableOffset, layout.JournalTableSize);
|
Stream journalTable = MetaRemapStorage.OpenStream(layout.JournalTableOffset, layout.JournalTableSize);
|
||||||
|
|
||||||
MappingEntry[] journalMap = JournalStream.ReadMappingEntries(journalTable, Header.Journal.MainDataBlockCount);
|
MappingEntry[] journalMap = JournalStream.ReadMappingEntries(journalTable, Header.Journal.MainDataBlockCount);
|
||||||
|
|
||||||
Stream journalData = DataRemapStorage.OpenStream(layout.JournalDataOffset,
|
Stream journalData = DataRemapStorage.OpenStream(layout.JournalDataOffset,
|
||||||
layout.JournalDataSizeB + layout.SizeReservedArea);
|
layout.JournalDataSizeB + layout.SizeReservedArea);
|
||||||
var journalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize);
|
var journalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize);
|
||||||
JournalStreamSource = new SharedStreamSource(journalStream);
|
JournalStreamSource = new SharedStreamSource(journalStream);
|
||||||
|
|
||||||
IvfcStream = InitIvfcStream(integrityCheckLevel);
|
IvfcStream = InitIvfcStream(integrityCheckLevel);
|
||||||
|
|
||||||
SaveFs = new SaveFs(IvfcStream, MetaRemapStorage.OpenStream(layout.FatOffset, layout.FatSize), Header.Save);
|
SaveFs = new SaveFs(IvfcStream, MetaRemapStorage.OpenStream(layout.FatOffset, layout.FatSize), Header.Save);
|
||||||
|
|
||||||
IvfcStreamSource = new SharedStreamSource(IvfcStream);
|
IvfcStreamSource = new SharedStreamSource(IvfcStream);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LayeredDuplexFs InitDuplexStream(RemapStorage baseStorage, Header header)
|
private static LayeredDuplexFs InitDuplexStream(RemapStorage baseStorage, Header header)
|
||||||
|
@ -95,7 +92,7 @@ namespace LibHac.Save
|
||||||
|
|
||||||
initInfo[0] = new IntegrityVerificationInfo
|
initInfo[0] = new IntegrityVerificationInfo
|
||||||
{
|
{
|
||||||
Data = new MemoryStream(Header.MasterHashA),
|
Data = Header.MasterHash,
|
||||||
BlockSize = 0,
|
BlockSize = 0,
|
||||||
Type = IntegrityStreamType.Save
|
Type = IntegrityStreamType.Save
|
||||||
};
|
};
|
||||||
|
@ -132,18 +129,28 @@ namespace LibHac.Save
|
||||||
|
|
||||||
public bool FileExists(string filename) => SaveFs.FileExists(filename);
|
public bool FileExists(string filename) => SaveFs.FileExists(filename);
|
||||||
|
|
||||||
public bool SignHeader(Keyset keyset)
|
public bool CommitHeader(Keyset keyset)
|
||||||
{
|
{
|
||||||
|
SharedStream headerStream = SavefileSource.CreateStream();
|
||||||
|
|
||||||
|
var hashData = new byte[0x3d00];
|
||||||
|
|
||||||
|
headerStream.Position = 0x300;
|
||||||
|
headerStream.Read(hashData, 0, hashData.Length);
|
||||||
|
|
||||||
|
byte[] hash = Crypto.ComputeSha256(hashData, 0, hashData.Length);
|
||||||
|
headerStream.Position = 0x108;
|
||||||
|
headerStream.Write(hash, 0, hash.Length);
|
||||||
|
|
||||||
if (keyset.SaveMacKey.IsEmpty()) return false;
|
if (keyset.SaveMacKey.IsEmpty()) return false;
|
||||||
|
|
||||||
var data = new byte[0x200];
|
var cmacData = new byte[0x200];
|
||||||
var cmac = new byte[0x10];
|
var cmac = new byte[0x10];
|
||||||
|
|
||||||
SharedStream headerStream = SavefileSource.CreateStream();
|
|
||||||
headerStream.Position = 0x100;
|
headerStream.Position = 0x100;
|
||||||
headerStream.Read(data, 0, 0x200);
|
headerStream.Read(cmacData, 0, 0x200);
|
||||||
|
|
||||||
Crypto.CalculateAesCmac(keyset.SaveMacKey, data, 0, cmac, 0, 0x200);
|
Crypto.CalculateAesCmac(keyset.SaveMacKey, cmacData, 0, cmac, 0, 0x200);
|
||||||
|
|
||||||
headerStream.Position = 0;
|
headerStream.Position = 0;
|
||||||
headerStream.Write(cmac, 0, 0x10);
|
headerStream.Write(cmac, 0, 0x10);
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.SignSave)
|
if (ctx.Options.SignSave)
|
||||||
{
|
{
|
||||||
if (save.SignHeader(ctx.Keyset))
|
if (save.CommitHeader(ctx.Keyset))
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("Successfully signed save file");
|
ctx.Logger.LogMessage("Successfully signed save file");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue