private IStorage OpenAesCtrExStorage(IStorage baseStorage, int index, bool decrypting) { NcaFsHeader fsHeader = GetFsHeader(index); NcaFsPatchInfo info = fsHeader.GetPatchInfo(); long sectionOffset = Header.GetSectionStartOffset(index); long sectionSize = Header.GetSectionSize(index); long bktrOffset = info.RelocationTreeOffset; long bktrSize = sectionSize - bktrOffset; long dataSize = info.RelocationTreeOffset; byte[] key = GetContentKey(NcaKeyType.AesCtr); byte[] counter = Aes128CtrStorage.CreateCounter(fsHeader.Counter, bktrOffset + sectionOffset); byte[] counterEx = Aes128CtrStorage.CreateCounter(fsHeader.Counter, sectionOffset); IStorage bucketTreeData; IStorage outputBucketTreeData; if (decrypting) { bucketTreeData = new CachedStorage(new Aes128CtrStorage(baseStorage.Slice(bktrOffset, bktrSize), key, counter, true), 4, true); outputBucketTreeData = bucketTreeData; } else { bucketTreeData = baseStorage.Slice(bktrOffset, bktrSize); outputBucketTreeData = new CachedStorage(new Aes128CtrStorage(baseStorage.Slice(bktrOffset, bktrSize), key, counter, true), 4, true); } var encryptionBucketTreeData = new SubStorage(bucketTreeData, info.EncryptionTreeOffset - bktrOffset, sectionSize - info.EncryptionTreeOffset); var cachedBucketTreeData = new CachedStorage(encryptionBucketTreeData, IndirectStorage.NodeSize, 6, true); var treeHeader = new BucketTree.Header(); info.EncryptionTreeHeader.CopyTo(SpanHelpers.AsByteSpan(ref treeHeader)); long nodeStorageSize = IndirectStorage.QueryNodeStorageSize(treeHeader.EntryCount); long entryStorageSize = IndirectStorage.QueryEntryStorageSize(treeHeader.EntryCount); var tableNodeStorage = new SubStorage(cachedBucketTreeData, 0, nodeStorageSize); var tableEntryStorage = new SubStorage(cachedBucketTreeData, nodeStorageSize, entryStorageSize); IStorage decStorage = new Aes128CtrExStorage(baseStorage.Slice(0, dataSize), tableNodeStorage, tableEntryStorage, treeHeader.EntryCount, key, counterEx, true); return(new ConcatenationStorage(new[] { decStorage, outputBucketTreeData }, true)); }
public IStorage OpenRawStorageWithPatch(Nca patchNca, int index) { IStorage patchStorage = patchNca.OpenRawStorage(index); IStorage baseStorage = SectionExists(index) ? OpenRawStorage(index) : new NullStorage(); patchStorage.GetSize(out long patchSize).ThrowIfFailure(); baseStorage.GetSize(out long baseSize).ThrowIfFailure(); NcaFsHeader header = patchNca.Header.GetFsHeader(index); NcaFsPatchInfo patchInfo = header.GetPatchInfo(); if (patchInfo.RelocationTreeSize == 0) { return(patchStorage); } var treeHeader = new BucketTree.Header(); patchInfo.RelocationTreeHeader.CopyTo(SpanHelpers.AsByteSpan(ref treeHeader)); long nodeStorageSize = IndirectStorage.QueryNodeStorageSize(treeHeader.EntryCount); long entryStorageSize = IndirectStorage.QueryEntryStorageSize(treeHeader.EntryCount); var relocationTableStorage = new SubStorage(patchStorage, patchInfo.RelocationTreeOffset, patchInfo.RelocationTreeSize); var cachedTableStorage = new CachedStorage(relocationTableStorage, IndirectStorage.NodeSize, 4, true); var tableNodeStorage = new SubStorage(cachedTableStorage, 0, nodeStorageSize); var tableEntryStorage = new SubStorage(cachedTableStorage, nodeStorageSize, entryStorageSize); var storage = new IndirectStorage(); storage.Initialize(tableNodeStorage, tableEntryStorage, treeHeader.EntryCount).ThrowIfFailure(); storage.SetStorage(0, baseStorage, 0, baseSize); storage.SetStorage(1, patchStorage, 0, patchSize); return(storage); }