Пример #1
0
        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);
            }

            var cmacData = new byte[0x200];
            var cmac     = new byte[0x10];

            headerStream.Position = 0x100;
            headerStream.Read(cmacData, 0, 0x200);

            Crypto.CalculateAesCmac(keyset.SaveMacKey, cmacData, 0, cmac, 0, 0x200);

            headerStream.Position = 0;
            headerStream.Write(cmac, 0, 0x10);
            headerStream.Flush();

            return(true);
        }
Пример #2
0
        public Stream OpenIni1()
        {
            int          offset    = 0x200 + Header.SectionSizes[0];
            SharedStream encStream = StreamSource.CreateStream(offset, Header.SectionSizes[1]);

            return(new RandomAccessSectorStream(new Aes128CtrStream(encStream, Key, Header.SectionCounters[1])));
        }
Пример #3
0
        private void SaveToFileInner()
        {
            ApiCallSource.AssertAccess(Permissions, Access.Write);

            long pos = SharedStream.Stream.Position;

            SharedStream.Seek(0);
            File.WriteAllBytes(SourcePath, SharedStream.ReadToEnd());
            SharedStream.Seek(pos);
        }
Пример #4
0
        internal void SaveToFileInner()
        {
            ApiCallSource.AssertAccess(Permissions, Access.Write);

            var pos = SharedStream.Stream.Position;

            SharedStream.Seek(0);
            File.WriteAllText(SourcePath, SharedStream.ReadToEnd());
            SharedStream.Seek(pos);
        }
Пример #5
0
        public Stream OpenHeaderPart2()
        {
            SharedStream encStream = StreamSource.CreateStream(0x110, 0xF0);

            // The counter starts counting at 0x100, but the block at 0x100 isn't encrypted.
            // Increase the counter by one and start decrypting at 0x110.
            var counter = new byte[0x10];

            Array.Copy(Header.Counter, counter, 0x10);
            Util.IncrementByteArray(counter);

            return(new RandomAccessSectorStream(new Aes128CtrStream(encStream, Key, counter)));
        }
Пример #6
0
 internal void SerializeInner <TObject>(TObject obj, WriteMode writeMode = WriteMode.Overwrite)
 {
     ApiCallSource.AssertAccess(Permissions, Access.Write);
     if (writeMode == WriteMode.Overwrite)
     {
         SharedStream.Seek(0);
         SharedStream.SetLength(0);
     }
     else
     {
         SharedStream.Seek(0, SeekOrigin.End);
     }
     SharedStream.WriteLine(JsonConvert.SerializeObject(obj, Formatting.Indented));
 }
Пример #7
0
        internal void SerializeInner <TObject>(TObject obj, WriteMode writeMode = WriteMode.Overwrite)
        {
            ApiCallSource.AssertAccess(Permissions, Access.Write);
            if (writeMode == WriteMode.Overwrite)
            {
                SharedStream.Seek(0);
                SharedStream.SetLength(0);
            }
            else
            {
                SharedStream.Seek(0, SeekOrigin.End);
            }

            using (var writer = new StringWriter())
            {
                new XmlSerializer(typeof(TObject)).Serialize(writer, obj);
                SharedStream.WriteLine(writer.ToString());
            }
        }
Пример #8
0
        public Package2(Keyset keyset, Stream stream)
        {
            StreamSource = new SharedStreamSource(stream);
            SharedStream headerStream = StreamSource.CreateStream(0, 0x200);

            KeyRevision = FindKeyGeneration(keyset, headerStream);
            Key         = keyset.Package2Keys[KeyRevision];

            Header = new Package2Header(headerStream, Key);

            PackageSize = BitConverter.ToInt32(Header.Counter, 0) ^ BitConverter.ToInt32(Header.Counter, 8) ^
                          BitConverter.ToInt32(Header.Counter, 12);

            HeaderVersion = Header.Counter[4] ^ Header.Counter[6] ^ Header.Counter[7];

            if (PackageSize != 0x200 + Header.SectionSizes[0] + Header.SectionSizes[1] + Header.SectionSizes[2])
            {
                throw new InvalidDataException("Package2 Header is corrupt!");
            }
        }
Пример #9
0
        internal TObject DeserializeInner <TObject>(long offset = long.MaxValue, SeekOrigin loc = SeekOrigin.Begin, bool retainPosition = true)
        {
            ApiCallSource.AssertAccess(Permissions, Access.Read);
            long?returnPosition = null;

            if (offset != long.MaxValue)
            {
                if (retainPosition)
                {
                    returnPosition = SharedStream.Stream.Position;
                }
                SharedStream.Seek(offset, loc);
            }

            TObject obj = (TObject) new XmlSerializer(typeof(TObject)).Deserialize(new StreamReader(SharedStream.Stream));

            if (returnPosition != null)
            {
                SharedStream.Seek(returnPosition.Value);
            }
            return(obj);
        }
Пример #10
0
        public bool SignHeader(Keyset keyset)
        {
            if (keyset.SaveMacKey.IsEmpty())
            {
                return(false);
            }

            var data = new byte[0x200];
            var cmac = new byte[0x10];

            SharedStream 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);
        }
Пример #11
0
        internal TObject DeserializeInner <TObject>(long offset         = long.MaxValue, SeekOrigin loc = SeekOrigin.Begin,
                                                    bool retainPosition = true)
        {
            ApiCallSource.AssertAccess(Permissions, Access.Read);
            long?returnPosition = null;

            if (offset != long.MaxValue)
            {
                if (retainPosition)
                {
                    returnPosition = SharedStream.Stream.Position;
                }
                SharedStream.Seek(offset, loc);
            }

            var obj = JsonConvert.DeserializeObject <TObject>(SharedStream.ReadToEnd());

            if (returnPosition != null)
            {
                SharedStream.Seek(returnPosition.Value);
            }
            return(obj);
        }
Пример #12
0
        public Savefile(Keyset keyset, Stream file, bool enableIntegrityChecks)
        {
            SavefileSource = new SharedStreamSource(file);

            using (var reader = new BinaryReader(SavefileSource.CreateStream(), Encoding.Default, true))
            {
                Header = new Header(keyset, reader);
                FsLayout layout = Header.Layout;

                FileRemap = new RemapStream(
                    SavefileSource.CreateStream(layout.FileMapDataOffset, layout.FileMapDataSize),
                    Header.FileMapEntries, Header.FileRemap.MapSegmentCount);

                FileRemapSource = new SharedStreamSource(FileRemap);

                var duplexLayers = new DuplexFsLayerInfo[3];

                duplexLayers[0] = new DuplexFsLayerInfo
                {
                    DataA = new MemoryStream(Header.DuplexMasterA),
                    DataB = new MemoryStream(Header.DuplexMasterB),
                    Info  = Header.Duplex.Layers[0]
                };

                duplexLayers[1] = new DuplexFsLayerInfo
                {
                    DataA = FileRemapSource.CreateStream(layout.DuplexL1OffsetA, layout.DuplexL1Size),
                    DataB = FileRemapSource.CreateStream(layout.DuplexL1OffsetB, layout.DuplexL1Size),
                    Info  = Header.Duplex.Layers[1]
                };

                duplexLayers[2] = new DuplexFsLayerInfo
                {
                    DataA = FileRemapSource.CreateStream(layout.DuplexDataOffsetA, layout.DuplexDataSize),
                    DataB = FileRemapSource.CreateStream(layout.DuplexDataOffsetB, layout.DuplexDataSize),
                    Info  = Header.Duplex.Layers[2]
                };

                DuplexL1A   = FileRemapSource.CreateStream(layout.DuplexL1OffsetA, layout.DuplexL1Size);
                DuplexL1B   = FileRemapSource.CreateStream(layout.DuplexL1OffsetB, layout.DuplexL1Size);
                DuplexDataA = FileRemapSource.CreateStream(layout.DuplexDataOffsetA, layout.DuplexDataSize);
                DuplexDataB = FileRemapSource.CreateStream(layout.DuplexDataOffsetB, layout.DuplexDataSize);
                JournalData = FileRemapSource.CreateStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea);

                DuplexData      = new LayeredDuplexFs(duplexLayers, Header.Layout.DuplexIndex == 1);
                MetaRemap       = new RemapStream(DuplexData, Header.MetaMapEntries, Header.MetaRemap.MapSegmentCount);
                MetaRemapSource = new SharedStreamSource(MetaRemap);

                JournalTable = MetaRemapSource.CreateStream(layout.JournalTableOffset, layout.JournalTableSize);
                JournalBitmapUpdatedPhysical = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedPhysicalOffset, layout.JournalBitmapUpdatedPhysicalSize);
                JournalBitmapUpdatedVirtual  = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedVirtualOffset, layout.JournalBitmapUpdatedVirtualSize);
                JournalBitmapUnassigned      = MetaRemapSource.CreateStream(layout.JournalBitmapUnassignedOffset, layout.JournalBitmapUnassignedSize);
                JournalLayer1Hash            = MetaRemapSource.CreateStream(layout.IvfcL1Offset, layout.IvfcL1Size);
                JournalLayer2Hash            = MetaRemapSource.CreateStream(layout.IvfcL2Offset, layout.IvfcL2Size);
                JournalLayer3Hash            = MetaRemapSource.CreateStream(layout.IvfcL3Offset, layout.IvfcL3Size);
                JournalFat      = MetaRemapSource.CreateStream(layout.FatOffset, layout.FatSize);
                AllocationTable = new AllocationTable(JournalFat);

                MappingEntry[] journalMap = JournalStream.ReadMappingEntries(JournalTable, Header.Journal.MainDataBlockCount);

                SharedStream journalData = FileRemapSource.CreateStream(layout.JournalDataOffset,
                                                                        layout.JournalDataSizeB + layout.SizeReservedArea);
                JournalStream       = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize);
                JournalStreamSource = new SharedStreamSource(JournalStream);

                IvfcStream       = InitIvfcStream(enableIntegrityChecks);
                IvfcStreamSource = new SharedStreamSource(IvfcStream);

                ReadFileInfo();
                var dictionary = new Dictionary <string, FileEntry>();
                foreach (FileEntry entry in Files)
                {
                    dictionary[entry.FullPath] = entry;
                }

                FileDict = dictionary;
            }
        }
Пример #13
0
 internal byte[]? ReadToEndInner()
 {
     ApiCallSource.AssertAccess(Permissions, Access.Read);
     return(SharedStream?.ReadToEnd());
 }