Add Savefile.CommitHeader method

This commit is contained in:
Alex Barney 2018-10-18 18:18:39 -05:00
parent f83a284b96
commit 7a7946a26c
4 changed files with 48 additions and 26 deletions

View file

@ -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())

View file

@ -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;

View file

@ -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);

View file

@ -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");
} }