private HierarchicalIntegrityVerificationStream InitIvfcStream(bool enableIntegrityChecks) { IvfcHeader ivfc = Header.Ivfc; const int ivfcLevels = 5; var initInfo = new IntegrityVerificationInfo[ivfcLevels]; initInfo[0] = new IntegrityVerificationInfo { Data = new MemoryStream(Header.MasterHashA), BlockSizePower = 0, Type = IntegrityStreamType.Save }; for (int i = 1; i < ivfcLevels; i++) { IvfcLevelHeader level = ivfc.LevelHeaders[i - 1]; Stream data = i == ivfcLevels - 1 ? (Stream)JournalStream : MetaRemapSource.CreateStream(level.LogicalOffset, level.HashDataSize); initInfo[i] = new IntegrityVerificationInfo { Data = data, BlockSizePower = level.BlockSize, Salt = new HMACSHA256(Encoding.ASCII.GetBytes(SaltSources[i - 1])).ComputeHash(ivfc.SaltSource), Type = IntegrityStreamType.Save }; } return(new HierarchicalIntegrityVerificationStream(initInfo, enableIntegrityChecks)); }
public Header(IStorage storage, KeySet keySet) { MainStorage = storage; MainHeader = MainStorage.Slice(0x100, 0x200); DuplexHeader = MainStorage.Slice(0x300, 0x44); DataIvfcHeader = MainStorage.Slice(0x344, 0xC0); JournalHeader = MainStorage.Slice(0x408, 0x200); SaveHeader = MainStorage.Slice(0x608, 0x48); MainRemapHeader = MainStorage.Slice(0x650, 0x40); MetaDataRemapHeader = MainStorage.Slice(0x690, 0x40); ExtraDataStorage = MainStorage.Slice(0x6D8, 0x400); FatIvfcHeader = MainStorage.Slice(0xAD8, 0xC0); Layout = new FsLayout(MainHeader); DuplexMasterBitmapA = MainStorage.Slice(Layout.DuplexMasterOffsetA, Layout.DuplexMasterSize); DuplexMasterBitmapB = MainStorage.Slice(Layout.DuplexMasterOffsetB, Layout.DuplexMasterSize); DataIvfcMaster = MainStorage.Slice(Layout.IvfcMasterHashOffsetA, Layout.IvfcMasterHashSize); FatIvfcMaster = MainStorage.Slice(Layout.FatIvfcMasterHashA, Layout.IvfcMasterHashSize); var reader = new BinaryReader(storage.AsStream()); reader.BaseStream.Position = 0; Data = reader.ReadBytes(0x4000); reader.BaseStream.Position = 0; Cmac = reader.ReadBytes(0x10); reader.BaseStream.Position = 0x100; reader.BaseStream.Position = 0x300; Duplex = new DuplexHeader(reader); reader.BaseStream.Position = 0x6D8; ExtraData = new ExtraData(reader); Ivfc = new IvfcHeader(DataIvfcHeader) { NumLevels = 5 }; if (Layout.Version >= 0x50000) { FatIvfc = new IvfcHeader(FatIvfcHeader) { NumLevels = 4 }; } MasterHash = storage.Slice(Layout.IvfcMasterHashOffsetA, Layout.IvfcMasterHashSize); Span <byte> actualHeaderHash = stackalloc byte[Sha256.DigestSize]; Sha256.GenerateSha256Hash(Data.AsSpan(0x300, 0x3d00), actualHeaderHash); HeaderHashValidity = Utilities.SpansEqual(Layout.Hash, actualHeaderHash) ? Validity.Valid : Validity.Invalid; SignatureValidity = ValidateSignature(keySet); }
public Header(Keyset keyset, BinaryReader reader) { reader.BaseStream.Position = 0; Data = reader.ReadBytes(0x4000); reader.BaseStream.Position = 0; Cmac = reader.ReadBytes(0x10); reader.BaseStream.Position = 0x100; Layout = new FsLayout(reader); reader.BaseStream.Position = 0x300; Duplex = new DuplexHeader(reader); reader.BaseStream.Position = 0x344; Ivfc = new IvfcHeader(reader); reader.BaseStream.Position = 0x408; Journal = new JournalHeader(reader); reader.BaseStream.Position = 0x608; Save = new SaveHeader(reader); reader.BaseStream.Position = 0x650; FileRemap = new RemapHeader(reader); reader.BaseStream.Position = 0x690; MetaRemap = new RemapHeader(reader); reader.BaseStream.Position = 0x6D8; ExtraData = new ExtraData(reader); reader.BaseStream.Position = Layout.IvfcMasterHashOffsetA; MasterHashA = reader.ReadBytes((int)Layout.IvfcMasterHashSize); reader.BaseStream.Position = Layout.IvfcMasterHashOffsetB; MasterHashB = reader.ReadBytes((int)Layout.IvfcMasterHashSize); reader.BaseStream.Position = Layout.DuplexMasterOffsetA; DuplexMasterA = reader.ReadBytes((int)Layout.DuplexMasterSize); reader.BaseStream.Position = Layout.DuplexMasterOffsetB; DuplexMasterB = reader.ReadBytes((int)Layout.DuplexMasterSize); reader.BaseStream.Position = Layout.FileMapEntryOffset; FileMapEntries = new MapEntry[FileRemap.MapEntryCount]; for (int i = 0; i < FileRemap.MapEntryCount; i++) { FileMapEntries[i] = new MapEntry(reader); } reader.BaseStream.Position = Layout.MetaMapEntryOffset; MetaMapEntries = new MapEntry[MetaRemap.MapEntryCount]; for (int i = 0; i < MetaRemap.MapEntryCount; i++) { MetaMapEntries[i] = new MapEntry(reader); } HeaderHashValidity = Crypto.CheckMemoryHashTable(Data, Layout.Hash, 0x300, 0x3d00); SignatureValidity = ValidateSignature(keyset); }
public Header(IStorage storage, Keyset keyset) { MainStorage = storage; MainHeader = MainStorage.Slice(0x100, 0x200); DuplexHeader = MainStorage.Slice(0x300, 0x44); DataIvfcHeader = MainStorage.Slice(0x344, 0xC0); JournalHeader = MainStorage.Slice(0x408, 0x200); SaveHeader = MainStorage.Slice(0x608, 0x48); MainRemapHeader = MainStorage.Slice(0x650, 0x40); MetaDataRemapHeader = MainStorage.Slice(0x690, 0x40); ExtraDataStorage = MainStorage.Slice(0x6D8, 0x400); FatIvfcHeader = MainStorage.Slice(0xAD8, 0xC0); Layout = new FsLayout(MainHeader); DuplexMasterBitmapA = MainStorage.Slice(Layout.DuplexMasterOffsetA, Layout.DuplexMasterSize); DuplexMasterBitmapB = MainStorage.Slice(Layout.DuplexMasterOffsetB, Layout.DuplexMasterSize); DataIvfcMaster = MainStorage.Slice(Layout.IvfcMasterHashOffsetA, Layout.IvfcMasterHashSize); FatIvfcMaster = MainStorage.Slice(Layout.FatIvfcMasterHashA, Layout.IvfcMasterHashSize); var reader = new BinaryReader(storage.AsStream()); reader.BaseStream.Position = 0; Data = reader.ReadBytes(0x4000); reader.BaseStream.Position = 0; Cmac = reader.ReadBytes(0x10); reader.BaseStream.Position = 0x100; reader.BaseStream.Position = 0x300; Duplex = new DuplexHeader(reader); reader.BaseStream.Position = 0x6D8; ExtraData = new ExtraData(reader); Ivfc = new IvfcHeader(DataIvfcHeader) { NumLevels = 5 }; if (Layout.Version >= 0x50000) { FatIvfc = new IvfcHeader(FatIvfcHeader) { NumLevels = 4 }; } MasterHash = storage.Slice(Layout.IvfcMasterHashOffsetA, Layout.IvfcMasterHashSize); HeaderHashValidity = Crypto.CheckMemoryHashTable(Data, Layout.Hash, 0x300, 0x3d00); SignatureValidity = ValidateSignature(keyset); }
public NcaFsHeader(BinaryReader reader) { long start = reader.BaseStream.Position; Version = reader.ReadInt16(); FormatType = (NcaFormatType)reader.ReadByte(); HashType = (NcaHashType)reader.ReadByte(); EncryptionType = (NcaEncryptionType)reader.ReadByte(); reader.BaseStream.Position += 3; switch (HashType) { case NcaHashType.Sha256: Sha256Info = new Sha256Info(reader); break; case NcaHashType.Ivfc: IvfcInfo = new IvfcHeader(reader); break; } if (EncryptionType == NcaEncryptionType.AesCtrEx) { BktrInfo = new BktrPatchInfo(); reader.BaseStream.Position = start + 0x100; BktrInfo.RelocationHeader = new BktrHeader(reader); BktrInfo.EncryptionHeader = new BktrHeader(reader); } if (FormatType == NcaFormatType.Pfs0) { Type = SectionType.Pfs0; } else if (FormatType == NcaFormatType.Romfs) { if (EncryptionType == NcaEncryptionType.AesCtrEx) { Type = SectionType.Bktr; } else { Type = SectionType.Romfs; } } reader.BaseStream.Position = start + 0x140; Ctr = reader.ReadBytes(8).Reverse().ToArray(); reader.BaseStream.Position = start + 512; }
private HierarchicalIntegrityVerificationStorage InitJournalIvfcStorage(IntegrityCheckLevel integrityCheckLevel) { const int ivfcLevels = 5; IvfcHeader ivfc = Header.Ivfc; var levels = new List <IStorage> { Header.DataIvfcMaster }; for (int i = 0; i < ivfcLevels - 2; i++) { IvfcLevelHeader level = ivfc.LevelHeaders[i]; levels.Add(MetaRemapStorage.Slice(level.Offset, level.Size)); } IvfcLevelHeader dataLevel = ivfc.LevelHeaders[ivfcLevels - 2]; levels.Add(JournalStorage.Slice(dataLevel.Offset, dataLevel.Size)); return(new HierarchicalIntegrityVerificationStorage(ivfc, levels, IntegrityStorageType.Save, integrityCheckLevel, LeaveOpen)); }
internal static void SetLevelValidities(this HierarchicalIntegrityVerificationStream stream, IvfcHeader header) { for (int i = 0; i < stream.Levels.Length - 1; i++) { Validity[] level = stream.LevelValidities[i]; var levelValidity = Validity.Valid; foreach (Validity block in level) { if (block == Validity.Invalid) { levelValidity = Validity.Invalid; break; } if (block == Validity.Unchecked && levelValidity != Validity.Invalid) { levelValidity = Validity.Unchecked; } } header.LevelHeaders[i].HashValidity = levelValidity; } }
public static void PrintIvfcHash(StringBuilder sb, int colLen, int indentSize, IvfcHeader ivfcInfo, IntegrityStorageType type) { var prefix = new string(' ', indentSize); var prefix2 = new string(' ', indentSize + 4); if (type == IntegrityStorageType.RomFs) { PrintItem(sb, colLen, $"{prefix}Master Hash{ivfcInfo.LevelHeaders[0].HashValidity.GetValidityString()}:", ivfcInfo.MasterHash); } PrintItem(sb, colLen, $"{prefix}Magic:", ivfcInfo.Magic); PrintItem(sb, colLen, $"{prefix}Version:", ivfcInfo.Version); if (type == IntegrityStorageType.Save) { PrintItem(sb, colLen, $"{prefix}Salt Seed:", ivfcInfo.SaltSource); } var levelCount = Math.Max(ivfcInfo.NumLevels - 1, 0); if (type == IntegrityStorageType.Save) { levelCount = 4; } var offsetLen = type == IntegrityStorageType.Save ? 16 : 12; for (var i = 0; i < levelCount; i++) { var level = ivfcInfo.LevelHeaders[i]; long hashOffset = 0; if (i != 0) { hashOffset = ivfcInfo.LevelHeaders[i - 1].Offset; } sb.AppendLine($"{prefix}Level {i}{level.HashValidity.GetValidityString()}:"); PrintItem(sb, colLen, $"{prefix2}Data Offset:", $"0x{level.Offset.ToString($"x{offsetLen}")}"); PrintItem(sb, colLen, $"{prefix2}Data Size:", $"0x{level.Size.ToString($"x{offsetLen}")}"); PrintItem(sb, colLen, $"{prefix2}Hash Offset:", $"0x{hashOffset.ToString($"x{offsetLen}")}"); PrintItem(sb, colLen, $"{prefix2}Hash BlockSize:", $"0x{1 << level.BlockSizePower:x8}"); } }